Skip to content

Add support for sessionToken in "connect" and "subscribe" operations #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.parse;


import android.util.Log;
import android.util.SparseArray;

Expand Down Expand Up @@ -179,7 +178,6 @@ private void parseMessage(String message) throws LiveQueryException {
} catch (JSONException e) {
throw new LiveQueryException.InvalidResponseException(message);
}

}

private void handleSubscribedEvent(JSONObject jsonObject) throws JSONException {
Expand Down Expand Up @@ -223,8 +221,14 @@ private Subscription<T> subscriptionForRequestId(int requestId) {
return subscriptions.get(requestId);
}

private void sendSubscription(Subscription<T> subscription) {
sendOperationAsync(new SubscribeClientOperation<>(subscription.getRequestId(), subscription.getQueryState()));
private void sendSubscription(final Subscription<T> subscription) {
ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation<String, Task<Void>>() {
@Override
public Task<Void> then(Task<String> task) throws Exception {
String sessionToken = task.getResult();
return sendOperationAsync(new SubscribeClientOperation<>(subscription.getRequestId(), subscription.getQueryState(), sessionToken));
}
});
}

private void sendUnsubscription(Subscription subscription) {
Expand All @@ -236,7 +240,13 @@ private WebSocketClient.WebSocketClientCallback getWebSocketClientCallback() {
@Override
public void onOpen() {
Log.v(LOG_TAG, "Socket opened");
sendOperationAsync(new ConnectClientOperation(applicationId, "")).continueWith(new Continuation<Void, Void>() {
ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation<String, Task<Void>>() {
@Override
public Task<Void> then(Task<String> task) throws Exception {
String sessionToken = task.getResult();
return sendOperationAsync(new ConnectClientOperation(applicationId, sessionToken));
}
}).continueWith(new Continuation<Void, Void>() {
public Void then(Task<Void> task) {
Exception error = task.getError();
if (error != null) {
Expand Down Expand Up @@ -277,5 +287,4 @@ public void stateChanged() {
}
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@

private final int requestId;
private final ParseQuery.State<T> state;
private final String sessionToken;

/* package */ SubscribeClientOperation(int requestId, final ParseQuery.State<T> state) {
/* package */ SubscribeClientOperation(int requestId, ParseQuery.State<T> state, String sessionToken) {
this.requestId = requestId;
this.state = state;
this.sessionToken = sessionToken;
}

@Override
/* package */ JSONObject getJSONObjectRepresentation() throws JSONException {
JSONObject jsonObject = new JSONObject();
jsonObject.put("op", "subscribe");
jsonObject.put("requestId", requestId);
jsonObject.put("sessionToken", sessionToken);

JSONObject queryJsonObject = state.toJSON(NoObjectsEncoder.get());

Expand Down
106 changes: 91 additions & 15 deletions ParseLiveQuery/src/test/java/com/parse/TestParseLiveQueryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,28 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;

import java.net.URI;
import java.util.concurrent.Executor;

import bolts.Task;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.mockito.AdditionalMatchers.and;
import static org.mockito.AdditionalMatchers.not;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.contains;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
Expand All @@ -29,9 +38,29 @@ public class TestParseLiveQueryClient {
private WebSocketClient.WebSocketClientCallback webSocketClientCallback;
private ParseLiveQueryClient<ParseObject> parseLiveQueryClient;

private ParseUser mockUser;

@Before
public void setUp() throws Exception {
ParsePlugins.initialize("1234", "1234");

// Register a mock currentUserController to make getCurrentUser work
mockUser = mock(ParseUser.class);
ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class);
when(currentUserController.getAsync(anyBoolean())).thenAnswer(new Answer<Task<ParseUser>>() {
@Override
public Task<ParseUser> answer(InvocationOnMock invocation) throws Throwable {
return Task.forResult(mockUser);
}
});
when(currentUserController.getCurrentSessionTokenAsync()).thenAnswer(new Answer<Task<String>>() {
@Override
public Task<String> answer(InvocationOnMock invocation) throws Throwable {
return Task.forResult(mockUser.getSessionToken());
}
});
ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController);

parseLiveQueryClient = ParseLiveQueryClient.Factory.getClient(new URI(""), new WebSocketClientFactory() {
@Override
public WebSocketClient createInstance(WebSocketClient.WebSocketClientCallback webSocketClientCallback, URI hostUrl) {
Expand Down Expand Up @@ -67,12 +96,14 @@ public void testSubscribeWhenSubscribedToCallback() throws Exception {
@Test
public void testUnsubscribeWhenSubscribedToCallback() throws Exception {
ParseQuery<ParseObject> parseQuery = new ParseQuery<>("test");
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery, mock(SubscriptionHandling.HandleSubscribeCallback.class));
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery,
mock(SubscriptionHandling.HandleSubscribeCallback.class));

parseLiveQueryClient.unsubscribe(parseQuery);
verify(webSocketClient, times(1)).send(any(String.class));

SubscriptionHandling.HandleUnsubscribeCallback<ParseObject> unsubscribeMockCallback = mock(SubscriptionHandling.HandleUnsubscribeCallback.class);
SubscriptionHandling.HandleUnsubscribeCallback<ParseObject> unsubscribeMockCallback = mock(
SubscriptionHandling.HandleUnsubscribeCallback.class);
subscriptionHandling.handleUnsubscribe(unsubscribeMockCallback);
webSocketClientCallback.onMessage(createUnsubscribedMessage(subscriptionHandling.getRequestId()).toString());

Expand All @@ -82,7 +113,8 @@ public void testUnsubscribeWhenSubscribedToCallback() throws Exception {
@Test
public void testErrorWhenSubscribedToCallback() throws Exception {
ParseQuery<ParseObject> parseQuery = new ParseQuery<>("test");
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery, mock(SubscriptionHandling.HandleSubscribeCallback.class));
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery,
mock(SubscriptionHandling.HandleSubscribeCallback.class));

SubscriptionHandling.HandleErrorCallback<ParseObject> errorMockCallback = mock(SubscriptionHandling.HandleErrorCallback.class);
subscriptionHandling.handleError(errorMockCallback);
Expand All @@ -103,7 +135,8 @@ public void testErrorWhenSubscribedToCallback() throws Exception {
@Test
public void testCreateEventWhenSubscribedToCallback() throws Exception {
ParseQuery<ParseObject> parseQuery = new ParseQuery<>("test");
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery, mock(SubscriptionHandling.HandleSubscribeCallback.class));
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery,
mock(SubscriptionHandling.HandleSubscribeCallback.class));

SubscriptionHandling.HandleEventCallback<ParseObject> eventMockCallback = mock(SubscriptionHandling.HandleEventCallback.class);
subscriptionHandling.handleEvent(SubscriptionHandling.Event.CREATE, eventMockCallback);
Expand All @@ -119,7 +152,8 @@ public void testCreateEventWhenSubscribedToCallback() throws Exception {
@Test
public void testEnterEventWhenSubscribedToCallback() throws Exception {
ParseQuery<ParseObject> parseQuery = new ParseQuery<>("test");
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery, mock(SubscriptionHandling.HandleSubscribeCallback.class));
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery,
mock(SubscriptionHandling.HandleSubscribeCallback.class));

SubscriptionHandling.HandleEventCallback<ParseObject> eventMockCallback = mock(SubscriptionHandling.HandleEventCallback.class);
subscriptionHandling.handleEvent(SubscriptionHandling.Event.ENTER, eventMockCallback);
Expand All @@ -135,7 +169,8 @@ public void testEnterEventWhenSubscribedToCallback() throws Exception {
@Test
public void testUpdateEventWhenSubscribedToCallback() throws Exception {
ParseQuery<ParseObject> parseQuery = new ParseQuery<>("test");
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery, mock(SubscriptionHandling.HandleSubscribeCallback.class));
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery,
mock(SubscriptionHandling.HandleSubscribeCallback.class));

SubscriptionHandling.HandleEventCallback<ParseObject> eventMockCallback = mock(SubscriptionHandling.HandleEventCallback.class);
subscriptionHandling.handleEvent(SubscriptionHandling.Event.UPDATE, eventMockCallback);
Expand All @@ -151,7 +186,8 @@ public void testUpdateEventWhenSubscribedToCallback() throws Exception {
@Test
public void testLeaveEventWhenSubscribedToCallback() throws Exception {
ParseQuery<ParseObject> parseQuery = new ParseQuery<>("test");
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery, mock(SubscriptionHandling.HandleSubscribeCallback.class));
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery,
mock(SubscriptionHandling.HandleSubscribeCallback.class));

SubscriptionHandling.HandleEventCallback<ParseObject> eventMockCallback = mock(SubscriptionHandling.HandleEventCallback.class);
subscriptionHandling.handleEvent(SubscriptionHandling.Event.LEAVE, eventMockCallback);
Expand All @@ -164,11 +200,11 @@ public void testLeaveEventWhenSubscribedToCallback() throws Exception {
validateSameObject(eventMockCallback, parseQuery, parseObject);
}


@Test
public void testDeleteEventWhenSubscribedToCallback() throws Exception {
ParseQuery<ParseObject> parseQuery = new ParseQuery<>("test");
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery, mock(SubscriptionHandling.HandleSubscribeCallback.class));
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery,
mock(SubscriptionHandling.HandleSubscribeCallback.class));

SubscriptionHandling.HandleEventCallback<ParseObject> eventMockCallback = mock(SubscriptionHandling.HandleEventCallback.class);
subscriptionHandling.handleEvent(SubscriptionHandling.Event.DELETE, eventMockCallback);
Expand All @@ -184,7 +220,8 @@ public void testDeleteEventWhenSubscribedToCallback() throws Exception {
@Test
public void testCreateEventWhenSubscribedToAnyCallback() throws Exception {
ParseQuery<ParseObject> parseQuery = new ParseQuery<>("test");
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery, mock(SubscriptionHandling.HandleSubscribeCallback.class));
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery,
mock(SubscriptionHandling.HandleSubscribeCallback.class));

SubscriptionHandling.HandleEventsCallback<ParseObject> eventsMockCallback = mock(SubscriptionHandling.HandleEventsCallback.class);
subscriptionHandling.handleEvents(eventsMockCallback);
Expand All @@ -205,12 +242,14 @@ public void testCreateEventWhenSubscribedToAnyCallback() throws Exception {
@Test
public void testSubscriptionStoppedAfterUnsubscribe() throws Exception {
ParseQuery<ParseObject> parseQuery = new ParseQuery<>("test");
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery, mock(SubscriptionHandling.HandleSubscribeCallback.class));
SubscriptionHandling<ParseObject> subscriptionHandling = createSubscription(parseQuery,
mock(SubscriptionHandling.HandleSubscribeCallback.class));

SubscriptionHandling.HandleEventCallback<ParseObject> eventMockCallback = mock(SubscriptionHandling.HandleEventCallback.class);
subscriptionHandling.handleEvent(SubscriptionHandling.Event.CREATE, eventMockCallback);

SubscriptionHandling.HandleUnsubscribeCallback<ParseObject> unsubscribeMockCallback = mock(SubscriptionHandling.HandleUnsubscribeCallback.class);
SubscriptionHandling.HandleUnsubscribeCallback<ParseObject> unsubscribeMockCallback = mock(
SubscriptionHandling.HandleUnsubscribeCallback.class);
subscriptionHandling.handleUnsubscribe(unsubscribeMockCallback);

parseLiveQueryClient.unsubscribe(parseQuery);
Expand Down Expand Up @@ -239,14 +278,52 @@ public void testSubscriptionReplayedAfterReconnect() throws Exception {
verify(webSocketClient, times(2)).send(any(String.class));
}

@Test
public void testSessionTokenSentOnConnect() {
when(mockUser.getSessionToken()).thenReturn("the token");
parseLiveQueryClient.reconnect();
webSocketClientCallback.onOpen();
verify(webSocketClient, times(1)).send(contains("\"sessionToken\":\"the token\""));
}

private SubscriptionHandling<ParseObject> createSubscription(ParseQuery<ParseObject> parseQuery, SubscriptionHandling.HandleSubscribeCallback<ParseObject> subscribeMockCallback) throws Exception {
@Test
public void testEmptySessionTokenOnConnect() {
parseLiveQueryClient.reconnect();
webSocketClientCallback.onOpen();
verify(webSocketClient, times(1)).send(not(contains("\"sessionToken\":")));
}

@Test
public void testSessionTokenSentOnSubscribe() {
when(mockUser.getSessionToken()).thenReturn("the token");
when(webSocketClient.getState()).thenReturn(WebSocketClient.State.CONNECTED);
parseLiveQueryClient.subscribe(ParseQuery.getQuery("Test"));
verify(webSocketClient, times(1)).send(and(
contains("\"op\":\"subscribe\""),
contains("\"sessionToken\":\"the token\"")));
}

@Test
public void testEmptySessionTokenOnSubscribe() {
when(mockUser.getSessionToken()).thenReturn("the token");
when(webSocketClient.getState()).thenReturn(WebSocketClient.State.CONNECTED);
parseLiveQueryClient.subscribe(ParseQuery.getQuery("Test"));
verify(webSocketClient, times(1)).send(contains("\"op\":\"connect\""));
verify(webSocketClient, times(1)).send(and(
contains("\"op\":\"subscribe\""),
contains("\"sessionToken\":\"the token\"")));
}

private SubscriptionHandling<ParseObject> createSubscription(ParseQuery<ParseObject> parseQuery,
SubscriptionHandling.HandleSubscribeCallback<ParseObject> subscribeMockCallback) throws Exception {
SubscriptionHandling<ParseObject> subscriptionHandling = parseLiveQueryClient.subscribe(parseQuery).handleSubscribe(subscribeMockCallback);
webSocketClientCallback.onMessage(createSubscribedMessage(subscriptionHandling.getRequestId()).toString());
return subscriptionHandling;
}

private void validateSameObject(SubscriptionHandling.HandleEventCallback<ParseObject> eventMockCallback, ParseQuery<ParseObject> parseQuery, ParseObject originalParseObject) {
private void validateSameObject(SubscriptionHandling.HandleEventCallback<ParseObject> eventMockCallback,
ParseQuery<ParseObject> parseQuery,
ParseObject originalParseObject) {
ArgumentCaptor<ParseObject> objectCaptor = ArgumentCaptor.forClass(ParseObject.class);
verify(eventMockCallback, times(1)).onEvent(eq(parseQuery), objectCaptor.capture());

Expand Down Expand Up @@ -335,5 +412,4 @@ private static JSONObject createObjectDeleteMessage(int requestId, ParseObject p
jsonObject.put("object", PointerEncoder.get().encodeRelatedObject(parseObject));
return jsonObject;
}

}