Commit 38a06f63 authored by Zhiqiang Zhang's avatar Zhiqiang Zhang Committed by Commit Bot

Unit test for CafMessageHandler

Most of the tests are migrated from CastMessageHandlerTest. Some
new tests are added as CafMessageHandler has more methods than
CastMessageHandler:

* testHandleClientConnectMessage*
* testHandleClientDisconnectMessage*
* testHandleClientLeaveSessionMessage*
* testSendReceiverActionToClient
* testBuildSessionMessage*

Bug: 711860
Change-Id: I821bb91f0c685809c143b60cc4700c47ffec16b6
Reviewed-on: https://chromium-review.googlesource.com/c/1343292
Commit-Queue: Zhiqiang Zhang <zqzhang@chromium.org>
Reviewed-by: default avatarThomas Guilbert <tguilbert@chromium.org>
Cr-Commit-Position: refs/heads/master@{#609805}
parent 8c45c21a
...@@ -70,8 +70,6 @@ public class CafMessageHandler { ...@@ -70,8 +70,6 @@ public class CafMessageHandler {
private ArrayMap<String, Queue<Integer>> mStopRequests; private ArrayMap<String, Queue<Integer>> mStopRequests;
private Queue<RequestRecord> mVolumeRequests; private Queue<RequestRecord> mVolumeRequests;
// The reference to CastSession, only valid after calling {@link onSessionCreated}, and will be
// reset to null when calling {@link onApplicationStopped}.
private final CastSessionController mSessionController; private final CastSessionController mSessionController;
private final CafMediaRouteProvider mRouteProvider; private final CafMediaRouteProvider mRouteProvider;
private Handler mHandler; private Handler mHandler;
...@@ -216,7 +214,7 @@ public class CafMessageHandler { ...@@ -216,7 +214,7 @@ public class CafMessageHandler {
if (clientId == null || !mSessionController.isConnected()) return false; if (clientId == null || !mSessionController.isConnected()) return false;
String sessionId = jsonMessage.getString("message"); String sessionId = jsonMessage.getString("message");
if (!mSessionController.getSession().getSessionId().equals(sessionId)) return false; if (!mSessionController.getSessionId().equals(sessionId)) return false;
ClientRecord currentClient = mRouteProvider.getClientIdToRecords().get(clientId); ClientRecord currentClient = mRouteProvider.getClientIdToRecords().get(clientId);
if (currentClient == null) return false; if (currentClient == null) return false;
...@@ -225,8 +223,8 @@ public class CafMessageHandler { ...@@ -225,8 +223,8 @@ public class CafMessageHandler {
// The web sender SDK doesn't actually recognize "leave_session" response, but this is to // The web sender SDK doesn't actually recognize "leave_session" response, but this is to
// acknowledge the "leave_session" request. // acknowledge the "leave_session" request.
mRouteProvider.sendMessageToClient(clientId, mRouteProvider.sendMessageToClient(
buildSimpleSessionMessage("leave_session", sequenceNumber, clientId, null)); clientId, buildSimpleSessionMessage("leave_session", sequenceNumber, clientId));
List<ClientRecord> leavingClients = new ArrayList<>(); List<ClientRecord> leavingClients = new ArrayList<>();
...@@ -253,14 +251,13 @@ public class CafMessageHandler { ...@@ -253,14 +251,13 @@ public class CafMessageHandler {
} }
/** Builds a simple message for session-related events. */ /** Builds a simple message for session-related events. */
private String buildSimpleSessionMessage( private String buildSimpleSessionMessage(String type, int sequenceNumber, String clientId)
String type, int sequenceNumber, String clientId, String message) throws JSONException { throws JSONException {
JSONObject jsonMessage = new JSONObject(); JSONObject jsonMessage = new JSONObject();
jsonMessage.put("type", type); jsonMessage.put("type", type);
jsonMessage.put("sequenceNumber", sequenceNumber); jsonMessage.put("sequenceNumber", sequenceNumber);
jsonMessage.put("timeoutMillis", TIMEOUT_IMMEDIATE); jsonMessage.put("timeoutMillis", TIMEOUT_IMMEDIATE);
jsonMessage.put("clientId", clientId); jsonMessage.put("clientId", clientId);
jsonMessage.put("message", message);
return jsonMessage.toString(); return jsonMessage.toString();
} }
...@@ -414,7 +411,7 @@ public class CafMessageHandler { ...@@ -414,7 +411,7 @@ public class CafMessageHandler {
JSONObject jsonAppMessageWrapper = jsonMessage.getJSONObject("message"); JSONObject jsonAppMessageWrapper = jsonMessage.getJSONObject("message");
if (!mSessionController.getSession().getSessionId().equals( if (!mSessionController.getSessionId().equals(
jsonAppMessageWrapper.getString("sessionId"))) { jsonAppMessageWrapper.getString("sessionId"))) {
return false; return false;
} }
...@@ -522,7 +519,7 @@ public class CafMessageHandler { ...@@ -522,7 +519,7 @@ public class CafMessageHandler {
void onAppMessage(String message, String namespace, RequestRecord request) { void onAppMessage(String message, String namespace, RequestRecord request) {
try { try {
JSONObject jsonMessage = new JSONObject(); JSONObject jsonMessage = new JSONObject();
jsonMessage.put("sessionId", mSessionController.getSession().getSessionId()); jsonMessage.put("sessionId", mSessionController.getSessionId());
jsonMessage.put("namespaceName", namespace); jsonMessage.put("namespaceName", namespace);
jsonMessage.put("message", message); jsonMessage.put("message", message);
if (request != null) { if (request != null) {
...@@ -544,13 +541,13 @@ public class CafMessageHandler { ...@@ -544,13 +541,13 @@ public class CafMessageHandler {
Queue<Integer> sequenceNumbersForClient = mStopRequests.get(clientId); Queue<Integer> sequenceNumbersForClient = mStopRequests.get(clientId);
if (sequenceNumbersForClient == null) { if (sequenceNumbersForClient == null) {
sendEnclosedMessageToClient(clientId, "remove_session", sendEnclosedMessageToClient(clientId, "remove_session",
mSessionController.getSession().getSessionId(), VOID_SEQUENCE_NUMBER); mSessionController.getSessionId(), VOID_SEQUENCE_NUMBER);
continue; continue;
} }
for (int sequenceNumber : sequenceNumbersForClient) { for (int sequenceNumber : sequenceNumbersForClient) {
sendEnclosedMessageToClient(clientId, "remove_session", sendEnclosedMessageToClient(clientId, "remove_session",
mSessionController.getSession().getSessionId(), sequenceNumber); mSessionController.getSessionId(), sequenceNumber);
} }
mStopRequests.remove(clientId); mStopRequests.remove(clientId);
} }
...@@ -688,7 +685,7 @@ public class CafMessageHandler { ...@@ -688,7 +685,7 @@ public class CafMessageHandler {
} }
JSONObject jsonMessage = new JSONObject(); JSONObject jsonMessage = new JSONObject();
jsonMessage.put("sessionId", mSessionController.getSession().getSessionId()); jsonMessage.put("sessionId", mSessionController.getSessionId());
jsonMessage.put("statusText", mSessionController.getSession().getApplicationStatus()); jsonMessage.put("statusText", mSessionController.getSession().getApplicationStatus());
jsonMessage.put("receiver", jsonReceiver); jsonMessage.put("receiver", jsonReceiver);
jsonMessage.put("namespaces", jsonNamespaces); jsonMessage.put("namespaces", jsonNamespaces);
...@@ -714,12 +711,12 @@ public class CafMessageHandler { ...@@ -714,12 +711,12 @@ public class CafMessageHandler {
* Modifies the received MediaStatus message to match the format expected by the client. * Modifies the received MediaStatus message to match the format expected by the client.
*/ */
private void sanitizeMediaStatusMessage(JSONObject object) throws JSONException { private void sanitizeMediaStatusMessage(JSONObject object) throws JSONException {
object.put("sessionId", mSessionController.getSession().getSessionId()); object.put("sessionId", mSessionController.getSessionId());
JSONArray mediaStatus = object.getJSONArray("status"); JSONArray mediaStatus = object.getJSONArray("status");
for (int i = 0; i < mediaStatus.length(); ++i) { for (int i = 0; i < mediaStatus.length(); ++i) {
JSONObject status = mediaStatus.getJSONObject(i); JSONObject status = mediaStatus.getJSONObject(i);
status.put("sessionId", mSessionController.getSession().getSessionId()); status.put("sessionId", mSessionController.getSessionId());
if (!status.has("supportedMediaCommands")) continue; if (!status.has("supportedMediaCommands")) continue;
JSONArray commands = new JSONArray(); JSONArray commands = new JSONArray();
...@@ -776,7 +773,7 @@ public class CafMessageHandler { ...@@ -776,7 +773,7 @@ public class CafMessageHandler {
return result; return result;
} }
private boolean sendStringCastMessage( boolean sendStringCastMessage(
String message, String namespace, String clientId, int sequenceNumber) { String message, String namespace, String clientId, int sequenceNumber) {
if (!mSessionController.isConnected()) return false; if (!mSessionController.isConnected()) return false;
...@@ -795,7 +792,7 @@ public class CafMessageHandler { ...@@ -795,7 +792,7 @@ public class CafMessageHandler {
* @param clientId The client id the message is sent from. * @param clientId The client id the message is sent from.
* @param sequenceNumber The sequence number of the message. * @param sequenceNumber The sequence number of the message.
*/ */
private void onSendAppMessageResult(Status result, String clientId, int sequenceNumber) { void onSendAppMessageResult(Status result, String clientId, int sequenceNumber) {
if (!result.isSuccess()) { if (!result.isSuccess()) {
// TODO(avayvod): should actually report back to the page. // TODO(avayvod): should actually report back to the page.
// See https://crbug.com/550445. // See https://crbug.com/550445.
......
...@@ -2366,12 +2366,12 @@ chrome_junit_test_java_sources = [ ...@@ -2366,12 +2366,12 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterSinkObservationTest.java", "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterSinkObservationTest.java",
"junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterTestBase.java", "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterTestBase.java",
"junit/src/org/chromium/chrome/browser/media/router/DiscoveryCallbackTest.java", "junit/src/org/chromium/chrome/browser/media/router/DiscoveryCallbackTest.java",
"junit/src/org/chromium/chrome/browser/media/router/JSONTestUtils.java",
"junit/src/org/chromium/chrome/browser/media/router/TestUtils.java", "junit/src/org/chromium/chrome/browser/media/router/TestUtils.java",
"junit/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProviderTest.java", "junit/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProviderTest.java",
"junit/src/org/chromium/chrome/browser/media/router/cast/CastMediaSourceTest.java", "junit/src/org/chromium/chrome/browser/media/router/cast/CastMediaSourceTest.java",
"junit/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandlerTest.java", "junit/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandlerTest.java",
"junit/src/org/chromium/chrome/browser/media/router/cast/ChromeCastSessionManagerTest.java", "junit/src/org/chromium/chrome/browser/media/router/cast/ChromeCastSessionManagerTest.java",
"junit/src/org/chromium/chrome/browser/media/router/cast/JSONTestUtils.java",
"junit/src/org/chromium/chrome/browser/media/router/caf/MediaRouterTestHelper.java", "junit/src/org/chromium/chrome/browser/media/router/caf/MediaRouterTestHelper.java",
"junit/src/org/chromium/chrome/browser/media/router/caf/ShadowMediaRouter.java", "junit/src/org/chromium/chrome/browser/media/router/caf/ShadowMediaRouter.java",
"junit/src/org/chromium/chrome/browser/media/router/caf/ShadowCastContext.java", "junit/src/org/chromium/chrome/browser/media/router/caf/ShadowCastContext.java",
...@@ -2380,6 +2380,7 @@ chrome_junit_test_java_sources = [ ...@@ -2380,6 +2380,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/media/router/caf/CastSessionControllerTest.java", "junit/src/org/chromium/chrome/browser/media/router/caf/CastSessionControllerTest.java",
"junit/src/org/chromium/chrome/browser/media/router/caf/CafBaseMediaRouteProviderTest.java", "junit/src/org/chromium/chrome/browser/media/router/caf/CafBaseMediaRouteProviderTest.java",
"junit/src/org/chromium/chrome/browser/media/router/caf/CafMediaRouteProviderTest.java", "junit/src/org/chromium/chrome/browser/media/router/caf/CafMediaRouteProviderTest.java",
"junit/src/org/chromium/chrome/browser/media/router/caf/CafMessageHandlerTest.java",
"junit/src/org/chromium/chrome/browser/media/ui/MediaImageManagerTest.java", "junit/src/org/chromium/chrome/browser/media/ui/MediaImageManagerTest.java",
"junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationActionsUpdatedTest.java", "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationActionsUpdatedTest.java",
"junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationButtonComputationTest.java", "junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationButtonComputationTest.java",
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
package org.chromium.chrome.browser.media.router.cast; package org.chromium.chrome.browser.media.router;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
...@@ -13,7 +13,6 @@ import java.util.Iterator; ...@@ -13,7 +13,6 @@ import java.util.Iterator;
/** /**
* Utilities for comparing JSON objects and strings. * Utilities for comparing JSON objects and strings.
* TODO(zqzhang): Move the class to somewhere more generic.
*/ */
public class JSONTestUtils { public class JSONTestUtils {
private static final String TAG = "MediaRouter"; private static final String TAG = "MediaRouter";
...@@ -36,6 +35,7 @@ public class JSONTestUtils { ...@@ -36,6 +35,7 @@ public class JSONTestUtils {
return true; return true;
} }
/** Returns whether two JSON arrays are equal. */
public static boolean isJSONArrayEqual(JSONArray expected, JSONArray actual) { public static boolean isJSONArrayEqual(JSONArray expected, JSONArray actual) {
try { try {
if (expected.length() != actual.length()) return false; if (expected.length() != actual.length()) return false;
...@@ -48,6 +48,7 @@ public class JSONTestUtils { ...@@ -48,6 +48,7 @@ public class JSONTestUtils {
return true; return true;
} }
/** Returns whether two JSON objects are equal. */
public static boolean isJSONObjectEqual(Object expected, Object actual) { public static boolean isJSONObjectEqual(Object expected, Object actual) {
if (expected == null && actual == null) return true; if (expected == null && actual == null) return true;
if (expected == null || actual == null) return false; if (expected == null || actual == null) return false;
...@@ -74,7 +75,8 @@ public class JSONTestUtils { ...@@ -74,7 +75,8 @@ public class JSONTestUtils {
} }
} }
static class JSONObjectLike implements ArgumentMatcher<JSONObject> { /** Matcher to determine whether a JSON object is equal to the expected one. */
public static class JSONObjectLike implements ArgumentMatcher<JSONObject> {
private final JSONObject mExpected; private final JSONObject mExpected;
public JSONObjectLike(JSONObject expected) { public JSONObjectLike(JSONObject expected) {
...@@ -92,7 +94,8 @@ public class JSONTestUtils { ...@@ -92,7 +94,8 @@ public class JSONTestUtils {
} }
} }
static class JSONStringLike implements ArgumentMatcher<String> { /** Matcher to determine whether a JSON string is equal to the expected one. */
public static class JSONStringLike implements ArgumentMatcher<String> {
private JSONObject mExpected; private JSONObject mExpected;
public JSONStringLike(JSONObject expected) { public JSONStringLike(JSONObject expected) {
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.media.router.caf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import com.google.android.gms.cast.ApplicationMetadata;
import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.framework.CastSession;
import com.google.android.gms.common.api.Status;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.media.router.CastSessionUtil;
import org.chromium.chrome.browser.media.router.ClientRecord;
import org.chromium.chrome.browser.media.router.JSONTestUtils.JSONObjectLike;
import org.chromium.chrome.browser.media.router.JSONTestUtils.JSONStringLike;
import org.chromium.chrome.browser.media.router.MediaSink;
import org.chromium.chrome.browser.media.router.caf.CafMessageHandler.RequestRecord;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Robolectric tests for CastSession.
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class CafMessageHandlerTest {
private static final String TAG = "MediaRouter";
private static final String SESSION_ID = "SESSION_ID";
private static final String INVALID_SESSION_ID = "INVALID_SESSION_ID";
private static final String CLIENT_ID1 = "client-id-1";
private static final String CLIENT_ID2 = "client-id-2";
private static final String INVALID_CLIENT_ID = "xxxxxxxxxxxxxxxxx";
private static final String NAMESPACE1 = "namespace1";
private static final String NAMESPACE2 = "namespace2";
private static final String MEDIA_NAMESPACE = CastSessionUtil.MEDIA_NAMESPACE;
private static final int SEQUENCE_NUMBER1 = 1;
private static final int SEQUENCE_NUMBER2 = 2;
private static final int REQUEST_ID1 = 1;
private static final int REQUEST_ID2 = 2;
private static final int VOID_SEQUENCE_NUMBER = CafMessageHandler.VOID_SEQUENCE_NUMBER;
private CafMediaRouteProvider mRouteProvider;
@Mock
private CastSession mSession;
@Mock
private CastSessionController mSessionController;
private ClientRecord mClientRecord1;
private ClientRecord mClientRecord2;
private Map<String, ClientRecord> mClientRecordMap;
private CafMessageHandler mMessageHandler;
private int mNumStopApplicationCalled;
private interface CheckedRunnable { void run() throws Exception; }
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mRouteProvider = mock(CafMediaRouteProvider.class);
mClientRecord1 =
new ClientRecord("route-id-1", CLIENT_ID1, "app-id", "auto-join", "origin", 1);
mClientRecord2 =
new ClientRecord("route-id-2", CLIENT_ID2, "app-id", "auto-join", "origin2", 1);
mMessageHandler = spy(new CafMessageHandler(mRouteProvider, mSessionController));
doReturn(SESSION_ID).when(mSessionController).getSessionId();
doReturn(true)
.when(mMessageHandler)
.sendStringCastMessage(anyString(), anyString(), anyString(), anyInt());
doReturn(mSession).when(mSessionController).getSession();
doReturn(true).when(mSessionController).isConnected();
doReturn(SESSION_ID).when(mSessionController).getSessionId();
mClientRecordMap = new HashMap<>();
mClientRecordMap.put(CLIENT_ID1, mClientRecord1);
mClientRecordMap.put(CLIENT_ID2, mClientRecord2);
doReturn(mClientRecordMap).when(mRouteProvider).getClientIdToRecords();
doNothing().when(mRouteProvider).sendMessageToClient(anyString(), anyString());
}
void setUpForAppMessageTest() throws JSONException {
List<String> namespaces = new ArrayList<String>();
namespaces.add(NAMESPACE1);
doReturn(namespaces).when(mSessionController).getNamespaces();
doReturn(true)
.when(mMessageHandler)
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testOnSessionStarted() {
doReturn("session_message").when(mMessageHandler).buildSessionMessage();
// The call in setUp() actually only sets the session. This call will notify the clients
// that have sent "client_connect"
mClientRecord1.isConnected = true;
mMessageHandler.onSessionStarted();
verify(mMessageHandler)
.sendEnclosedMessageToClient(
CLIENT_ID1, "new_session", "session_message", VOID_SEQUENCE_NUMBER);
verify(mMessageHandler, never())
.sendEnclosedMessageToClient(eq(CLIENT_ID2), anyString(), anyString(), anyInt());
}
@Test
public void testHandleClientConnectMessage_sessionConnected() throws JSONException {
doReturn("session_message").when(mMessageHandler).buildSessionMessage();
mClientRecord1.isConnected = false;
JSONObject message = new JSONObject();
message.put("type", "client_connect");
message.put("clientId", mClientRecord1.clientId);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
assertTrue(mClientRecord1.isConnected);
verify(mMessageHandler)
.sendEnclosedMessageToClient(mClientRecord1.clientId, "new_session",
"session_message", VOID_SEQUENCE_NUMBER);
verify(mRouteProvider).flushPendingMessagesToClient(mClientRecord1);
}
@Test
public void testHandleClientConnectMessage_sessionNotConnected() throws JSONException {
doReturn("session_message").when(mMessageHandler).buildSessionMessage();
doReturn(false).when(mSessionController).isConnected();
mClientRecord1.isConnected = false;
JSONObject message = new JSONObject();
message.put("type", "client_connect");
message.put("clientId", mClientRecord1.clientId);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
assertTrue(mClientRecord1.isConnected);
verify(mMessageHandler, never())
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
verify(mRouteProvider).flushPendingMessagesToClient(mClientRecord1);
}
@Test
public void testHandleClientConnectMessage_noClientRecord() throws JSONException {
doReturn("session_message").when(mMessageHandler).buildSessionMessage();
JSONObject message = new JSONObject();
message.put("type", "client_connect");
message.put("clientId", "other-client-id");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
verify(mRouteProvider, never()).flushPendingMessagesToClient(any(ClientRecord.class));
}
@Test
public void testHandleClientConnectMessage_noClientId() throws JSONException {
doReturn("session_message").when(mMessageHandler).buildSessionMessage();
JSONObject message = new JSONObject();
message.put("type", "client_connect");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
verify(mRouteProvider, never()).flushPendingMessagesToClient(any(ClientRecord.class));
}
@Test
public void testHandleClientDisconnectMessage() throws JSONException {
JSONObject message = new JSONObject();
message.put("type", "client_disconnect");
message.put("clientId", mClientRecord1.clientId);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mRouteProvider).removeRoute("route-id-1", null);
}
@Test
public void testHandleClientDisconnectMessage_noClientRecord() throws JSONException {
JSONObject message = new JSONObject();
message.put("type", "client_disconnect");
message.put("clientId", "other-client-id");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mRouteProvider, never()).removeRoute(anyString(), anyString());
}
@Test
public void testHandleClientDisconnectMessage_noClientId() throws JSONException {
JSONObject message = new JSONObject();
message.put("type", "client_disconnect");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mRouteProvider, never()).removeRoute(anyString(), anyString());
}
@Test
public void testHandleClientLeaveSessionMessage() throws JSONException {
JSONObject message = buildLeaveSessionMessage(mClientRecord1.clientId, SESSION_ID, 12345);
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mRouteProvider)
.sendMessageToClient(eq(mClientRecord1.clientId), messageCaptor.capture());
JSONObject capturedMessage = new JSONObject(messageCaptor.getValue());
verifySimpleSessionMessage(
capturedMessage, "leave_session", 12345, mClientRecord1.clientId);
}
@Test
public void testHandleClientLeaveSessionMessage_noSequenceNumber() throws JSONException {
JSONObject message = buildLeaveSessionMessage(mClientRecord1.clientId, SESSION_ID, 12345);
message.remove("sequenceNumber");
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mRouteProvider)
.sendMessageToClient(eq(mClientRecord1.clientId), messageCaptor.capture());
JSONObject capturedMessage = new JSONObject(messageCaptor.getValue());
verifySimpleSessionMessage(
capturedMessage, "leave_session", VOID_SEQUENCE_NUMBER, mClientRecord1.clientId);
}
@Test
public void testHandleClientLeaveSessionMessage_noClientRecord() throws JSONException {
JSONObject message = buildLeaveSessionMessage("other-client-id", SESSION_ID, 12345);
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mRouteProvider, never()).sendMessageToClient(anyString(), anyString());
}
@Test
public void testHandleClientLeaveSessionMessage_wrongSessionId() throws JSONException {
JSONObject message =
buildLeaveSessionMessage(mClientRecord1.clientId, "other-session-id", 12345);
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mRouteProvider, never()).sendMessageToClient(anyString(), anyString());
}
@Test
public void testHandleClientLeaveSessionMessage_sessionNotConnected() throws JSONException {
doReturn(false).when(mSessionController).isConnected();
JSONObject message = buildLeaveSessionMessage(mClientRecord1.clientId, SESSION_ID, 12345);
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mRouteProvider, never()).sendMessageToClient(anyString(), anyString());
}
@Test
public void testHandleClientLeaveSessionMessage_noClientId() throws JSONException {
JSONObject message = buildLeaveSessionMessage(mClientRecord1.clientId, SESSION_ID, 12345);
message.remove("clientId");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mRouteProvider, never()).sendMessageToClient(anyString(), anyString());
}
@Test
public void testHandleClientLeaveSessionMessage_removeRoutes_tabAndOriginScoped()
throws JSONException {
mClientRecordMap.clear();
prepareClientRecord(
"route-id-1", "client-id-1", "app-id", "tab_and_origin_scoped", "origin", 1);
prepareClientRecord("route-id-2", "client-id-2", "app-id", "auto-join", "origin", 1);
prepareClientRecord("route-id-3", "client-id-3", "app-id", "auto-join", "origin2", 1);
prepareClientRecord("route-id-4", "client-id-4", "app-id", "auto-join", "origin", 2);
JSONObject message = buildLeaveSessionMessage("client-id-1", SESSION_ID, 12345);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
// Only routes with same origin and tab ID will be removed.
verify(mRouteProvider).removeRoute("route-id-1", null);
verify(mRouteProvider).removeRoute("route-id-2", null);
verify(mRouteProvider, never()).removeRoute("route-id-3", null);
verify(mRouteProvider, never()).removeRoute("route-id-4", null);
}
@Test
public void testHandleClientLeaveSessionMessage_removeRoutes_originScoped()
throws JSONException {
prepareClientRecord("route-id-1", "client-id-1", "app-id", "origin_scoped", "origin", 1);
prepareClientRecord("route-id-2", "client-id-2", "app-id", "auto-join", "origin", 1);
prepareClientRecord("route-id-3", "client-id-3", "app-id", "auto-join", "origin2", 1);
prepareClientRecord("route-id-4", "client-id-4", "app-id", "auto-join", "origin", 2);
JSONObject message = buildLeaveSessionMessage("client-id-1", SESSION_ID, 12345);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
// Only routes with same origin will be removed.
verify(mRouteProvider).removeRoute("route-id-1", null);
verify(mRouteProvider).removeRoute("route-id-2", null);
verify(mRouteProvider, never()).removeRoute("route-id-3", null);
verify(mRouteProvider).removeRoute("route-id-4", null);
}
@Test
public void testHandleClientLeaveSessionMessage_removeRoutes_otherScoped()
throws JSONException {
prepareClientRecord("route-id-1", "client-id-1", "app-id", "other_scoped", "origin", 1);
prepareClientRecord("route-id-2", "client-id-2", "app-id", "auto-join", "origin", 1);
prepareClientRecord("route-id-3", "client-id-3", "app-id", "auto-join", "origin2", 1);
prepareClientRecord("route-id-4", "client-id-4", "app-id", "auto-join", "origin", 2);
JSONObject message = buildLeaveSessionMessage("client-id-1", SESSION_ID, 12345);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
// No route should be removed.
verify(mRouteProvider, never()).removeRoute(anyString(), anyString());
}
@Test
public void testHandleSessionMessageOfV2MessageType() throws JSONException {
doReturn(true).when(mMessageHandler).handleCastV2MessageFromClient(any(JSONObject.class));
JSONObject message = new JSONObject();
message.put("type", "v2_message");
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler).handleCastV2MessageFromClient(argThat(new JSONObjectLike(message)));
}
@Test
public void testHandleSessionMessageOfAppMessageType() throws JSONException {
doReturn(true).when(mMessageHandler).handleAppMessageFromClient(any(JSONObject.class));
JSONObject message = new JSONObject();
message.put("type", "app_message");
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler).handleAppMessageFromClient(argThat(new JSONObjectLike(message)));
}
@Test
public void testHandleSessionMessageOfUnsupportedType() throws JSONException {
doReturn(true).when(mMessageHandler).handleCastV2MessageFromClient(any(JSONObject.class));
JSONObject message = new JSONObject();
message.put("type", "unsupported");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never()).handleCastV2MessageFromClient(any(JSONObject.class));
verify(mMessageHandler, never()).handleAppMessageFromClient(any(JSONObject.class));
}
@Test
public void testCastV2MessageWithWrongTypeInnerMessage() throws JSONException {
org.robolectric.shadows.ShadowLog.stream = System.out;
JSONObject innerMessage = new JSONObject().put("type", "STOP");
final JSONObject message = buildCastV2Message(CLIENT_ID1, innerMessage);
// Replace the inner JSON message with string.
message.put("message", "wrong type inner message");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never()).handleStopMessage(anyString(), anyInt());
verify(mMessageHandler, never())
.handleVolumeMessage(any(JSONObject.class), anyString(), anyInt());
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testCastV2MessageOfStopType() throws JSONException {
JSONObject innerMessage = new JSONObject().put("type", "STOP");
JSONObject message = buildCastV2Message(CLIENT_ID1, innerMessage);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler).handleStopMessage(eq(CLIENT_ID1), eq(SEQUENCE_NUMBER1));
}
@Test
public void testCastV2MessageofSetVolumeTypeShouldWait() throws Exception {
doReturn(true).when(mSession).isMute();
JSONObject innerMessage =
new JSONObject()
.put("type", "SET_VOLUME")
.put("volume",
new JSONObject().put("level", (double) 1).put("muted", false));
JSONObject message = buildCastV2Message(CLIENT_ID1, innerMessage);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
JSONObject volumeMessage = innerMessage.getJSONObject("volume");
verify(mSession).setMute(false);
verify(mSession).setVolume(1.0);
verify(mMessageHandler)
.handleVolumeMessage(
argThat(new JSONObjectLike(innerMessage.getJSONObject("volume"))),
eq(CLIENT_ID1), eq(SEQUENCE_NUMBER1));
assertEquals(mMessageHandler.getVolumeRequestsForTest().size(), 1);
}
@Test
public void testCastV2MessageofSetVolumeTypeShouldNotWait() throws Exception {
doReturn(false).when(mSession).isMute();
doReturn(1.0).when(mSession).getVolume();
JSONObject innerMessage =
new JSONObject()
.put("type", "SET_VOLUME")
.put("volume",
new JSONObject().put("level", (double) 1).put("muted", false));
JSONObject message = buildCastV2Message(CLIENT_ID1, innerMessage);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
JSONObject volumeMessage = innerMessage.getJSONObject("volume");
verify(mSession, never()).setMute(anyBoolean());
verify(mSession, never()).setVolume(anyDouble());
verify(mMessageHandler)
.handleVolumeMessage(
argThat(new JSONObjectLike(innerMessage.getJSONObject("volume"))),
eq(CLIENT_ID1), eq(SEQUENCE_NUMBER1));
assertEquals(mMessageHandler.getVolumeRequestsForTest().size(), 0);
}
@Test
public void testCastV2MessageofSetVolumeTypeWithNullVolumeMessage() throws JSONException {
JSONObject innerMessage = new JSONObject().put("type", "SET_VOLUME");
final JSONObject message = buildCastV2Message(CLIENT_ID1, innerMessage);
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.handleVolumeMessage(any(JSONObject.class), anyString(), anyInt());
}
@Test
public void testCastV2MessageofSetVolumeTypeWithWrongTypeVolumeMessage() throws JSONException {
JSONObject innerMessage = new JSONObject()
.put("type", "SET_VOLUME")
.put("volume", "wrong type volume message");
final JSONObject message = buildCastV2Message(CLIENT_ID1, innerMessage);
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.handleVolumeMessage(any(JSONObject.class), anyString(), anyInt());
}
@Test
public void testCastV2MessageOfMediaMessageType() throws JSONException {
doReturn(true)
.when(mMessageHandler)
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
for (String messageType : CafMessageHandler.getMediaMessageTypesForTest()) {
// TODO(zqzhang): SET_VOLUME and STOP should not reach here?
if ("MEDIA_SET_VOLUME".equals(messageType) || "STOP_MEDIA".equals(messageType)) {
continue;
}
JSONObject innerMessage = new JSONObject().put("type", messageType);
JSONObject message = buildCastV2Message(CLIENT_ID1, innerMessage);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
JSONObject expected = new JSONObject();
if (CafMessageHandler.getMediaOverloadedMessageTypesForTest().containsKey(
messageType)) {
expected.put("type",
CafMessageHandler.getMediaOverloadedMessageTypesForTest().get(messageType));
} else {
expected.put("type", messageType);
}
verify(mMessageHandler)
.sendJsonCastMessage(argThat(new JSONObjectLike(expected)),
eq(CastSessionUtil.MEDIA_NAMESPACE), eq(CLIENT_ID1),
eq(SEQUENCE_NUMBER1));
}
}
@Test
public void testCastV2MessageWithNullSequenceNumber() throws JSONException {
JSONObject innerMessage = new JSONObject().put("type", "STOP");
JSONObject message = buildCastV2Message(CLIENT_ID1, innerMessage);
message.remove("sequenceNumber");
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler).handleStopMessage(eq(CLIENT_ID1), eq(VOID_SEQUENCE_NUMBER));
}
@Test
public void testHandleStopMessage() throws JSONException {
InOrder inOrder = inOrder(mSessionController);
assertEquals(0, mMessageHandler.getStopRequestsForTest().size());
mMessageHandler.handleStopMessage(CLIENT_ID1, SEQUENCE_NUMBER1);
assertEquals(1, mMessageHandler.getStopRequestsForTest().get(CLIENT_ID1).size(), 1);
inOrder.verify(mSessionController).endSession();
mMessageHandler.handleStopMessage(CLIENT_ID1, SEQUENCE_NUMBER2);
assertEquals(2, mMessageHandler.getStopRequestsForTest().get(CLIENT_ID1).size(), 2);
inOrder.verify(mSessionController).endSession();
}
@Test
public void testAppMessageWithExistingNamespace() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler)
.sendJsonCastMessage(argThat(new JSONObjectLike(actualMessage)), eq(NAMESPACE1),
eq(CLIENT_ID1), eq(SEQUENCE_NUMBER1));
}
@Test
public void testAppMessageWithNonexistingNamespace() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE2, actualMessage);
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testAppMessageWithoutSequenceNumber() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
message.remove("sequenceNumber");
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler)
.sendJsonCastMessage(argThat(new JSONObjectLike(actualMessage)), eq(NAMESPACE1),
eq(CLIENT_ID1), eq(VOID_SEQUENCE_NUMBER));
}
@Test
public void testAppMessageWithNullSessionId() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
final JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
message.getJSONObject("message").remove("sessionId");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testAppMessageWithWrongSessionId() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
message.getJSONObject("message").put("sessionId", INVALID_SESSION_ID);
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testAppMessageWithNullActualMessage() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
final JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
message.getJSONObject("message").remove("message");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testAppMessageWithStringMessage() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
message.getJSONObject("message").put("message", "string message");
assertTrue(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
verify(mMessageHandler)
.sendStringCastMessage(
eq("string message"), eq(NAMESPACE1), eq(CLIENT_ID1), eq(SEQUENCE_NUMBER1));
}
@Test
public void testAppMessageWithNullAppMessage() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
final JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
message.remove("message");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testAppMessageWithEmptyAppMessage() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
final JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
message.put("message", new JSONObject());
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testAppMessageWithWrongTypeAppMessage() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
final JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
message.put("message", "wrong type app message");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testAppMessageWithNullClient() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
final JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
message.remove("clientId");
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testAppMessageWithNonexistingClient() throws JSONException {
setUpForAppMessageTest();
JSONObject actualMessage = buildActualAppMessage();
JSONObject message = buildAppMessage(CLIENT_ID1, NAMESPACE1, actualMessage);
message.put("clientId", INVALID_CLIENT_ID);
assertFalse(mMessageHandler.handleMessageFromClient(message.toString()));
verify(mMessageHandler, never())
.sendJsonCastMessage(any(JSONObject.class), anyString(), anyString(), anyInt());
}
@Test
public void testSendJsonCastMessage() throws JSONException {
assertEquals(mMessageHandler.getRequestsForTest().size(), 0);
JSONObject message = buildJsonCastMessage("message");
assertTrue(mMessageHandler.sendJsonCastMessage(
message, NAMESPACE1, CLIENT_ID1, SEQUENCE_NUMBER1));
assertEquals(mMessageHandler.getRequestsForTest().size(), 1);
verify(mMessageHandler)
.sendStringCastMessage(
argThat(new JSONStringLike(message)), anyString(), anyString(), anyInt());
}
@Test
public void testSendJsonCastMessageWhileDisconnected() throws JSONException {
doReturn(false).when(mSessionController).isConnected();
JSONObject message = buildJsonCastMessage("message");
assertFalse(mMessageHandler.sendJsonCastMessage(
message, NAMESPACE1, CLIENT_ID1, SEQUENCE_NUMBER1));
assertEquals(mMessageHandler.getRequestsForTest().size(), 0);
verify(mMessageHandler, never())
.sendStringCastMessage(anyString(), anyString(), anyString(), anyInt());
}
@Test
public void testSendJsonCastMessageWithInvalidSequenceNumber() throws JSONException {
JSONObject message = buildJsonCastMessage("message");
assertTrue(mMessageHandler.sendJsonCastMessage(
message, NAMESPACE1, CLIENT_ID1, VOID_SEQUENCE_NUMBER));
assertEquals(mMessageHandler.getRequestsForTest().size(), 0);
verify(mMessageHandler)
.sendStringCastMessage(
argThat(new JSONStringLike(message)), anyString(), anyString(), anyInt());
}
@Test
public void testSendJsonCastMessageWithNullRequestId() throws JSONException {
assertEquals(mMessageHandler.getRequestsForTest().size(), 0);
JSONObject message = buildJsonCastMessage("message");
message.remove("requestId");
assertTrue(mMessageHandler.sendJsonCastMessage(
message, NAMESPACE1, CLIENT_ID1, SEQUENCE_NUMBER1));
assertTrue(message.has("requestId"));
assertEquals(mMessageHandler.getRequestsForTest().size(), 1);
verify(mMessageHandler)
.sendStringCastMessage(
argThat(new JSONStringLike(message)), anyString(), anyString(), anyInt());
}
@Test
public void testOnMessageReceivedWithExistingRequestId() throws JSONException {
doNothing()
.when(mMessageHandler)
.onAppMessage(anyString(), anyString(), any(RequestRecord.class));
assertEquals(mMessageHandler.getRequestsForTest().size(), 0);
RequestRecord request = new RequestRecord(CLIENT_ID1, SEQUENCE_NUMBER1);
mMessageHandler.getRequestsForTest().append(REQUEST_ID1, request);
assertEquals(mMessageHandler.getRequestsForTest().size(), 1);
JSONObject message = new JSONObject();
message.put("requestId", REQUEST_ID1);
mMessageHandler.onMessageReceived(NAMESPACE1, message.toString());
assertEquals(mMessageHandler.getRequestsForTest().size(), 0);
verify(mMessageHandler).onAppMessage(eq(message.toString()), eq(NAMESPACE1), eq(request));
}
@Test
public void testOnMessageReceivedWithNonexistingRequestId() throws JSONException {
doNothing()
.when(mMessageHandler)
.onAppMessage(anyString(), anyString(), any(RequestRecord.class));
assertEquals(mMessageHandler.getRequestsForTest().size(), 0);
RequestRecord request = new RequestRecord(CLIENT_ID1, SEQUENCE_NUMBER1);
mMessageHandler.getRequestsForTest().append(REQUEST_ID1, request);
assertEquals(mMessageHandler.getRequestsForTest().size(), 1);
JSONObject message = new JSONObject();
message.put("requestId", REQUEST_ID2);
mMessageHandler.onMessageReceived(NAMESPACE1, message.toString());
assertEquals(mMessageHandler.getRequestsForTest().size(), 1);
verify(mMessageHandler)
.onAppMessage(eq(message.toString()), eq(NAMESPACE1), (RequestRecord) isNull());
}
@Test
public void testOnMessageReceivedWithoutRequestId() throws JSONException {
doNothing()
.when(mMessageHandler)
.onAppMessage(anyString(), anyString(), any(RequestRecord.class));
assertEquals(mMessageHandler.getRequestsForTest().size(), 0);
RequestRecord request = new RequestRecord(CLIENT_ID1, SEQUENCE_NUMBER1);
mMessageHandler.getRequestsForTest().append(REQUEST_ID1, request);
assertEquals(mMessageHandler.getRequestsForTest().size(), 1);
JSONObject message = new JSONObject();
mMessageHandler.onMessageReceived(NAMESPACE1, message.toString());
assertEquals(mMessageHandler.getRequestsForTest().size(), 1);
verify(mMessageHandler)
.onAppMessage(eq(message.toString()), eq(NAMESPACE1), (RequestRecord) isNull());
}
@Test
public void testOnMessageReceivedOfMediaNamespace() throws JSONException {
doNothing().when(mMessageHandler).onMediaMessage(anyString(), any(RequestRecord.class));
mMessageHandler.onMessageReceived(MEDIA_NAMESPACE, "anymessage");
verify(mMessageHandler).onMediaMessage(eq("anymessage"), (RequestRecord) isNull());
}
@Test
public void testOnMediaMessageOfMediaStatusTypeWithRequestRecord() {
doNothing()
.when(mMessageHandler)
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
doReturn(true).when(mMessageHandler).isMediaStatusMessage(anyString());
RequestRecord request = new RequestRecord(CLIENT_ID1, SEQUENCE_NUMBER1);
mMessageHandler.onMediaMessage("anymessage", request);
verify(mMessageHandler, never())
.sendEnclosedMessageToClient(eq(CLIENT_ID1), eq("v2_message"), eq("anymessage"),
eq(VOID_SEQUENCE_NUMBER));
verify(mMessageHandler)
.sendEnclosedMessageToClient(eq(CLIENT_ID2), eq("v2_message"), eq("anymessage"),
eq(VOID_SEQUENCE_NUMBER));
verify(mMessageHandler)
.sendEnclosedMessageToClient(
eq(CLIENT_ID1), eq("v2_message"), eq("anymessage"), eq(SEQUENCE_NUMBER1));
}
@Test
public void testOnMediaMessageOfMediaStatusTypeWithNullRequestRecord() {
doNothing()
.when(mMessageHandler)
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
doReturn(true).when(mMessageHandler).isMediaStatusMessage(anyString());
mMessageHandler.onMediaMessage("anymessage", null);
verify(mMessageHandler)
.sendEnclosedMessageToClient(eq(CLIENT_ID1), eq("v2_message"), eq("anymessage"),
eq(VOID_SEQUENCE_NUMBER));
verify(mMessageHandler)
.sendEnclosedMessageToClient(eq(CLIENT_ID2), eq("v2_message"), eq("anymessage"),
eq(VOID_SEQUENCE_NUMBER));
}
@Test
public void testOnMediaMessageOfNonMediaStatusTypeWithRequestRecord() {
doNothing()
.when(mMessageHandler)
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
doReturn(false).when(mMessageHandler).isMediaStatusMessage(anyString());
RequestRecord request = new RequestRecord(CLIENT_ID1, SEQUENCE_NUMBER1);
mMessageHandler.onMediaMessage("anymessage", request);
verify(mMessageHandler, never())
.sendEnclosedMessageToClient(
anyString(), anyString(), anyString(), eq(VOID_SEQUENCE_NUMBER));
verify(mMessageHandler)
.sendEnclosedMessageToClient(
eq(CLIENT_ID1), eq("v2_message"), eq("anymessage"), eq(SEQUENCE_NUMBER1));
}
@Test
public void testOnMediaMessageOfNonMediaStatusTypeWithNullRequestRecord() {
doNothing()
.when(mMessageHandler)
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
doReturn(false).when(mMessageHandler).isMediaStatusMessage(anyString());
mMessageHandler.onMediaMessage("anymessage", null);
verify(mMessageHandler, never())
.sendEnclosedMessageToClient(
anyString(), anyString(), anyString(), eq(VOID_SEQUENCE_NUMBER));
verify(mMessageHandler, never())
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
}
@Test
public void testOnAppMessageWithRequestRecord() throws JSONException {
doNothing()
.when(mMessageHandler)
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
RequestRecord request = new RequestRecord(CLIENT_ID1, SEQUENCE_NUMBER1);
mMessageHandler.onAppMessage("anyMessage", NAMESPACE1, request);
JSONObject expected = new JSONObject();
expected.put("sessionId", SESSION_ID);
expected.put("namespaceName", NAMESPACE1);
expected.put("message", "anyMessage");
verify(mMessageHandler)
.sendEnclosedMessageToClient(eq(CLIENT_ID1), eq("app_message"),
argThat(new JSONStringLike(expected)), eq(SEQUENCE_NUMBER1));
verify(mMessageHandler, never()).broadcastClientMessage(anyString(), anyString());
}
@Test
public void testOnAppMessageWithNullRequestRecord() throws JSONException {
doNothing().when(mMessageHandler).broadcastClientMessage(anyString(), anyString());
mMessageHandler.onAppMessage("anyMessage", NAMESPACE1, null);
JSONObject expected = new JSONObject();
expected.put("sessionId", SESSION_ID);
expected.put("namespaceName", NAMESPACE1);
expected.put("message", "anyMessage");
verify(mMessageHandler, never())
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
verify(mMessageHandler)
.broadcastClientMessage(eq("app_message"), argThat(new JSONStringLike(expected)));
}
@Test
public void testOnSessionEnded() {
doNothing()
.when(mMessageHandler)
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
assertEquals(0, mMessageHandler.getStopRequestsForTest().size());
mMessageHandler.getStopRequestsForTest().put(CLIENT_ID1, new ArrayDeque<Integer>());
mMessageHandler.getStopRequestsForTest().get(CLIENT_ID1).add(SEQUENCE_NUMBER1);
mMessageHandler.getStopRequestsForTest().get(CLIENT_ID1).add(SEQUENCE_NUMBER2);
assertEquals(1, mMessageHandler.getStopRequestsForTest().size());
assertEquals(2, mMessageHandler.getStopRequestsForTest().get(CLIENT_ID1).size());
mMessageHandler.onSessionEnded();
verify(mMessageHandler)
.sendEnclosedMessageToClient(
eq(CLIENT_ID1), eq("remove_session"), eq(SESSION_ID), eq(SEQUENCE_NUMBER1));
verify(mMessageHandler)
.sendEnclosedMessageToClient(
eq(CLIENT_ID1), eq("remove_session"), eq(SESSION_ID), eq(SEQUENCE_NUMBER2));
verify(mMessageHandler)
.sendEnclosedMessageToClient(eq(CLIENT_ID2), eq("remove_session"), eq(SESSION_ID),
eq(VOID_SEQUENCE_NUMBER));
}
@Test
public void testOnVolumeChanged() {
doNothing().when(mMessageHandler).onVolumeChanged(anyString(), anyInt());
assertEquals(0, mMessageHandler.getVolumeRequestsForTest().size());
mMessageHandler.getVolumeRequestsForTest().add(
new RequestRecord(CLIENT_ID1, SEQUENCE_NUMBER1));
assertEquals(1, mMessageHandler.getVolumeRequestsForTest().size());
mMessageHandler.onVolumeChanged();
verify(mMessageHandler).onVolumeChanged(CLIENT_ID1, SEQUENCE_NUMBER1);
assertEquals(0, mMessageHandler.getVolumeRequestsForTest().size());
}
@Test
public void testOnVolumeChangedWithEmptyVolumeRequests() {
mMessageHandler.onVolumeChanged();
verify(mMessageHandler, never()).onVolumeChanged(eq(CLIENT_ID1), eq(SEQUENCE_NUMBER1));
}
@Test
public void testOnVolumeChangedForClient() {
doNothing()
.when(mMessageHandler)
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
mMessageHandler.onVolumeChanged(CLIENT_ID1, SEQUENCE_NUMBER1);
verify(mMessageHandler)
.sendEnclosedMessageToClient(
eq(CLIENT_ID1), eq("v2_message"), (String) isNull(), eq(SEQUENCE_NUMBER1));
}
@Test
public void testOnAppMessageSent() {
Status mockResult = mock(Status.class);
doReturn(true).when(mockResult).isSuccess();
doNothing()
.when(mMessageHandler)
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
mMessageHandler.onSendAppMessageResult(mockResult, CLIENT_ID1, SEQUENCE_NUMBER1);
verify(mMessageHandler)
.sendEnclosedMessageToClient(
eq(CLIENT_ID1), eq("app_message"), (String) isNull(), eq(SEQUENCE_NUMBER1));
}
@Test
public void testSendEnclosedMessageToClient() throws JSONException {
String message = "dontcare_message1";
doReturn(message)
.when(mMessageHandler)
.buildEnclosedClientMessage(anyString(), anyString(), anyString(), anyInt());
mMessageHandler.sendEnclosedMessageToClient(
CLIENT_ID1, "anytype", "dontcare_message2", SEQUENCE_NUMBER1);
verify(mRouteProvider).sendMessageToClient(eq(CLIENT_ID1), eq(message));
}
@Test
public void testBroadcastClientMessage() {
doNothing()
.when(mMessageHandler)
.sendEnclosedMessageToClient(anyString(), anyString(), anyString(), anyInt());
mMessageHandler.broadcastClientMessage("anytype", "anymessage");
for (String clientId : mRouteProvider.getClientIdToRecords().keySet()) {
verify(mMessageHandler)
.sendEnclosedMessageToClient(eq(clientId), eq("anytype"), eq("anymessage"),
eq(VOID_SEQUENCE_NUMBER));
}
}
@Test
public void testSendReceiverActionToClient() throws JSONException {
MediaSink sink = mock(MediaSink.class);
doReturn("sink-id").when(sink).getId();
doReturn("sink-name").when(sink).getName();
doReturn(Arrays.asList("audio_in", "audio_out", "video_in", "video_out"))
.when(mSessionController)
.getCapabilities();
mMessageHandler.sendReceiverActionToClient("route-id", sink, "client-id", "action");
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
verify(mRouteProvider).sendMessageToClient(eq("client-id"), messageCaptor.capture());
JSONObject capturedMessage = new JSONObject(messageCaptor.getValue());
assertEquals(capturedMessage.getString("type"), "receiver_action");
assertEquals(capturedMessage.getInt("sequenceNumber"), VOID_SEQUENCE_NUMBER);
assertEquals(capturedMessage.getInt("timeoutMillis"), 0);
assertEquals(capturedMessage.getString("clientId"), "client-id");
JSONObject receiverAction = capturedMessage.getJSONObject("message");
assertEquals(receiverAction.getString("action"), "action");
JSONObject receiverInfo = receiverAction.getJSONObject("receiver");
assertEquals(receiverInfo.getString("label"), "sink-id");
assertEquals(receiverInfo.getString("friendlyName"), "sink-name");
assertFalse(receiverInfo.has("volume"));
assertFalse(receiverInfo.has("isActiveInput"));
assertFalse(receiverInfo.has("displayStatus"));
assertEquals(receiverInfo.getString("receiverType"), "cast");
JSONArray capabilities = receiverInfo.getJSONArray("capabilities");
assertEquals(capabilities.getString(0), "audio_in");
assertEquals(capabilities.getString(1), "audio_out");
assertEquals(capabilities.getString(2), "video_in");
assertEquals(capabilities.getString(3), "video_out");
}
@Test
public void testBuildEnclosedClientMessageWithNullMessage() throws JSONException {
String message = mMessageHandler.buildEnclosedClientMessage(
"anytype", null, CLIENT_ID1, SEQUENCE_NUMBER1);
JSONObject expected = new JSONObject();
expected.put("type", "anytype");
expected.put("sequenceNumber", SEQUENCE_NUMBER1);
expected.put("timeoutMillis", 0);
expected.put("clientId", CLIENT_ID1);
expected.put("message", null);
assertTrue("\nexpected: " + expected.toString() + ",\n actual: " + message.toString(),
new JSONObjectLike(expected).matches(new JSONObject(message)));
}
@Test
public void testBuildEnclosedClientMessageOfRemoveSessionType() throws JSONException {
String message = mMessageHandler.buildEnclosedClientMessage(
"remove_session", SESSION_ID, CLIENT_ID1, SEQUENCE_NUMBER1);
JSONObject expected = new JSONObject();
expected.put("type", "remove_session");
expected.put("sequenceNumber", SEQUENCE_NUMBER1);
expected.put("timeoutMillis", 0);
expected.put("clientId", CLIENT_ID1);
expected.put("message", SESSION_ID);
assertTrue("\nexpected: " + expected.toString() + ",\n actual: " + message.toString(),
new JSONObjectLike(expected).matches(new JSONObject(message)));
}
@Test
public void testBuildEnclosedClientMessageOfDisconnectSessionType() throws JSONException {
String message = mMessageHandler.buildEnclosedClientMessage(
"disconnect_session", SESSION_ID, CLIENT_ID1, SEQUENCE_NUMBER1);
JSONObject expected = new JSONObject();
expected.put("type", "disconnect_session");
expected.put("sequenceNumber", SEQUENCE_NUMBER1);
expected.put("timeoutMillis", 0);
expected.put("clientId", CLIENT_ID1);
expected.put("message", SESSION_ID);
assertTrue("\nexpected: " + expected.toString() + ",\n actual: " + message.toString(),
new JSONObjectLike(expected).matches(new JSONObject(message)));
}
@Test
public void testBuildEnclosedClientMessageWithInnerMessage() throws JSONException {
JSONObject innerMessage = buildSessionMessage(SESSION_ID);
String message = mMessageHandler.buildEnclosedClientMessage(
"anytype", innerMessage.toString(), CLIENT_ID1, SEQUENCE_NUMBER1);
JSONObject expected = new JSONObject();
expected.put("type", "anytype");
expected.put("sequenceNumber", SEQUENCE_NUMBER1);
expected.put("timeoutMillis", 0);
expected.put("clientId", CLIENT_ID1);
expected.put("message", innerMessage);
assertTrue("\nexpected: " + expected.toString() + ",\n actual: " + message.toString(),
new JSONObjectLike(expected).matches(new JSONObject(message)));
}
@Test
public void testBuildSessionMessage() throws JSONException {
CastDevice castDevice = mock(CastDevice.class);
doReturn("device-id").when(castDevice).getDeviceId();
doReturn("CastDevice friendly name").when(castDevice).getFriendlyName();
doReturn(castDevice).when(mSession).getCastDevice();
ApplicationMetadata appMetadata = mock(ApplicationMetadata.class);
doReturn("app-id").when(appMetadata).getApplicationId();
doReturn(appMetadata).when(mSession).getApplicationMetadata();
doReturn(1.0).when(mSession).getVolume();
doReturn(false).when(mSession).isMute();
doReturn("status text").when(mSession).getApplicationStatus();
doReturn(1).when(mSession).getActiveInputState();
doReturn(Arrays.asList("namespace-1", "namespace-2"))
.when(mSessionController)
.getNamespaces();
doReturn(Arrays.asList("audio_in", "audio_out", "video_in", "video_out"))
.when(mSessionController)
.getCapabilities();
JSONObject message = new JSONObject(mMessageHandler.buildSessionMessage());
assertEquals(message.getString("sessionId"), SESSION_ID);
assertEquals(message.getString("statusText"), "status text");
assertEquals(message.getString("status"), "connected");
assertEquals(message.getString("transportId"), "web-4");
assertEquals(message.getString("appId"), "app-id");
assertEquals(message.getString("displayName"), "CastDevice friendly name");
JSONArray mediaArray = message.getJSONArray("media");
assertEquals(mediaArray.length(), 0);
JSONArray namespacesArray = message.getJSONArray("namespaces");
assertEquals(namespacesArray.length(), 2);
assertEquals(namespacesArray.getJSONObject(0).getString("name"), "namespace-1");
assertEquals(namespacesArray.getJSONObject(1).getString("name"), "namespace-2");
JSONObject receiverInfo = message.getJSONObject("receiver");
assertEquals(receiverInfo.getString("label"), "device-id");
assertEquals(receiverInfo.getString("friendlyName"), "CastDevice friendly name");
assertEquals(receiverInfo.getInt("isActiveInput"), 1);
assertEquals(receiverInfo.getString("receiverType"), "cast");
assertFalse(receiverInfo.has("displayStatus"));
JSONArray capabilities = receiverInfo.getJSONArray("capabilities");
assertEquals(capabilities.getString(0), "audio_in");
assertEquals(capabilities.getString(1), "audio_out");
assertEquals(capabilities.getString(2), "video_in");
assertEquals(capabilities.getString(3), "video_out");
JSONObject volume = receiverInfo.getJSONObject("volume");
assertEquals(volume.getDouble("level"), 1.0, 1e-6);
assertFalse(volume.getBoolean("muted"));
}
@Test
public void testBuildSessionMessage_sessionDisconnected() {
doReturn(false).when(mSessionController).isConnected();
CastDevice castDevice = mock(CastDevice.class);
doReturn("device-id").when(castDevice).getDeviceId();
doReturn("CastDevice friendly name").when(castDevice).getFriendlyName();
doReturn(castDevice).when(mSession).getCastDevice();
ApplicationMetadata appMetadata = mock(ApplicationMetadata.class);
doReturn("app-id").when(appMetadata).getApplicationId();
doReturn(appMetadata).when(mSession).getApplicationMetadata();
doReturn(1.0).when(mSession).getVolume();
doReturn(false).when(mSession).isMute();
doReturn("status text").when(mSession).getApplicationStatus();
doReturn(1).when(mSession).getActiveInputState();
doReturn(Arrays.asList("namespace-1", "namespace-2"))
.when(mSessionController)
.getNamespaces();
doReturn(Arrays.asList("audio_in", "audio_out", "video_in", "video_out"))
.when(mSessionController)
.getCapabilities();
assertEquals(mMessageHandler.buildSessionMessage(), "{}");
}
private JSONObject buildCastV2Message(String clientId, JSONObject innerMessage)
throws JSONException {
JSONObject message = new JSONObject();
message.put("type", "v2_message");
message.put("message", innerMessage);
message.put("sequenceNumber", SEQUENCE_NUMBER1);
message.put("timeoutMillis", 0);
message.put("clientId", clientId);
return message;
}
private JSONObject buildAppMessage(String clientId, String namespace, Object actualMessage)
throws JSONException {
JSONObject innerMessage = new JSONObject();
innerMessage.put("sessionId", mSessionController.getSessionId());
innerMessage.put("namespaceName", namespace);
innerMessage.put("message", actualMessage);
JSONObject message = new JSONObject();
message.put("type", "app_message");
message.put("message", innerMessage);
message.put("sequenceNumber", SEQUENCE_NUMBER1);
message.put("timeoutMillis", 0);
message.put("clientId", clientId);
return message;
}
private JSONObject buildActualAppMessage() throws JSONException {
JSONObject message = new JSONObject();
message.put("type", "actual app message type");
return message;
}
private JSONObject buildSessionMessage(String sessionId) throws JSONException {
JSONObject message = new JSONObject();
message.put("sessionId", sessionId);
return message;
}
private void expectException(CheckedRunnable r, Class exceptionClass) {
boolean caughtException = false;
try {
r.run();
} catch (Exception e) {
if (e.getClass() == exceptionClass) caughtException = true;
}
assertTrue(caughtException);
}
private JSONObject buildJsonCastMessage(String message) throws JSONException {
JSONObject jsonMessage = new JSONObject();
jsonMessage.put("requestId", REQUEST_ID1);
jsonMessage.put("message", message);
return jsonMessage;
}
private void verifySimpleSessionMessage(JSONObject message, String type, int sequenceNumber,
String clientId) throws JSONException {
assertEquals(message.getString("type"), type);
assertEquals(message.getInt("sequenceNumber"), sequenceNumber);
assertEquals(message.getInt("timeoutMillis"), 0);
assertEquals(message.getInt("sequenceNumber"), sequenceNumber);
}
private void prepareClientRecord(String routeId, String clientId, String appId,
String autoJoinPolicy, String origin, int tabId) {
ClientRecord clientRecord =
new ClientRecord(routeId, clientId, appId, autoJoinPolicy, origin, tabId);
mClientRecordMap.put(clientId, clientRecord);
}
private JSONObject buildLeaveSessionMessage(
String clientId, String sessionId, int sequenceNumber) throws JSONException {
JSONObject message = new JSONObject();
message.put("type", "leave_session");
message.put("clientId", clientId);
message.put("message", sessionId);
message.put("sequenceNumber", sequenceNumber);
return message;
}
}
...@@ -36,9 +36,9 @@ import org.chromium.base.test.BaseRobolectricTestRunner; ...@@ -36,9 +36,9 @@ import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.media.router.CastSessionUtil; import org.chromium.chrome.browser.media.router.CastSessionUtil;
import org.chromium.chrome.browser.media.router.ClientRecord; import org.chromium.chrome.browser.media.router.ClientRecord;
import org.chromium.chrome.browser.media.router.JSONTestUtils.JSONObjectLike;
import org.chromium.chrome.browser.media.router.JSONTestUtils.JSONStringLike;
import org.chromium.chrome.browser.media.router.cast.CastMessageHandler.RequestRecord; import org.chromium.chrome.browser.media.router.cast.CastMessageHandler.RequestRecord;
import org.chromium.chrome.browser.media.router.cast.JSONTestUtils.JSONObjectLike;
import org.chromium.chrome.browser.media.router.cast.JSONTestUtils.JSONStringLike;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.HashMap; import java.util.HashMap;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment