blob: e76e1ea5d0447307904313fbb1678b5fee0ed9d5 [file] [log] [blame]
// 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;
}
}