/* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0/ * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ /// @file ExternalMediaPlayerTest.cpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ExternalMediaPlayer/ExternalMediaPlayer.h" namespace alexaClientSDK { namespace capabilityAgents { namespace externalMediaPlayer { namespace test { using namespace avsCommon::utils; using namespace avsCommon::utils::json::jsonUtils; using namespace avsCommon; using namespace avsCommon::avs; using namespace avsCommon::avs::attachment; using namespace avsCommon::sdkInterfaces; using namespace avsCommon::sdkInterfaces::externalMediaPlayer; using namespace avsCommon::sdkInterfaces::test; using namespace avsCommon::utils::mediaPlayer; using namespace avsCommon::utils::memory; using namespace avsCommon::utils::mediaPlayer::test; using namespace avsCommon::utils::metrics::test; using namespace capabilityAgents::externalMediaPlayer; using namespace ::testing; using namespace rapidjson; /// Provide State Token for testing. static const unsigned int PROVIDE_STATE_TOKEN_TEST{1}; /// Plenty of time for a test to complete. static std::chrono::milliseconds MY_WAIT_TIMEOUT(1000); // The namespaces used in the context. static const std::string EXTERNALMEDIAPLAYER_STATE_NAMESPACE = "ExternalMediaPlayer"; static const std::string PLAYBACKSTATEREPORTER_STATE_NAMESPACE = "Alexa.PlaybackStateReporter"; // The names used in the context. static const std::string EXTERNALMEDIAPLAYER_NAME = "ExternalMediaPlayerState"; static const std::string PLAYBACKSTATEREPORTER_NAME = "playbackState"; static const std::string EXTERNALMEDIAPLAYER_NAMESPACE = "ExternalMediaPlayer"; static const std::string PLAYBACKCONTROLLER_NAMESPACE = "Alexa.PlaybackController"; static const std::string PLAYLISTCONTROLLER_NAMESPACE = "Alexa.PlaylistController"; static const std::string SEEKCONTROLLER_NAMESPACE = "Alexa.SeekController"; static const std::string FAVORITESCONTROLLER_NAMESPACE = "Alexa.FavoritesController"; // field values used in Adapter State response static const std::string PLAYER_USER_NAME = "userName"; static const std::string PLAYER_ID = "testPlayerId"; static const std::string PLAYER_TRACK = "testTrack"; static const std::string PLAYER_STATE = "IDLE"; // The @c External media player play directive signature. static const NamespaceAndName PLAY_DIRECTIVE{EXTERNALMEDIAPLAYER_NAMESPACE, "Play"}; static const NamespaceAndName LOGIN_DIRECTIVE{EXTERNALMEDIAPLAYER_NAMESPACE, "Login"}; static const NamespaceAndName LOGOUT_DIRECTIVE{EXTERNALMEDIAPLAYER_NAMESPACE, "Logout"}; static const NamespaceAndName AUTHORIZEDISCOVEREDPLAYERS_DIRECTIVE{EXTERNALMEDIAPLAYER_NAMESPACE, "AuthorizeDiscoveredPlayers"}; // The @c Transport control directive signatures. static const NamespaceAndName RESUME_DIRECTIVE{PLAYBACKCONTROLLER_NAMESPACE, "Play"}; static const NamespaceAndName PAUSE_DIRECTIVE{PLAYBACKCONTROLLER_NAMESPACE, "Pause"}; static const NamespaceAndName STOP_DIRECTIVE{PLAYBACKCONTROLLER_NAMESPACE, "Stop"}; static const NamespaceAndName NEXT_DIRECTIVE{PLAYBACKCONTROLLER_NAMESPACE, "Next"}; static const NamespaceAndName PREVIOUS_DIRECTIVE{PLAYBACKCONTROLLER_NAMESPACE, "Previous"}; static const NamespaceAndName STARTOVER_DIRECTIVE{PLAYBACKCONTROLLER_NAMESPACE, "StartOver"}; static const NamespaceAndName REWIND_DIRECTIVE{PLAYBACKCONTROLLER_NAMESPACE, "Rewind"}; static const NamespaceAndName FASTFORWARD_DIRECTIVE{PLAYBACKCONTROLLER_NAMESPACE, "FastForward"}; // The @c PlayList control directive signature. static const NamespaceAndName ENABLEREPEATONE_DIRECTIVE{PLAYLISTCONTROLLER_NAMESPACE, "EnableRepeatOne"}; static const NamespaceAndName ENABLEREPEAT_DIRECTIVE{PLAYLISTCONTROLLER_NAMESPACE, "EnableRepeat"}; static const NamespaceAndName DISABLEREPEAT_DIRECTIVE{PLAYLISTCONTROLLER_NAMESPACE, "DisableRepeat"}; static const NamespaceAndName ENABLESHUFFLE_DIRECTIVE{PLAYLISTCONTROLLER_NAMESPACE, "EnableShuffle"}; static const NamespaceAndName DISABLESHUFFLE_DIRECTIVE{PLAYLISTCONTROLLER_NAMESPACE, "DisableShuffle"}; // The @c Seek control directive signature. static const NamespaceAndName SEEK_DIRECTIVE{SEEKCONTROLLER_NAMESPACE, "SetSeekPosition"}; static const NamespaceAndName ADJUSTSEEK_DIRECTIVE{SEEKCONTROLLER_NAMESPACE, "AdjustSeekPosition"}; // The @c favorites control directive signature. static const NamespaceAndName FAVORITE_DIRECTIVE{FAVORITESCONTROLLER_NAMESPACE, "Favorite"}; static const NamespaceAndName UNFAVORITE_DIRECTIVE{FAVORITESCONTROLLER_NAMESPACE, "Unfavorite"}; // The @c ExternalMediaPlayer context state signatures. static const NamespaceAndName SESSION_STATE{EXTERNALMEDIAPLAYER_STATE_NAMESPACE, EXTERNALMEDIAPLAYER_NAME}; static const NamespaceAndName PLAYBACK_STATE{PLAYBACKSTATEREPORTER_STATE_NAMESPACE, PLAYBACKSTATEREPORTER_NAME}; // @c ExternalMediaPlayer events. static const NamespaceAndName REPORT_DISCOVERED_PLAYERS{EXTERNALMEDIAPLAYER_NAMESPACE, "ReportDiscoveredPlayers"}; static const NamespaceAndName AUTHORIZATION_COMPLETE{EXTERNALMEDIAPLAYER_NAMESPACE, "AuthorizationComplete"}; // A playRequestor for testing static const PlayRequestor testPlayRequestor{.type = "ALERT", .id = "123"}; // clang-format off static const std::string IDLE_PLAYBACK_STATE = R"({ "state":"IDLE", "supportedOperations":[], "shuffle":"NOT_SHUFFLED", "repeat":"NOT_REPEATED", "favorite":"NOT_RATED", "positionMilliseconds":0, "players":[{ "playerId":"", "state":"IDLE", "supportedOperations":[], "positionMilliseconds":0, "shuffle":"NOT_SHUFFLED", "repeat":"NOT_REPEATED", "favorite":"NOT_RATED", "media":{ "type":"", "value":{ "playbackSource":"", "playbackSourceId":"", "trackName":"", "trackId":"", "trackNumber":"", "artist":"", "artistId":"", "album":"", "albumId":"", "coverUrls":{"tiny":"","small":"","medium":"","large":""}, "coverId":"", "mediaProvider":"", "mediaType":"TRACK", "durationInMilliseconds":0 } } }] })"; // clang-format on /** * Method to create an adapter state struct response to getState(); * * @return an adpater state partially filled with test values */ static AdapterState createAdapterState() { AdapterSessionState sessionState; sessionState.loggedIn = false; sessionState.userName = PLAYER_USER_NAME; sessionState.playerId = PLAYER_ID; AdapterPlaybackState playbackState; playbackState.state = PLAYER_STATE; playbackState.trackName = PLAYER_TRACK; playbackState.playRequestor = testPlayRequestor; AdapterState adapterState; adapterState.sessionState = sessionState; adapterState.playbackState = playbackState; return adapterState; } /// Message Id for testing. static const std::string MESSAGE_ID_TEST("MessageId_Test"); static const std::string MESSAGE_ID_TEST2("MessageId_Test2"); /// Dialog Request Id for testing. static const std::string DIALOG_REQUEST_ID_TEST("DialogId_Test"); /// String to identify log entries originating from this file. static const std::string TAG("ExternalMediaPlayerTest"); /// Music service provider id 1. static const std::string MSP1_LOCAL_PLAYER_ID("MSP1_LOCAL_PLAYER_ID"); /// Cloud assigned playerId for this MSP. static const std::string MSP1_PLAYER_ID("MSP1_PLAYERID"); /// Associated skillToken for this MSP. static const std::string MSP1_SKILLTOKEN("MSP1_SKILLTOKEN"); /// Music service provider id 2. static const std::string MSP2_LOCAL_PLAYER_ID("MSP2_LOCAL_PLAYER_ID"); /// Cloud assigned playerId for this MSP. static const std::string MSP2_PLAYER_ID("MSP2_PLAYERID"); /// Associated skillToken for this MSP. static const std::string MSP2_SKILLTOKEN("MSP2_SKILLTOKEN"); /** * Create a LogEntry using this file's TAG and the specified event string. * * @param The event string for this @c LogEntry. */ #define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event) /// Mock class of ExternalMediaAdapterInterface. class MockExternalMediaPlayerAdapter : public ExternalMediaAdapterInterface { public: /* * Method that adheres to the AdapterCreateFunc interface to create an adapter. This method create a mock * instances and assigns it to a class static to keep the mock class simple. * * @param metricRecorder The metricRecorder instance to be used to record metrics * @param mediaPlayer The mediaPlayer instance to be used to play Spotify content. * @param speakerManager A @c SpeakerManagerInterface to perform volume changes requested by ESDK. * @param messageSender The object to use for sending events. * @param focusManager The focusManager used to acquire/release channel. * @param contextManager The AVS Context manager used to generate system context for events. * @param externalMediaPlayer The instance of the @c ExternalMediaPlayer managing the adapter. * @return A @c std::shared_ptr to the new @c ExternalMediaAdapter instance. */ static std::shared_ptr getInstance( std::shared_ptr metricRecorder, std::shared_ptr mediaPlayer, std::shared_ptr speaker, std::shared_ptr speakerManager, std::shared_ptr messageSender, std::shared_ptr focusManager, std::shared_ptr contextManager, std::shared_ptr externalMediaPlayer); static std::shared_ptr m_currentActiveMediaPlayerAdapter; MOCK_METHOD0(doShutdown, void()); MOCK_METHOD0(init, void()); MOCK_METHOD0(deInit, void()); MOCK_METHOD4( handleLogin, void( const std::string& accessToken, const std::string& userName, bool forceLogin, std::chrono::milliseconds tokenRefreshInterval)); MOCK_METHOD0(handleLogout, void()); MOCK_METHOD8( handlePlay, void( std::string& playContextToken, int64_t index, std::chrono::milliseconds offset, const std::string& skillToken, const std::string& playbackSessionId, const std::string& navigation, bool preload, const avsCommon::avs::PlayRequestor& playRequestor)); MOCK_METHOD1(handlePlayControl, void(RequestType requestType)); MOCK_METHOD1(handleSeek, void(std::chrono::milliseconds offset)); MOCK_METHOD1(handleAdjustSeek, void(std::chrono::milliseconds deltaOffset)); MOCK_METHOD3( handleAuthorized, void(bool authorized, const std::string& playerId, const std::string& defaultSkillToken)); MOCK_METHOD1(handleSetVolume, void(int8_t volume)); MOCK_METHOD1(handleSetMute, void(bool)); MOCK_METHOD0(getState, AdapterState()); MOCK_METHOD0(getOffset, std::chrono::milliseconds()); private: /// MockExternalMediaPlayerAdapter private constructor. MockExternalMediaPlayerAdapter(); }; /// Static instance of MockMediaPlayerAdapter. std::shared_ptr MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter; MockExternalMediaPlayerAdapter::MockExternalMediaPlayerAdapter() : RequiresShutdown("MockExternalMediaPlayerAdapter"), ExternalMediaAdapterInterface("MockExternalMediaPlayerAdapter") { } std::shared_ptr MockExternalMediaPlayerAdapter::getInstance( std::shared_ptr metricRecorder, std::shared_ptr mediaPlayer, std::shared_ptr speaker, std::shared_ptr speakerManager, std::shared_ptr messageSender, std::shared_ptr focusManager, std::shared_ptr contextManager, std::shared_ptr externalMediaPlayer) { MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter = std::shared_ptr(new MockExternalMediaPlayerAdapter()); return MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter; } class MockExternalMediaPlayerObserver : public ExternalMediaPlayerObserverInterface { public: static std::shared_ptr getInstance(); MOCK_METHOD2( onLoginStateProvided, void(const std::string&, const avsCommon::sdkInterfaces::externalMediaPlayer::ObservableSessionProperties)); MOCK_METHOD2( onPlaybackStateProvided, void( const std::string&, const avsCommon::sdkInterfaces::externalMediaPlayer::ObservablePlaybackStateProperties)); private: /** * Constructor */ MockExternalMediaPlayerObserver(); }; std::shared_ptr MockExternalMediaPlayerObserver::getInstance() { return std::shared_ptr(new MockExternalMediaPlayerObserver()); } MockExternalMediaPlayerObserver::MockExternalMediaPlayerObserver() { } /** * Method to create AuthorizeDiscoveredPlayers payload. * * @param players A set of players JSON objects. * * @return A string representation of the payload. */ static std::string createAuthorizeDiscoveredPlayersPayload( std::unordered_set players = std::unordered_set()) { // clang-format off std::string payload = R"( { "players" : [ )"; for (auto it = players.begin(); it != players.end(); it++) { if (it != players.begin()) { payload += ","; } payload += *it; } payload += R"(]})"; // clang-format on return payload; } /** * Create the players json object. * * @param localPlayerId The localPlayerId. * @param authorized Whether the player is authorized. * @param playerId The cloud assigned playerId. * @param skillToken The skillToken. * * @return A string representation of the payload. */ static std::string createPlayerJson( const std::string& localPlayerId, bool authorized, const std::string& playerId, const std::string& skillToken) { // clang-format off return R"({ "localPlayerId" : ")" + localPlayerId + R"(", "authorized" : )" + (authorized ? "true" : "false") + R"(, "metadata" : { "playerId" : ")" + playerId + R"(", "skillToken" : ")" + skillToken + R"(" } })"; // clang-format on } /** * Get idle session state json object * * @return A string representation of idle session state json object */ static std::string getIdleSessionStateJson(std::string agent) { // clang-format off std::string idle_session_state = R"({ "agent":")" + std::string(agent) + R"(", "spiVersion":")" + std::string(ExternalMediaPlayer::SPI_VERSION) + R"(", "playerInFocus":"", "players":[{ "playerId":"", "endpointId":"", "loggedIn":false, "username":"", "isGuest":false, "launched":false, "active":false, "spiVersion":"", "playerCookie":"", "skillToken":"", "playbackSessionId":"" }] })"; // clang-format on return idle_session_state; } /** * Method to create payload with parse error. * * @param playContext Play context {Track/playlist/album/artist/station/podcast} identifier. * @param index The index of the media item in the container, if the container is indexable. * @param offsetInMilliseconds The offset position within media item, in milliseconds. * @param playerId The business name of the player. * @return A string representation of the payload. */ static std::string createPlayPayloadWithParseError( const std::string& playContext, int index, int64_t offsetInMilliseconds, const std::string& playerId, const std::string& skillToken, const std::string& playbackSessionId, const std::string& navigation, bool preload) { // clang-format off const std::string PLAY_PAYLOAD_TEST = "{" "\"playbackContextToken\":\"" + playContext + "\"," "\"offsetInMilliseconds\":" + std::to_string(offsetInMilliseconds) + "\"," "\"playerId\":\"" + playerId + "\"," "\"index\":\"" + std::to_string(index) + "\"," "\"skillToken\":\"" + skillToken + "\"," "\"playbackSessionId\":\"" + playbackSessionId + "\"," "\"navigation\":\"" + navigation + "\"," "\"preload\":" + (preload ? "true" : "false") + "" "}"; // clang-format on return PLAY_PAYLOAD_TEST; } /** * Method to create payload with only playerId. * * @param playerId The business name of the player. * @return A string representation of the payload. */ static std::string createPayloadWithPlayerId(const std::string& playerId) { // clang-format off const std::string PLAYERID_PAYLOAD_TEST = "{" "\"playerId\":\"" + playerId + "\"" "}"; // clang-format on return PLAYERID_PAYLOAD_TEST; } /** * Method to create a Play payload with playContext, index, offsetInMilliseconds, playerId. * * @param playContext Play context {Track/playlist/album/artist/station/podcast} identifier. * @param index The index of the media item in the container, if the container is indexable. * @param offsetInMilliseconds The offset position within media item, in milliseconds. * @param playerId The business name of the player. * @return A string representation of the payload. */ static std::string createPlayPayload( const std::string& playContext, int index, int64_t offsetInMilliseconds, const std::string& playerId, const std::string& skillToken, const std::string& playbackSessionId, const std::string& navigation, bool preload) { // clang-format off const std::string PLAY_PAYLOAD_TEST = "{" "\"playbackContextToken\":\"" + playContext + "\"," "\"offsetInMilliseconds\":\"" + std::to_string(offsetInMilliseconds) + "\"," "\"playerId\":\"" + playerId + "\"," "\"index\":\"" + std::to_string(index) + "\"," "\"skillToken\":\"" + skillToken + "\"," "\"playbackSessionId\":\"" + playbackSessionId + "\"," "\"navigation\":\"" + navigation + "\"," "\"preload\":" + (preload ? "true" : "false") + "" "}"; // clang-format on return PLAY_PAYLOAD_TEST; } /** * Method to create a Play payload with playContext, index, offsetInMilliseconds, playerId, and playRequestor. * * @param playContext Play context {Track/playlist/album/artist/station/podcast} identifier. * @param index The index of the media item in the container, if the container is indexable. * @param offsetInMilliseconds The offset position within media item, in milliseconds. * @param playerId The business name of the player. * @param skillToken The token identifying the domain or skill associated with this player. * @param playbackSessionId A UUID associated with the most recent @c Play directive. * @param navigation Communicates desired visual display behavior for the app associated with playback. * @param preload Indicates if @c Play directive is intended to preload the identified content only but not begin * playback. * @param playRequestor The playRequestor object of the @c play directive. * * @return A string representation of the payload. */ static std::string createPlayPayloadWithPlayRequestor( const std::string& playContext, int index, int64_t offsetInMilliseconds, const std::string& playerId, const std::string& skillToken, const std::string& playbackSessionId, const std::string& navigation, bool preload, const PlayRequestor& playRequestor) { // clang-format off const std::string PLAY_PAYLOAD_TEST = "{" "\"playbackContextToken\":\"" + playContext + "\"," "\"offsetInMilliseconds\":\"" + std::to_string(offsetInMilliseconds) + "\"," "\"playerId\":\"" + playerId + "\"," "\"index\":\"" + std::to_string(index) + "\"," "\"skillToken\":\"" + skillToken + "\"," "\"playbackSessionId\":\"" + playbackSessionId + "\"," "\"navigation\":\"" + navigation + "\"," "\"preload\":" + (preload ? "true" : "false") + "," "\"playRequestor\":{" "\"type\":\"" + playRequestor.type + "\"," "\"id\":\"" + playRequestor.id + "\"" "}" "}"; // clang-format on return PLAY_PAYLOAD_TEST; } /** * Method to create a Play payload with only index, offsetInMilliseconds, playerId. * * @param index The index of the media item in the container, if the container is indexable. * @param offsetInMilliseconds The offset position within media item, in milliseconds. * @param playerId The business name of the player. * @return A string representation of the payload. */ static std::string createPlayPayloadNoContext( int index, int64_t offsetInMilliseconds, const std::string& playerId, const std::string& skillToken, const std::string& playbackSessionId, const std::string& navigation, bool preload) { // clang-format off const std::string PLAY_PAYLOAD_TEST = "{" "\"offsetInMilliseconds\":\"" + std::to_string(offsetInMilliseconds) + "\"," "\"playerId\":\"" + playerId + "\"," "\"index\":\"" + std::to_string(index) + "\"," "\"skillToken\":\"" + skillToken + "\"," "\"playbackSessionId\":\"" + playbackSessionId + "\"," "\"navigation\":\"" + navigation + "\"," "\"preload\":" + (preload ? "true" : "false") + "" "}"; // clang-format on return PLAY_PAYLOAD_TEST; } /** * Method to create a Play payload with only playContext, index, offsetInMilliseconds. * * @param playContext Play context {Track/playlist/album/artist/station/podcast} identifier. * @param index The index of the media item in the container, if the container is indexable. * @param offsetInMilliseconds The offset position within media item, in milliseconds. * @return A string representation of the payload. */ static std::string createPlayPayloadNoPlayerId( const std::string& playContext, int index, int64_t offsetInMilliseconds, const std::string& skillToken, const std::string& playbackSessionId, const std::string& navigation, bool preload) { // clang-format off const std::string PLAY_PAYLOAD_TEST = "{" "\"playbackContextToken\":\"" + playContext + "\"," "\"offsetInMilliseconds\":\"" + std::to_string(offsetInMilliseconds) + "\"," "\"index\":\"" + std::to_string(index) + "\"," "\"skillToken\":\"" + skillToken + "\"," "\"playbackSessionId\":\"" + playbackSessionId + "\"," "\"navigation\":\"" + navigation + "\"," "\"preload\":" + (preload ? "true" : "false") + "" "}"; // clang-format on return PLAY_PAYLOAD_TEST; } /** * Method to create a Play payload with only playContext, offsetInMilliseconds and playerId. * * @param playContext Play context {Track/playlist/album/artist/station/podcast} identifier. * @param offsetInMilliseconds The offset position within media item, in milliseconds. * @param playerId The business name of the player. * @return A string representation of the payload. */ static std::string createPlayPayloadNoIndex( const std::string& playContext, int64_t offsetInMilliseconds, const std::string& playerId, const std::string& skillToken, const std::string& playbackSessionId, const std::string& navigation, bool preload) { // clang-format off const std::string PLAY_PAYLOAD_TEST = "{" "\"playbackContextToken\":\"" + playContext + "\"," "\"offsetInMilliseconds\":" + std::to_string(offsetInMilliseconds) + "," "\"playerId\":\"" + playerId + "\"," "\"skillToken\":\"" + skillToken + "\"," "\"playbackSessionId\":\"" + playbackSessionId + "\"," "\"navigation\":\"" + navigation + "\"," "\"preload\":" + (preload ? "true" : "false") + "" "}"; // clang-format on return PLAY_PAYLOAD_TEST; } /** * Method to create a Play payload with only playContext, index, playerId. * * @param playContext Play context {Track/playlist/album/artist/station/podcast} identifier. * @param index The index of the media item in the container, if the container is indexable. * @param playerId The business name of the player. * @return A string representation of the payload. */ static std::string createPlayPayloadNoOffset( const std::string& playContext, int index, const std::string& playerId, const std::string& skillToken, const std::string& playbackSessionId, const std::string& navigation, bool preload) { // clang-format off const std::string PLAY_PAYLOAD_TEST = "{" "\"playbackContextToken\":\"" + playContext + "\"," "\"playerId\":\"" + playerId + "\"," "\"index\":\"" + std::to_string(index) + "\"," "\"skillToken\":\"" + skillToken + "\"," "\"playbackSessionId\":\"" + playbackSessionId + "\"," "\"navigation\":\"" + navigation + "\"," "\"preload\":" + (preload ? "true" : "false") + "" "}"; // clang-format on return PLAY_PAYLOAD_TEST; } /** * Method to create a Login payload with accessToken, userName, refresh interval, forceLogin, playerId. * * @param accessToken The access context of the user identifier. * @param userName The userName of the user logging in. * @param refreshInterval The duration in milliseconds for which the accessToken is valid. * @param forceLogin bool which signifies if the adapter has to a force a login or merely cache the access token. * @param playerId The business name of the player. * @return A string representation of the payload. */ static std::string createLoginPayload( const std::string& accessToken, const std::string& userName, int64_t refreshInterval, bool forceLogin, const std::string& playerId) { // clang-format off const std::string LOGIN_PAYLOAD_TEST = "{" "\"playerId\":\"" + playerId + "\"," "\"accessToken\":\"" + accessToken + "\"," "\"tokenRefreshIntervalInMilliseconds\":" + std::to_string(refreshInterval) + "," "\"forceLogin\": true" + "," "\"username\":\"" + userName + "\"" "}"; // clang-format on return LOGIN_PAYLOAD_TEST; } /** * Method to create a Seek payload. * * @param timeOffset The offset to seek to. * @param playerId The business name of the player. * @param adjustSeek @c true offset adjusts seek relative to current position * @c false offset is interpreted as an absolute offset. * @return A string representation of the payload. */ static std::string createSeekPayload(int64_t timeOffset, const std::string& playerId, bool adjustSeek) { std::string SEEK_PAYLOAD_TEST; // clang-format off if (adjustSeek) { SEEK_PAYLOAD_TEST = "{\"playerId\":\"" + playerId + "\",\"deltaPositionMilliseconds\":" + std::to_string(timeOffset) + "}"; } else { SEEK_PAYLOAD_TEST = "{\"playerId\":\"" + playerId + "\",\"positionMilliseconds\":" + std::to_string(timeOffset) + "}"; } // clang-format on return SEEK_PAYLOAD_TEST; } class ExternalMediaPlayerTest : public ::testing::Test { public: ExternalMediaPlayerTest(); void SetUp() override; void TearDown() override; /** * Verify that the provided state matches the expected state * * @param jsonState The state to verify * @param expectedState The expected state */ void verifyState(const std::string& providedState, const std::string& expectedState); /** * Helper method to authorize a set of players. * * @param payload The payload for an AuthorizeDiscoveredPlayers directive. * @param resultHandler A result handler associated with the directive upon which expectations can be set. */ void sendAuthorizeDiscoveredPlayersDirective( const std::string& payload, std::unique_ptr resultHandler = nullptr); /** * This is invoked in response to a @c setState call. * * @return @c SUCCESS. */ SetStateResult wakeOnSetState(); /** * This is is invoked to clear the promise set by a setState call for repeat testing * * @return @c SUCCESS. */ SetStateResult resetWakeOnSetState(); /// The map of adapters to @c MediaPlayerInterface. ExternalMediaPlayer::AdapterMediaPlayerMap m_adapterMediaPlayerMap; /// The map of adapters to @c SpeakerInterface. ExternalMediaPlayer::AdapterSpeakerMap m_adapterSpeakerMap; /// The map of adapter creation functions. ExternalMediaPlayer::AdapterCreationMap m_adapterMap; /// @c ExternalMediaPlayer to test std::shared_ptr m_externalMediaPlayer; /// Player to send the audio to. std::shared_ptr m_mockMediaPlayer; /// @c SpeakerInterface to manage volume changes of individual speakers. std::shared_ptr m_mockSpeakerInterface; /// @c SpeakerManager to manage volume changes across speakers. std::shared_ptr m_mockSpeakerManager; /// @c MetricRecorder to send metrics std::shared_ptr m_metricRecorder; /// @c ContextManager to provide state and update state. std::shared_ptr m_mockContextManager; /// @c FocusManager to request focus to the DIALOG channel. std::shared_ptr m_mockFocusManager; /// A directive handler result to send the result to. std::unique_ptr m_mockDirectiveHandlerResult; /// A message sender used to send events to AVS. std::shared_ptr m_mockMessageSender; std::shared_ptr m_mockCertifiedSender; /// An exception sender used to send exception encountered events to AVS. std::shared_ptr m_mockExceptionSender; /// A playback router to notify when @c ExternalMediaPlayer becomes active. std::shared_ptr m_mockPlaybackRouter; /// Attachment manager used to create a reader. std::shared_ptr m_attachmentManager; /// Promise to be fulfilled when @c setState is called. std::promise m_wakeSetStatePromise; /// Future to notify when @c setState is called. std::future m_wakeSetStateFuture; }; ExternalMediaPlayerTest::ExternalMediaPlayerTest() : m_wakeSetStatePromise{}, m_wakeSetStateFuture{m_wakeSetStatePromise.get_future()} { } void ExternalMediaPlayerTest::SetUp() { m_mockSpeakerInterface = std::make_shared>(); m_mockSpeakerManager = std::make_shared>(); m_metricRecorder = std::make_shared>(); m_mockMessageSender = std::make_shared>(); m_mockFocusManager = std::make_shared>(); m_mockContextManager = std::make_shared>(); m_mockExceptionSender = std::make_shared>(); m_mockMediaPlayer = MockMediaPlayer::create(); m_mockPlaybackRouter = std::make_shared>(); m_attachmentManager = std::make_shared(AttachmentManager::AttachmentType::IN_PROCESS); m_mockCertifiedSender = std::make_shared(); m_adapterMediaPlayerMap.insert(std::make_pair(MSP1_LOCAL_PLAYER_ID, m_mockMediaPlayer)); m_adapterSpeakerMap.insert(std::make_pair(MSP1_LOCAL_PLAYER_ID, m_mockSpeakerInterface)); m_adapterMap.insert(std::make_pair(MSP1_LOCAL_PLAYER_ID, &MockExternalMediaPlayerAdapter::getInstance)); m_externalMediaPlayer = ExternalMediaPlayer::create( m_adapterMediaPlayerMap, m_adapterSpeakerMap, m_adapterMap, m_mockSpeakerManager, m_mockMessageSender, m_mockCertifiedSender->get(), m_mockFocusManager, m_mockContextManager, m_mockExceptionSender, m_mockPlaybackRouter, m_metricRecorder); m_mockDirectiveHandlerResult = std::unique_ptr(new MockDirectiveHandlerResult); ASSERT_TRUE(m_externalMediaPlayer); // Authorize Players. const std::string playersJson = createPlayerJson(MSP1_LOCAL_PLAYER_ID, true, MSP1_PLAYER_ID, MSP1_SKILLTOKEN); sendAuthorizeDiscoveredPlayersDirective(createAuthorizeDiscoveredPlayersPayload({playersJson})); } void ExternalMediaPlayerTest::TearDown() { EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), doShutdown()); m_externalMediaPlayer->shutdown(); m_mockMediaPlayer->shutdown(); MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter.reset(); } SetStateResult ExternalMediaPlayerTest::wakeOnSetState() { m_wakeSetStatePromise.set_value(); return SetStateResult::SUCCESS; } SetStateResult ExternalMediaPlayerTest::resetWakeOnSetState() { m_wakeSetStatePromise = std::promise(); m_wakeSetStateFuture = m_wakeSetStatePromise.get_future(); return SetStateResult::SUCCESS; } void ExternalMediaPlayerTest::verifyState(const std::string& providedState, const std::string& expectedState) { rapidjson::Document providedStateParsed; providedStateParsed.Parse(providedState); rapidjson::Document expectedStateParsed; expectedStateParsed.Parse(expectedState); EXPECT_EQ(providedStateParsed, expectedStateParsed); } /** * Test create() with nullptrs */ TEST_F(ExternalMediaPlayerTest, test_createWithNullPointers) { /// Have an empty map of adapters and mediaPlayers ExternalMediaPlayer::AdapterCreationMap adapterMap; ExternalMediaPlayer::AdapterMediaPlayerMap adapterMediaPlayerMap; ExternalMediaPlayer::AdapterSpeakerMap adapterSpeakerMap; auto testExternalMediaPlayer = ExternalMediaPlayer::create( adapterMediaPlayerMap, adapterSpeakerMap, adapterMap, nullptr, m_mockMessageSender, m_mockCertifiedSender->get(), m_mockFocusManager, m_mockContextManager, m_mockExceptionSender, m_mockPlaybackRouter, m_metricRecorder); EXPECT_EQ(testExternalMediaPlayer, nullptr); testExternalMediaPlayer = ExternalMediaPlayer::create( adapterMediaPlayerMap, adapterSpeakerMap, adapterMap, m_mockSpeakerManager, nullptr, m_mockCertifiedSender->get(), m_mockFocusManager, m_mockContextManager, m_mockExceptionSender, m_mockPlaybackRouter, m_metricRecorder); EXPECT_EQ(testExternalMediaPlayer, nullptr); testExternalMediaPlayer = ExternalMediaPlayer::create( adapterMediaPlayerMap, adapterSpeakerMap, adapterMap, m_mockSpeakerManager, m_mockMessageSender, m_mockCertifiedSender->get(), nullptr, m_mockContextManager, m_mockExceptionSender, m_mockPlaybackRouter, m_metricRecorder); EXPECT_EQ(testExternalMediaPlayer, nullptr); testExternalMediaPlayer = ExternalMediaPlayer::create( adapterMediaPlayerMap, adapterSpeakerMap, adapterMap, m_mockSpeakerManager, m_mockMessageSender, m_mockCertifiedSender->get(), m_mockFocusManager, nullptr, m_mockExceptionSender, m_mockPlaybackRouter, m_metricRecorder); EXPECT_EQ(testExternalMediaPlayer, nullptr); testExternalMediaPlayer = ExternalMediaPlayer::create( adapterMediaPlayerMap, adapterSpeakerMap, adapterMap, m_mockSpeakerManager, m_mockMessageSender, m_mockCertifiedSender->get(), m_mockFocusManager, m_mockContextManager, nullptr, m_mockPlaybackRouter, m_metricRecorder); EXPECT_EQ(testExternalMediaPlayer, nullptr); testExternalMediaPlayer = ExternalMediaPlayer::create( adapterMediaPlayerMap, adapterSpeakerMap, adapterMap, m_mockSpeakerManager, m_mockMessageSender, m_mockCertifiedSender->get(), m_mockFocusManager, m_mockContextManager, m_mockExceptionSender, nullptr, m_metricRecorder); EXPECT_EQ(testExternalMediaPlayer, nullptr); } /** * Method to test successful creation of ExternalMediaPlayer capability agent * even if the creation of adapters fails. */ TEST_F(ExternalMediaPlayerTest, test_createWithAdapterCreationFailures) { /// Have an empty map of adapters and mediaPlayers ExternalMediaPlayer::AdapterCreationMap adapterMap; ExternalMediaPlayer::AdapterMediaPlayerMap adapterMediaPlayerMap; ExternalMediaPlayer::AdapterSpeakerMap adapterSpeakerMap; auto testExternalMediaPlayer = ExternalMediaPlayer::create( adapterMediaPlayerMap, adapterSpeakerMap, adapterMap, m_mockSpeakerManager, m_mockMessageSender, m_mockCertifiedSender->get(), m_mockFocusManager, m_mockContextManager, m_mockExceptionSender, m_mockPlaybackRouter, m_metricRecorder); ASSERT_TRUE(testExternalMediaPlayer); testExternalMediaPlayer->shutdown(); // Create an adapter MSP_PROVIDER2 but do not create a mediaPlayer for it. adapterMap.clear(); adapterMediaPlayerMap.clear(); adapterMediaPlayerMap.insert(std::make_pair(MSP1_LOCAL_PLAYER_ID, m_mockMediaPlayer)); adapterMap.insert(std::make_pair(MSP2_LOCAL_PLAYER_ID, &MockExternalMediaPlayerAdapter::getInstance)); testExternalMediaPlayer = ExternalMediaPlayer::create( adapterMediaPlayerMap, adapterSpeakerMap, adapterMap, m_mockSpeakerManager, m_mockMessageSender, m_mockCertifiedSender->get(), m_mockFocusManager, m_mockContextManager, m_mockExceptionSender, m_mockPlaybackRouter, m_metricRecorder); ASSERT_TRUE(testExternalMediaPlayer); testExternalMediaPlayer->shutdown(); } /** * Test getConfiguration on an ExternalMediaPlayer. The operation succeeds. */ TEST_F(ExternalMediaPlayerTest, test_getConfiguration) { auto configuration = m_externalMediaPlayer->getConfiguration(); auto audioNonBlockingPolicy = BlockingPolicy(BlockingPolicy::MEDIUM_AUDIO, false); auto neitherNonBlockingPolicy = BlockingPolicy(BlockingPolicy::MEDIUMS_NONE, false); // TODO: ARC-227 Verify default values ASSERT_EQ(configuration[PLAY_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[AUTHORIZEDISCOVEREDPLAYERS_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[LOGIN_DIRECTIVE], neitherNonBlockingPolicy); ASSERT_EQ(configuration[LOGOUT_DIRECTIVE], neitherNonBlockingPolicy); ASSERT_EQ(configuration[RESUME_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[PAUSE_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[STOP_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[NEXT_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[PREVIOUS_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[STARTOVER_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[REWIND_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[FASTFORWARD_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[ENABLEREPEATONE_DIRECTIVE], neitherNonBlockingPolicy); ASSERT_EQ(configuration[ENABLEREPEAT_DIRECTIVE], neitherNonBlockingPolicy); ASSERT_EQ(configuration[DISABLEREPEAT_DIRECTIVE], neitherNonBlockingPolicy); ASSERT_EQ(configuration[ENABLESHUFFLE_DIRECTIVE], neitherNonBlockingPolicy); ASSERT_EQ(configuration[DISABLESHUFFLE_DIRECTIVE], neitherNonBlockingPolicy); ASSERT_EQ(configuration[SEEK_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[ADJUSTSEEK_DIRECTIVE], audioNonBlockingPolicy); ASSERT_EQ(configuration[FAVORITE_DIRECTIVE], neitherNonBlockingPolicy); ASSERT_EQ(configuration[UNFAVORITE_DIRECTIVE], neitherNonBlockingPolicy); } void ExternalMediaPlayerTest::sendAuthorizeDiscoveredPlayersDirective( const std::string& payload, std::unique_ptr resultHandler) { if (!resultHandler) { resultHandler = std::unique_ptr(new MockDirectiveHandlerResult); } auto avsMessageHeader = std::make_shared( AUTHORIZEDISCOVEREDPLAYERS_DIRECTIVE.nameSpace, AUTHORIZEDISCOVEREDPLAYERS_DIRECTIVE.name, MESSAGE_ID_TEST2); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, payload, m_attachmentManager, ""); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(resultHandler)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST2); } /** * Test session state information on an ExternalMediaPlayer . */ TEST_F(ExternalMediaPlayerTest, test_callingProvideSessionState) { EXPECT_CALL( *(m_mockContextManager.get()), setState(SESSION_STATE, _, StateRefreshPolicy::ALWAYS, PROVIDE_STATE_TOKEN_TEST)) .Times(1) .WillOnce(DoAll( // need to include all four arguments, but only care about jsonState Invoke([this]( const avs::NamespaceAndName& namespaceAndName, const std::string& jsonState, const avs::StateRefreshPolicy& refreshPolicy, const unsigned int stateRequestToken) { std::string agent = ""; verifyState(jsonState, getIdleSessionStateJson(agent)); }), InvokeWithoutArgs(this, &ExternalMediaPlayerTest::wakeOnSetState))); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), getState()); m_externalMediaPlayer->provideState(SESSION_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT)); } /** * Test playback state information on an ExternalMediaPlayer. */ TEST_F(ExternalMediaPlayerTest, test_callingProvidePlaybackState) { EXPECT_CALL( *(m_mockContextManager.get()), setState(PLAYBACK_STATE, _, StateRefreshPolicy::ALWAYS, PROVIDE_STATE_TOKEN_TEST)) .Times(1) .WillOnce(DoAll( // need to include all four arguments, but only care about jsonState Invoke([this]( const avs::NamespaceAndName& namespaceAndName, const std::string& jsonState, const avs::StateRefreshPolicy& refreshPolicy, const unsigned int stateRequestToken) { verifyState(jsonState, IDLE_PLAYBACK_STATE); }), InvokeWithoutArgs(this, &ExternalMediaPlayerTest::wakeOnSetState))); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), getState()).Times(AtLeast(1)); m_externalMediaPlayer->provideState(PLAYBACK_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT)); } /** * Test payload with parse error in ExternalMediaPlayer. This should fail. */ TEST_F(ExternalMediaPlayerTest, test_playParserError) { auto avsMessageHeader = std::make_shared( PLAY_DIRECTIVE.nameSpace, PLAY_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createPlayPayloadWithParseError("XXX", 0, 0, "Adapter", "YYY", "ZZZ", "DEFAULT", false), m_attachmentManager, ""); EXPECT_CALL(*(m_mockExceptionSender.get()), sendExceptionEncountered(_, _, _)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setFailed(_)); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test PLAY payload without an adapter in ExternalMediaPlayer. This should fail. */ TEST_F(ExternalMediaPlayerTest, test_playNoAdapter) { auto avsMessageHeader = std::make_shared( PLAY_DIRECTIVE.nameSpace, PLAY_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createPlayPayload("XXX", 0, 0, "Adapter", "YYY", "ZZZ", "DEFAULT", false), m_attachmentManager, ""); EXPECT_CALL(*(m_mockExceptionSender.get()), sendExceptionEncountered(_, _, _)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setFailed(_)); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test PLAY payload without play context in ExternalMediaPlayer. This should fail. */ TEST_F(ExternalMediaPlayerTest, test_playNoPlayContext) { auto avsMessageHeader = std::make_shared( PLAY_DIRECTIVE.nameSpace, PLAY_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createPlayPayloadNoContext(0, 0, MSP1_PLAYER_ID, "YYY", "ZZZ", "DEFAULT", false), m_attachmentManager, ""); EXPECT_CALL(*(m_mockExceptionSender.get()), sendExceptionEncountered(_, _, _)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setFailed(_)); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test PLAY payload without playerId in ExternalMediaPlayer. This should fail. */ TEST_F(ExternalMediaPlayerTest, test_playNoPlayerId) { auto avsMessageHeader = std::make_shared( PLAY_DIRECTIVE.nameSpace, PLAY_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createPlayPayloadNoPlayerId("XXX", 0, 0, "YYY", "ZZZ", "DEFAULT", false), m_attachmentManager, ""); EXPECT_CALL(*(m_mockExceptionSender.get()), sendExceptionEncountered(_, _, _)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setFailed(_)); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test PLAY payload without offsetin ExternalMediaPlayer. This should succeed. */ TEST_F(ExternalMediaPlayerTest, test_playNoOffset) { auto avsMessageHeader = std::make_shared( PLAY_DIRECTIVE.nameSpace, PLAY_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createPlayPayloadNoOffset("XXX", 0, MSP1_PLAYER_ID, "YYY", "ZZZ", "DEFAULT", false), m_attachmentManager, ""); EXPECT_CALL( *(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlay(_, _, _, _, _, _, _, PlayRequestor{})); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test PLAY payload with playRequestor in ExternalMediaPlayer. This should succeed. */ TEST_F(ExternalMediaPlayerTest, testPlaywithPlayRequestor) { auto avsMessageHeader = std::make_shared( PLAY_DIRECTIVE.nameSpace, PLAY_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createPlayPayloadWithPlayRequestor( "XXX", 0, 0, MSP1_PLAYER_ID, "YYY", "ZZZ", "DEFAULT", false, testPlayRequestor), m_attachmentManager, ""); EXPECT_CALL( *(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlay(_, _, _, _, _, _, _, testPlayRequestor)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test PLAY payload without index in ExternalMediaPlayer. This should succeed. */ TEST_F(ExternalMediaPlayerTest, test_playNoIndex) { auto avsMessageHeader = std::make_shared( PLAY_DIRECTIVE.nameSpace, PLAY_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createPlayPayloadNoIndex("XXX", 0, MSP1_PLAYER_ID, "YYY", "ZZZ", "DEFAULT", false), m_attachmentManager, ""); EXPECT_CALL( *(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlay(_, _, _, _, _, _, _, _)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful logout. */ TEST_F(ExternalMediaPlayerTest, test_logout) { auto avsMessageHeader = std::make_shared( LOGOUT_DIRECTIVE.nameSpace, LOGOUT_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handleLogout()); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful login. */ TEST_F(ExternalMediaPlayerTest, test_login) { auto avsMessageHeader = std::make_shared( LOGIN_DIRECTIVE.nameSpace, LOGIN_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createLoginPayload("XXX", "msploginuser", 1000, false, MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handleLogin(_, _, _, _)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test observers of session state are correctly notified */ TEST_F(ExternalMediaPlayerTest, test_loginStateChangeObserverIsNotified) { // add a mock observer auto observer = MockExternalMediaPlayerObserver::getInstance(); m_externalMediaPlayer->addObserver(observer); EXPECT_CALL( *(m_mockContextManager.get()), setState(SESSION_STATE, _, StateRefreshPolicy::ALWAYS, PROVIDE_STATE_TOKEN_TEST)) .Times(1) .WillOnce(InvokeWithoutArgs(this, &ExternalMediaPlayerTest::wakeOnSetState)); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), getState()) .WillRepeatedly(Return(createAdapterState())); ObservableSessionProperties observableSessionProperties{false, PLAYER_USER_NAME}; EXPECT_CALL(*(observer), onLoginStateProvided(PLAYER_ID, observableSessionProperties)).Times(1); m_externalMediaPlayer->provideState(SESSION_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT)); } /** * Test observers of playback state are correctly notified */ TEST_F(ExternalMediaPlayerTest, test_playbackStateChangeObserverIsNotified) { // add a mock observer auto observer = MockExternalMediaPlayerObserver::getInstance(); m_externalMediaPlayer->addObserver(observer); EXPECT_CALL( *(m_mockContextManager.get()), setState(PLAYBACK_STATE, _, StateRefreshPolicy::ALWAYS, PROVIDE_STATE_TOKEN_TEST)) .Times(1) .WillRepeatedly(InvokeWithoutArgs(this, &ExternalMediaPlayerTest::wakeOnSetState)); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), getState()) .WillRepeatedly(Return(createAdapterState())); ObservablePlaybackStateProperties observablePlaybackStateProperties{PLAYER_STATE, PLAYER_TRACK, testPlayRequestor}; EXPECT_CALL(*(observer), onPlaybackStateProvided(PLAYER_ID, observablePlaybackStateProperties)).Times(1); m_externalMediaPlayer->provideState(PLAYBACK_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT)); } /** * Test that after removal login observers are not called anymore */ TEST_F(ExternalMediaPlayerTest, test_loginStateChangeObserverRemoval) { // add a mock observer auto observer = MockExternalMediaPlayerObserver::getInstance(); m_externalMediaPlayer->addObserver(observer); EXPECT_CALL( *(m_mockContextManager.get()), setState(SESSION_STATE, _, StateRefreshPolicy::ALWAYS, PROVIDE_STATE_TOKEN_TEST)) .Times(2) .WillRepeatedly(InvokeWithoutArgs(this, &ExternalMediaPlayerTest::wakeOnSetState)); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), getState()) .WillRepeatedly(Return(createAdapterState())); EXPECT_CALL(*(observer), onLoginStateProvided(_, _)).Times(1); m_externalMediaPlayer->provideState(SESSION_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT)); this->resetWakeOnSetState(); m_externalMediaPlayer->removeObserver(observer); EXPECT_CALL(*(observer), onLoginStateProvided(_, _)).Times(0); m_externalMediaPlayer->provideState(SESSION_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT)); } /** * Test that after removal playback state observers are not called anymore */ TEST_F(ExternalMediaPlayerTest, test_playbackStateChangeObserverRemoval) { // add a mock observer auto observer = MockExternalMediaPlayerObserver::getInstance(); m_externalMediaPlayer->addObserver(observer); EXPECT_CALL( *(m_mockContextManager.get()), setState(PLAYBACK_STATE, _, StateRefreshPolicy::ALWAYS, PROVIDE_STATE_TOKEN_TEST)) .Times(2) .WillRepeatedly(InvokeWithoutArgs(this, &ExternalMediaPlayerTest::wakeOnSetState)); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), getState()) .WillRepeatedly(Return(createAdapterState())); EXPECT_CALL(*(observer), onPlaybackStateProvided(_, _)).Times(1); m_externalMediaPlayer->provideState(PLAYBACK_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT)); this->resetWakeOnSetState(); m_externalMediaPlayer->removeObserver(observer); EXPECT_CALL(*(observer), onPlaybackStateProvided(_, _)).Times(0); m_externalMediaPlayer->provideState(PLAYBACK_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT)); } /** * Test successful resume. */ TEST_F(ExternalMediaPlayerTest, test_play) { auto avsMessageHeader = std::make_shared( RESUME_DIRECTIVE.nameSpace, RESUME_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful pause. */ TEST_F(ExternalMediaPlayerTest, test_pause) { auto avsMessageHeader = std::make_shared( PAUSE_DIRECTIVE.nameSpace, PAUSE_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful stop. */ TEST_F(ExternalMediaPlayerTest, testStop) { auto avsMessageHeader = std::make_shared( STOP_DIRECTIVE.nameSpace, STOP_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful stop. */ TEST_F(ExternalMediaPlayerTest, test_stop) { auto avsMessageHeader = std::make_shared( STOP_DIRECTIVE.nameSpace, STOP_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful next. */ TEST_F(ExternalMediaPlayerTest, test_next) { auto avsMessageHeader = std::make_shared( NEXT_DIRECTIVE.nameSpace, NEXT_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful previous. */ TEST_F(ExternalMediaPlayerTest, test_previous) { auto avsMessageHeader = std::make_shared( PREVIOUS_DIRECTIVE.nameSpace, PREVIOUS_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful StarOver. */ TEST_F(ExternalMediaPlayerTest, test_startOver) { auto avsMessageHeader = std::make_shared( STARTOVER_DIRECTIVE.nameSpace, STARTOVER_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful rewind. */ TEST_F(ExternalMediaPlayerTest, test_rewind) { auto avsMessageHeader = std::make_shared( REWIND_DIRECTIVE.nameSpace, REWIND_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful fast-forward. */ TEST_F(ExternalMediaPlayerTest, test_fastForward) { auto avsMessageHeader = std::make_shared( FASTFORWARD_DIRECTIVE.nameSpace, FASTFORWARD_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful EnableRepeatOne. */ TEST_F(ExternalMediaPlayerTest, test_enableRepeatOne) { auto avsMessageHeader = std::make_shared( ENABLEREPEATONE_DIRECTIVE.nameSpace, ENABLEREPEATONE_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful EnableRepeat. */ TEST_F(ExternalMediaPlayerTest, test_enableRepeat) { auto avsMessageHeader = std::make_shared( ENABLEREPEAT_DIRECTIVE.nameSpace, ENABLEREPEAT_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful DisableRepeat. */ TEST_F(ExternalMediaPlayerTest, test_disableRepeat) { auto avsMessageHeader = std::make_shared( DISABLEREPEAT_DIRECTIVE.nameSpace, DISABLEREPEAT_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful EnableShuffle. */ TEST_F(ExternalMediaPlayerTest, test_enableShuffle) { auto avsMessageHeader = std::make_shared( ENABLESHUFFLE_DIRECTIVE.nameSpace, ENABLESHUFFLE_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful DisableRepeat. */ TEST_F(ExternalMediaPlayerTest, test_disableShuffle) { auto avsMessageHeader = std::make_shared( DISABLESHUFFLE_DIRECTIVE.nameSpace, DISABLESHUFFLE_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful Favorite. */ TEST_F(ExternalMediaPlayerTest, test_favorite) { auto avsMessageHeader = std::make_shared( FAVORITE_DIRECTIVE.nameSpace, FAVORITE_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful UnFavorite. */ TEST_F(ExternalMediaPlayerTest, test_unfavorite) { auto avsMessageHeader = std::make_shared( UNFAVORITE_DIRECTIVE.nameSpace, UNFAVORITE_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handlePlayControl(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test incorrect directive. */ TEST_F(ExternalMediaPlayerTest, test_incorrectDirective) { auto avsMessageHeader = std::make_shared( FAVORITE_DIRECTIVE.nameSpace, PREVIOUS_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create("", avsMessageHeader, createPayloadWithPlayerId(MSP1_PLAYER_ID), m_attachmentManager, ""); EXPECT_CALL(*(m_mockExceptionSender.get()), sendExceptionEncountered(_, _, _)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setFailed(_)); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test Seek failure passing incorrect field in payload. */ TEST_F(ExternalMediaPlayerTest, test_seekFailure) { auto avsMessageHeader = std::make_shared( SEEK_DIRECTIVE.nameSpace, SEEK_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createSeekPayload(100, MSP1_PLAYER_ID, true), m_attachmentManager, ""); EXPECT_CALL(*(m_mockExceptionSender.get()), sendExceptionEncountered(_, _, _)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setFailed(_)); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test successful Seek. */ TEST_F(ExternalMediaPlayerTest, test_seekSuccess) { auto avsMessageHeader = std::make_shared( SEEK_DIRECTIVE.nameSpace, SEEK_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createSeekPayload(100, MSP1_PLAYER_ID, false), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handleSeek(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test AdjustSeek failure incorrect field in payload. */ TEST_F(ExternalMediaPlayerTest, test_adjustSeekFailure) { auto avsMessageHeader = std::make_shared( ADJUSTSEEK_DIRECTIVE.nameSpace, ADJUSTSEEK_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createSeekPayload(100, MSP1_PLAYER_ID, false), m_attachmentManager, ""); EXPECT_CALL(*(m_mockExceptionSender.get()), sendExceptionEncountered(_, _, _)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setFailed(_)); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test AdjustSeek failure passing in an incorrect offset. */ TEST_F(ExternalMediaPlayerTest, test_adjustSeekFailure2) { auto avsMessageHeader = std::make_shared( ADJUSTSEEK_DIRECTIVE.nameSpace, ADJUSTSEEK_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createSeekPayload(86400014, MSP1_PLAYER_ID, true), m_attachmentManager, ""); EXPECT_CALL(*(m_mockExceptionSender.get()), sendExceptionEncountered(_, _, _)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setFailed(_)); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Test AdjustSeek successful passing in correct payload and offset. */ TEST_F(ExternalMediaPlayerTest, test_adjustSeekSuccess) { auto avsMessageHeader = std::make_shared( ADJUSTSEEK_DIRECTIVE.nameSpace, ADJUSTSEEK_DIRECTIVE.name, MESSAGE_ID_TEST, DIALOG_REQUEST_ID_TEST); std::shared_ptr directive = AVSDirective::create( "", avsMessageHeader, createSeekPayload(86400000, MSP1_PLAYER_ID, true), m_attachmentManager, ""); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handleAdjustSeek(_)); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); m_externalMediaPlayer->CapabilityAgent::preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult)); m_externalMediaPlayer->CapabilityAgent::handleDirective(MESSAGE_ID_TEST); } /** * Custom matcher to check an event of a certain name is sent. * Returns true if the event with that name is sent. * */ MATCHER_P2( EventNamed, /* std::string */ expectedNameSpace, /* std::string */ expectedName, "") { // Throw obvious compile error if not a MessageRequest. std::shared_ptr request = arg; if (!request) { return false; } rapidjson::Document document; ParseResult result = document.Parse(request->getJsonContent()); if (!result) { return false; } rapidjson::Value::ConstMemberIterator eventIt; rapidjson::Value::ConstMemberIterator headerIt; if (!json::jsonUtils::findNode(document, "event", &eventIt) || !json::jsonUtils::findNode(eventIt->value, "header", &headerIt)) { return false; } std::string name; std::string nameSpace; if (!json::jsonUtils::retrieveValue(headerIt->value, "name", &name) || !json::jsonUtils::retrieveValue(headerIt->value, "namespace", &nameSpace) || nameSpace != expectedNameSpace || name != expectedName) { return false; } return true; } /** * Checks that the AuthorizationComplete event contains the expected authorized and deauthorized fields. * * @param request The AuthorizationComplete event sent. * @param expectedAuthorized The expected list of @c playerId to @c skillToken pairs to verify against. * @param expectedDeauthorized The expected list of @c deauthorized localPlayerId the verify against. */ static void veryifyAuthorizationCompletePayload( std::shared_ptr request, std::unordered_map expectedAuthorized, std::unordered_set expectedDeauthorized = std::unordered_set()) { rapidjson::Document document; ParseResult result = document.Parse(request->getJsonContent()); if (!result) { FAIL(); } rapidjson::Value::ConstMemberIterator eventIt; rapidjson::Value::ConstMemberIterator payloadIt; rapidjson::Value::ConstMemberIterator authorizedIt; rapidjson::Value::ConstMemberIterator deauthorizedIt; if (!findNode(document, "event", &eventIt) || !findNode(eventIt->value, "payload", &payloadIt) || !findNode(payloadIt->value, "authorized", &authorizedIt) || !findNode(payloadIt->value, "deauthorized", &deauthorizedIt)) { FAIL(); } std::unordered_map authorized; std::unordered_set deauthorized; for (rapidjson::Value::ConstValueIterator it = authorizedIt->value.Begin(); it != authorizedIt->value.End(); it++) { std::string playerId; std::string skillToken; if (!retrieveValue(*it, "playerId", &playerId) || !retrieveValue(*it, "skillToken", &skillToken)) { FAIL(); } authorized[playerId] = skillToken; } for (rapidjson::Value::ConstValueIterator it = deauthorizedIt->value.Begin(); it != deauthorizedIt->value.End(); it++) { std::string localPlayerId; if (!retrieveValue(*it, "localPlayerId", &localPlayerId)) { FAIL(); } deauthorized.insert(localPlayerId); } ASSERT_THAT(authorized, ContainerEq(expectedAuthorized)); ASSERT_THAT(deauthorized, ContainerEq(expectedDeauthorized)); } /** * Test that ReportDiscoveredPlayers is sent. */ TEST_F(ExternalMediaPlayerTest, testReportDiscoveredPlayers) { std::promise eventPromise; std::future eventFuture = eventPromise.get_future(); // Initialize the CertifiedSender auto mockCertifiedSender = std::make_shared(); std::shared_ptr connectionObserver = std::static_pointer_cast( mockCertifiedSender->get()); connectionObserver->onConnectionStatusChanged( ConnectionStatusObserverInterface::Status::CONNECTED, ConnectionStatusObserverInterface::ChangedReason::SUCCESS); // Set expectation on m_mockCertifiedSender's @c MessageSenderInterface // because @c MockCertifiedSender isn't a gmock mock. EXPECT_CALL( *(mockCertifiedSender->getMockMessageSender()), sendMessage(EventNamed(REPORT_DISCOVERED_PLAYERS.nameSpace, REPORT_DISCOVERED_PLAYERS.name))) .Times(1) .WillOnce(InvokeWithoutArgs([&eventPromise]() { eventPromise.set_value(); })); auto messageSender = std::make_shared>(); m_externalMediaPlayer = ExternalMediaPlayer::create( m_adapterMediaPlayerMap, m_adapterSpeakerMap, m_adapterMap, m_mockSpeakerManager, m_mockMessageSender, mockCertifiedSender->get(), m_mockFocusManager, m_mockContextManager, m_mockExceptionSender, m_mockPlaybackRouter, m_metricRecorder); ASSERT_TRUE(std::future_status::ready == eventFuture.wait_for(MY_WAIT_TIMEOUT)); } /** * Test successful AuthorizeDiscoveredPlayers directive processing. */ TEST_F(ExternalMediaPlayerTest, testAuthorizeDiscoveredPlayersSuccess) { std::promise authorizationCompletePromise; std::future authorizationCompleteFuture = authorizationCompletePromise.get_future(); ON_CALL(*m_mockContextManager, getContext(_, _, _)).WillByDefault(InvokeWithoutArgs([this]() { m_externalMediaPlayer->onContextAvailable(""); return 0; })); // Use another instance to avoid SetUp() interferring with the test. auto messageSender = std::make_shared>(); m_externalMediaPlayer = ExternalMediaPlayer::create( m_adapterMediaPlayerMap, m_adapterSpeakerMap, m_adapterMap, m_mockSpeakerManager, messageSender, m_mockCertifiedSender->get(), m_mockFocusManager, m_mockContextManager, m_mockExceptionSender, m_mockPlaybackRouter, m_metricRecorder); EXPECT_CALL(*m_mockDirectiveHandlerResult, setCompleted()); EXPECT_CALL(*messageSender, sendMessage(EventNamed(AUTHORIZATION_COMPLETE.nameSpace, AUTHORIZATION_COMPLETE.name))) .Times(1) .WillOnce(Invoke([&authorizationCompletePromise](std::shared_ptr request) { veryifyAuthorizationCompletePayload(request, {{MSP1_PLAYER_ID, MSP1_SKILLTOKEN}}); authorizationCompletePromise.set_value(); })); EXPECT_CALL( *(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handleAuthorized(true, MSP1_PLAYER_ID, MSP1_SKILLTOKEN)); const std::string playersJson = createPlayerJson(MSP1_LOCAL_PLAYER_ID, true, MSP1_PLAYER_ID, MSP1_SKILLTOKEN); sendAuthorizeDiscoveredPlayersDirective( createAuthorizeDiscoveredPlayersPayload({playersJson}), std::move(m_mockDirectiveHandlerResult)); ASSERT_TRUE(std::future_status::ready == authorizationCompleteFuture.wait_for(MY_WAIT_TIMEOUT)); } /** * Test successful AuthorizeDiscoveredPlayers directive processing of multiple directives. */ TEST_F(ExternalMediaPlayerTest, testMultipleAuthorizeDiscoveredPlayersSuccess) { ON_CALL(*m_mockContextManager, getContext(_, _, _)).WillByDefault(InvokeWithoutArgs([this]() { m_externalMediaPlayer->onContextAvailable(""); return 0; })); // Use another instance to avoid SetUp() interferring with the test. auto messageSender = std::make_shared>(); m_externalMediaPlayer = ExternalMediaPlayer::create( m_adapterMediaPlayerMap, m_adapterSpeakerMap, m_adapterMap, m_mockSpeakerManager, messageSender, m_mockCertifiedSender->get(), m_mockFocusManager, m_mockContextManager, m_mockExceptionSender, m_mockPlaybackRouter, m_metricRecorder); std::promise authorizationCompletePromise; std::future authorizationCompleteFuture = authorizationCompletePromise.get_future(); auto mockDirectiveHandlerResult = std::unique_ptr(new MockDirectiveHandlerResult); EXPECT_CALL(*mockDirectiveHandlerResult, setCompleted()); EXPECT_CALL( *(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handleAuthorized(true, MSP1_PLAYER_ID, MSP1_SKILLTOKEN)); std::promise authorizationCompletePromise2; std::future authorizationCompleteFuture2 = authorizationCompletePromise2.get_future(); auto mockDirectiveHandlerResult2 = std::unique_ptr(new MockDirectiveHandlerResult); EXPECT_CALL(*mockDirectiveHandlerResult2, setCompleted()); EXPECT_CALL(*(MockExternalMediaPlayerAdapter::m_currentActiveMediaPlayerAdapter), handleAuthorized(false, "", "")); { InSequence s; EXPECT_CALL( *messageSender, sendMessage(EventNamed(AUTHORIZATION_COMPLETE.nameSpace, AUTHORIZATION_COMPLETE.name))) .Times(1) .WillOnce(Invoke([&authorizationCompletePromise](std::shared_ptr request) { veryifyAuthorizationCompletePayload(request, {{MSP1_PLAYER_ID, MSP1_SKILLTOKEN}}); authorizationCompletePromise.set_value(); })); EXPECT_CALL( *messageSender, sendMessage(EventNamed(AUTHORIZATION_COMPLETE.nameSpace, AUTHORIZATION_COMPLETE.name))) .Times(1) .WillOnce(Invoke([&authorizationCompletePromise2](std::shared_ptr request) { veryifyAuthorizationCompletePayload( request, std::unordered_map(), {MSP1_LOCAL_PLAYER_ID}); authorizationCompletePromise2.set_value(); })); } const std::string playersJson = createPlayerJson(MSP1_LOCAL_PLAYER_ID, true, MSP1_PLAYER_ID, MSP1_SKILLTOKEN); sendAuthorizeDiscoveredPlayersDirective( createAuthorizeDiscoveredPlayersPayload({playersJson}), std::move(mockDirectiveHandlerResult)); sendAuthorizeDiscoveredPlayersDirective( createAuthorizeDiscoveredPlayersPayload(), std::move(mockDirectiveHandlerResult2)); ASSERT_TRUE(std::future_status::ready == authorizationCompleteFuture.wait_for(MY_WAIT_TIMEOUT)); ASSERT_TRUE(std::future_status::ready == authorizationCompleteFuture2.wait_for(MY_WAIT_TIMEOUT)); } /** * Test setPlayerInFocus succeeds for authorized players. */ TEST_F(ExternalMediaPlayerTest, testSetPlayerInFocusSucceedsForAuthorized) { EXPECT_CALL(*m_mockContextManager, setState(SESSION_STATE, _, _, _)) .WillOnce(Invoke([this]( const avs::NamespaceAndName& namespaceAndName, const std::string& jsonState, const avs::StateRefreshPolicy& refreshPolicy, const unsigned int stateRequestToken) { rapidjson::Document document; ParseResult result = document.Parse(jsonState); if (!result) { return SetStateResult::SUCCESS; } std::string playerInFocus; if (!retrieveValue(document, "playerInFocus", &playerInFocus)) { return SetStateResult::SUCCESS; } if (MSP1_PLAYER_ID == playerInFocus) { wakeOnSetState(); } return SetStateResult::SUCCESS; })); // Authorized from SetUp(). m_externalMediaPlayer->setPlayerInFocus(MSP1_PLAYER_ID); m_externalMediaPlayer->provideState(SESSION_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT)); } /** * Test setPlayerInFocus fails for unauthorized players. */ TEST_F(ExternalMediaPlayerTest, testSetPlayerInFocusFailsForAuthorized) { const std::string INVALID_ID = "invalidPlayerId"; EXPECT_CALL(*m_mockPlaybackRouter, setHandler(_)).Times(0); EXPECT_CALL(*m_mockContextManager, setState(_, Not(HasSubstr(INVALID_ID)), _, _)) .WillOnce(InvokeWithoutArgs(this, &ExternalMediaPlayerTest::wakeOnSetState)); m_externalMediaPlayer->setPlayerInFocus(INVALID_ID); m_externalMediaPlayer->provideState(SESSION_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == m_wakeSetStateFuture.wait_for(MY_WAIT_TIMEOUT)); } /** * Test setPlayerInFocus notifies any RenderPlayerInfoCardsObservers. */ TEST_F(ExternalMediaPlayerTest, testSetPlayerInFocusNotfiesTemplateRuntimeObserver) { std::promise promise; std::future future = promise.get_future(); auto renderCardObserver = std::make_shared(); m_externalMediaPlayer->setObserver(renderCardObserver); EXPECT_CALL(*renderCardObserver, onRenderPlayerCardsInfoChanged(_, _)) .WillOnce(Invoke([&promise]( avsCommon::avs::PlayerActivity state, const RenderPlayerInfoCardsObserverInterface::Context& context) { promise.set_value(); })); // Authorized from SetUp(). m_externalMediaPlayer->setPlayerInFocus(MSP1_PLAYER_ID); m_externalMediaPlayer->provideState(PLAYBACK_STATE, PROVIDE_STATE_TOKEN_TEST); ASSERT_TRUE(std::future_status::ready == future.wait_for(MY_WAIT_TIMEOUT)); } } // namespace test } // namespace externalMediaPlayer } // namespace capabilityAgents } // namespace alexaClientSDK