/* * Copyright 2017-2018 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. */ #include #include #include #include "ContextManager/ContextManager.h" using namespace testing; namespace alexaClientSDK { namespace contextManager { namespace test { using namespace avsCommon; using namespace avsCommon::avs; using namespace avsCommon::sdkInterfaces; /// String to identify log entries originating from this file. static const std::string TAG("ContextManagerTest"); /** * 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) /// Payload for SpeechSynthesizer state when it is playing back audio. static const std::string SPEECH_SYNTHESIZER_PAYLOAD_PLAYING = "{" "\"playerActivity\":\"PLAYING\"," "\"offsetInMilliseconds\":5," "\"token\":\"\"" "}"; /// Payload for SpeechSynthesizer state when playback has finished. static const std::string SPEECH_SYNTHESIZER_PAYLOAD_FINISHED = "{" "\"playerActivity\":\"FINISHED\"," "\"offsetInMilliseconds\":0," "\"token\":\"\"" "}"; /// Payload for AudioPlayer. static const std::string AUDIO_PLAYER_PAYLOAD = "{" "\"playerActivity\":\"FINISHED\"," "\"offsetInMilliseconds\":0," "\"token\":\"\"" "}"; /// Payload for Alerts. static const std::string ALERTS_PAYLOAD = "{" "\"allAlerts\": [" "{" "\"token\": \"\"," "\"type\": \"TIMER\"," "\"scheduledTime\": \"\"" "}" "]," "\"activeAlerts\": [" "{" "\"token\": \"\"," "\"type\": \"TIMER\"," "\"scheduledTime\": \"\"" "}" "]" "}"; /// Context used for testing. static const std::string CONTEXT_TEST = "{" "\"context\":[" "{" "\"header\":{" "\"namespace\":\"AudioPlayer\"," "\"name\":\"PlaybackState\"" "}," "\"payload\":{" "\"playerActivity\":\"FINISHED\"," "\"offsetInMilliseconds\":0," "\"token\":\"\"" "}" "}," "{" "\"header\":{" "\"namespace\":\"SpeechSynthesizer\"," "\"name\":\"SpeechState\"" "}," "\"payload\":{" "\"playerActivity\":\"FINISHED\"," "\"offsetInMilliseconds\":0," "\"token\":\"\"" "}" "}" "]" "}"; /// Default time @c doProvide sleeps before it calls @c setState. static const std::chrono::milliseconds DEFAULT_SLEEP_TIME = std::chrono::milliseconds(10); /// Time @c doProvide sleeps before it calls @c setState to induce a timeout. static const std::chrono::milliseconds TIMEOUT_SLEEP_TIME = std::chrono::milliseconds(100); /** * Default timeout for the @c ContextRequester to get the context.This needs to be modified if the * @c TIMEOUT_SLEEP_TIME is modified. The value should be less than the @c TIMEOUT_SLEEP_TIME. */ static const std::chrono::milliseconds DEFAULT_TIMEOUT = std::chrono::milliseconds(50); /// Timeout for the @c ContextRequester to get the failure. static const std::chrono::milliseconds FAILURE_TIMEOUT = std::chrono::milliseconds(220); /// Namespace for SpeechSynthesizer. static const std::string NAMESPACE_SPEECH_SYNTHESIZER("SpeechSynthesizer"); /// Namespace for AudioPlayer. static const std::string NAMESPACE_AUDIO_PLAYER("AudioPlayer"); /// Namespace for Alerts. static const std::string NAMESPACE_ALERTS("Alerts"); /// Name for SpeechSynthesizer state. static const std::string NAME_SPEECH_STATE("SpeechState"); /// Name for AudioPlayer state. static const std::string NAME_PLAYBACK_STATE("PlaybackState"); /// Name for Alerts state. static const std::string NAME_ALERTS_STATE("AlertsState"); /// SpeechSynthesizer namespace and name static const NamespaceAndName SPEECH_SYNTHESIZER(NAMESPACE_SPEECH_SYNTHESIZER, NAME_SPEECH_STATE); /// AudioPlayer namespace and name static const NamespaceAndName AUDIO_PLAYER(NAMESPACE_AUDIO_PLAYER, NAME_PLAYBACK_STATE); /// Alerts namespace and name static const NamespaceAndName ALERTS(NAMESPACE_ALERTS, NAME_ALERTS_STATE); /// Dummy provider namespace and name static const NamespaceAndName DUMMY_PROVIDER("Dummy", "DummyName"); /** * @c MockContextRequester used to verify @c ContextManager behavior. */ class MockContextRequester : public ContextRequesterInterface { public: /** * Creates an instance of the @c MockContextRequester. * * @param contextManager Pointer to an instance of the @c ContextManager. * @return A shared pointer to an instance of the @c MockContextRequester. */ static std::shared_ptr create(std::shared_ptr contextManager); /** * Constructor * * @param contextManager Pointer to an instance of the @c ContextManager. */ MockContextRequester(std::shared_ptr contextManager); ~MockContextRequester(); void onContextAvailable(const std::string& context) override; void onContextFailure(const ContextRequestError error) override; /** * Waits for a specified time for the context to be available @c getContext. * * @param duration Number of milliseconds to wait before giving up. * @return @c true if a context or failure was received within the specified duration, else @c false. */ bool waitForContext(const std::chrono::milliseconds duration = std::chrono::milliseconds(200)); /** * Waits for a specified time for the context request to fail on a @c getContext. * * @param duration Number of milliseconds to wait before giving up. * @return @c true if a failure was received within the specified duration, else @c false. */ bool waitForFailure(const std::chrono::milliseconds duration = std::chrono::milliseconds(200)); /** * Function to read the stored context. * * @return The context. */ std::string& getContextString(); /** * Function to read check context string JSON against the reference context JSON with unordered states. * * @return @c true if both JSON context strings are equivalent, else @c false. */ bool checkContextString(const std::string& a, const std::string& b); private: /// Instance of @ ContextManager std::shared_ptr m_contextManager; /// Condition variable to wake the @ waitForContext. std::condition_variable m_wakeTriggerSuccess; /// Condition variable to wake the @ waitForFailure. std::condition_variable m_wakeTriggerFailure; /// mutex to protect @c m_contextAvailable. std::mutex m_mutexSuccess; /// mutex to protect @c m_contextFailure. std::mutex m_mutexFailure; /// Flag to indicate context is available. bool m_contextAvailable; /// Flag to indicate there was a failure during @c getContext. bool m_contextFailure; /// String to hold the context returned by the @c ContextManager. std::string m_context; /** * Function to convert a JSON object to string. * *@param documentNode the JSON object. *@return the serialized JSON string */ std::string serializeJSONObjectToString(const rapidjson::Value& documentNode); }; std::shared_ptr MockContextRequester::create(std::shared_ptr contextManager) { auto result = std::make_shared(contextManager); return result; } MockContextRequester::MockContextRequester(std::shared_ptr contextManager) : m_contextManager{contextManager}, m_contextAvailable{false}, m_contextFailure{false} { } MockContextRequester::~MockContextRequester() { } void MockContextRequester::onContextAvailable(const std::string& context) { std::unique_lock lock(m_mutexSuccess); m_context = context; m_contextAvailable = true; m_wakeTriggerSuccess.notify_one(); } void MockContextRequester::onContextFailure(const ContextRequestError error) { std::unique_lock lock(m_mutexFailure); m_contextFailure = true; m_wakeTriggerFailure.notify_one(); } bool MockContextRequester::waitForContext(const std::chrono::milliseconds duration) { std::unique_lock lock(m_mutexSuccess); if (!m_wakeTriggerSuccess.wait_for(lock, duration, [this]() { return (m_contextAvailable || m_contextFailure); })) { return false; } return true; } bool MockContextRequester::waitForFailure(const std::chrono::milliseconds duration) { std::unique_lock lock(m_mutexFailure); if (!m_wakeTriggerFailure.wait_for(lock, duration, [this]() { return (m_contextAvailable || m_contextFailure); })) { return false; } return true; } std::string& MockContextRequester::getContextString() { return m_context; } std::string MockContextRequester::serializeJSONObjectToString(const rapidjson::Value& documentNode) { if (!documentNode.IsObject()) { ACSDK_ERROR(LX("serializeJSONObjectToStringFailed") .d("reason", "invalidType") .d("expectedType", rapidjson::Type::kObjectType) .d("type", documentNode.GetType())); return ""; } rapidjson::StringBuffer stringBuffer; rapidjson::Writer writer(stringBuffer); if (!documentNode.Accept(writer)) { ACSDK_ERROR(LX("serializeJSONObjectToStringFailed").d("reason", "acceptFailed").d("handler", "Writer")); return ""; } return stringBuffer.GetString(); } bool MockContextRequester::checkContextString(const std::string& a, const std::string& b) { rapidjson::Document ajson; rapidjson::Document bjson; const char contextstr[] = "context"; ajson.Parse(a.c_str()); if (!ajson.HasMember(contextstr)) { ACSDK_ERROR(LX("checkContextStringFailed").d("reason", "invalidContextString").d("json", a)); return false; } bjson.Parse(b.c_str()); if (!bjson.HasMember(contextstr)) { ACSDK_ERROR(LX("checkContextStringFailed").d("reason", "invalidContextString").d("json", b)); return false; } const rapidjson::Value& acontext = ajson[contextstr]; const rapidjson::Value& bcontext = bjson[contextstr]; if (!acontext.IsArray()) { ACSDK_ERROR(LX("checkContextStringFailed").d("reason", "invalidContextString").d("json", a)); return false; } if (!bcontext.IsArray()) { ACSDK_ERROR(LX("checkContextStringFailed").d("reason", "invalidContextString").d("json", b)); return false; } if (acontext.Size() != bcontext.Size()) { ACSDK_ERROR(LX("checkContextStringFailed").d("reason", "contextStringNotMatched").d("value", a).d("ref", b)); return false; } for (rapidjson::Value::ConstValueIterator itr = acontext.Begin(); itr != acontext.End(); ++itr) { bool entryMatch = false; std::string aconstring; aconstring = serializeJSONObjectToString(*itr); for (rapidjson::Value::ConstValueIterator itr2 = bcontext.Begin(); itr2 != bcontext.End(); ++itr2) { std::string bconstring; bconstring = serializeJSONObjectToString(*itr); if (aconstring == bconstring) { entryMatch = true; break; } } if (!entryMatch) { ACSDK_ERROR( LX("checkContextStringFailed").d("reason", "contextStringNotMatched").d("value", a).d("ref", b)); return false; } } return true; } /** * @c MockStateProvider used to verify @c ContextManager behavior. */ class MockStateProvider : public StateProviderInterface { public: /** * Creates an instance of the @c MockStateProvider. * * @param contextManager Pointer to an instance of the @c ContextManager. * @param namespaceAndName The namespace and name of the @c StateProvider. * @param jsonState The state of the @c StateProvider set in response to the @c provideState. * @param refreshPolicy The refresh policy for the state set in response to the @c provideState. * @param delayTime The time @c m_doProvideThread sleeps before updating state via @c setState. * @return A pointer to an instance of the @c MockStateProvider. */ static std::shared_ptr create( std::shared_ptr contextManager, const NamespaceAndName& namespaceAndName, const std::string& state, const StateRefreshPolicy& refreshPolicy, const std::chrono::milliseconds delayTime); /** * Constructor. It sets up the state and refresh policy that needs to be sent in response to a @c provideContext * request. * * @param contextManager Pointer to an instance of the @c ContextManager. * @param namespaceAndName The namespace and name of the @c StateProvider. * @param jsonState The state of the @c StateProvider set in response to the @c provideState. * @param refreshPolicy The refresh policy for the state set in response to the @c provideState. * @param delayTime The time @c m_doProvideThread sleeps before updating state via @c setState. * @return A pointer to an instance of the @c MockStateProvider. */ MockStateProvider( std::shared_ptr contextManager, const NamespaceAndName& namespaceAndName, const std::string& state, const StateRefreshPolicy& refreshPolicy, const std::chrono::milliseconds delayTime); ~MockStateProvider(); void provideState(const NamespaceAndName& stateProviderName, unsigned int currentstateRequestToken) override; /** * Method for m_doProvideThread. It waits for @c m_delayTime and then calls @c setState with the state @c m_state * and the refresh policy @c m_refreshPolicy the @c stateProviderInterface was initialized with. */ void doProvideState(); unsigned int getCurrentstateRequestToken(); private: /// Pointer to an instance of the @c ContextManager std::shared_ptr m_contextManager; /// The namespace and name of the @c stateProviderInterface NamespaceAndName m_namespaceAndName; /// The state provided to the @c ContextManager via @c setState. std::string m_state; /// The refresh policy for the state provided to the @c ContextManager via @c setState. StateRefreshPolicy m_refreshPolicy; /// The token provided by the @c ContextManager. unsigned int m_stateRequestToken; /// Thread to execute the doProvide. std::thread m_doProvideThread; /// Mutex to protect the @c m_provideState. std::mutex m_providerMutex; /// The condition variable used to wake up @c m_doProvideThread when the @c ContextManager requests for state. std::condition_variable m_providerWakeTrigger; /// The time the @c m_doProvideThread sleeps before providing state. std::chrono::milliseconds m_delayTime; /// Flag to indicate when a @c provideState has been called. bool m_provideState; /// Flag to indicate when the @c MockStateProvider is shutting down. When set, @c m_doProvideThread needs to return. bool m_stateProviderShutdown; }; std::shared_ptr MockStateProvider::create( std::shared_ptr contextManager, const NamespaceAndName& stateProviderName, const std::string& state, const StateRefreshPolicy& refreshPolicy, const std::chrono::milliseconds delayTime) { auto result = std::make_shared(contextManager, stateProviderName, state, refreshPolicy, delayTime); return result; } MockStateProvider::MockStateProvider( std::shared_ptr contextManager, const NamespaceAndName& stateProviderName, const std::string& state, const StateRefreshPolicy& refreshPolicy, const std::chrono::milliseconds delayTime) : m_contextManager{contextManager}, m_namespaceAndName{stateProviderName}, m_state{state}, m_refreshPolicy{refreshPolicy}, m_stateRequestToken{0}, m_delayTime{delayTime}, m_provideState{false}, m_stateProviderShutdown{false} { m_doProvideThread = std::thread(&MockStateProvider::doProvideState, this); } MockStateProvider::~MockStateProvider() { std::unique_lock lock(m_providerMutex); m_stateProviderShutdown = true; m_providerWakeTrigger.notify_one(); lock.unlock(); if (m_doProvideThread.joinable()) { m_doProvideThread.join(); } } void MockStateProvider::provideState(const NamespaceAndName& stateProviderName, unsigned int stateRequestToken) { m_stateRequestToken = stateRequestToken; std::lock_guard lock(m_providerMutex); m_provideState = true; m_providerWakeTrigger.notify_one(); } void MockStateProvider::doProvideState() { while (true) { std::unique_lock lock(m_providerMutex); m_providerWakeTrigger.wait(lock, [this]() { return (m_provideState || m_stateProviderShutdown); }); if (m_stateProviderShutdown) { lock.unlock(); return; } std::this_thread::sleep_for(m_delayTime); EXPECT_EQ( SetStateResult::SUCCESS, m_contextManager->setState(m_namespaceAndName, m_state, m_refreshPolicy, m_stateRequestToken)); m_provideState = false; lock.unlock(); } } unsigned int MockStateProvider::getCurrentstateRequestToken() { return m_stateRequestToken; } /// Context Manager Test class ContextManagerTest : public ::testing::Test { public: /** * Setup the @c ContextManagerTest. Creates a @c ContextManager. Creates a couple of @c MockStateProviders and * a @c MockContextRequester. */ void SetUp() override; /// @c ContextManager to test std::shared_ptr m_contextManager; /// @c MockStateProviders and @c MockContextRequesters std::shared_ptr m_speechSynthesizer; std::shared_ptr m_audioPlayer; std::shared_ptr m_alerts; std::shared_ptr m_contextRequester; std::shared_ptr m_contextRequester2; }; void ContextManagerTest::SetUp() { m_contextManager = ContextManager::create(); m_speechSynthesizer = MockStateProvider::create( m_contextManager, SPEECH_SYNTHESIZER, SPEECH_SYNTHESIZER_PAYLOAD_FINISHED, StateRefreshPolicy::NEVER, DEFAULT_SLEEP_TIME); m_audioPlayer = MockStateProvider::create( m_contextManager, AUDIO_PLAYER, AUDIO_PLAYER_PAYLOAD, StateRefreshPolicy::NEVER, DEFAULT_SLEEP_TIME); m_contextManager->setStateProvider(SPEECH_SYNTHESIZER, m_speechSynthesizer); m_contextManager->setStateProvider(AUDIO_PLAYER, m_audioPlayer); m_contextRequester = MockContextRequester::create(m_contextManager); } /** * Set the state with a @c StateRefreshPolicy @c ALWAYS for a @c StateProviderInterface that is registered with the * @c ContextManager. Expect @c SetStateResult @c SUCCESS is returned. */ TEST_F(ContextManagerTest, testSetStateForRegisteredProvider) { ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( SPEECH_SYNTHESIZER, SPEECH_SYNTHESIZER_PAYLOAD_PLAYING, StateRefreshPolicy::ALWAYS, m_speechSynthesizer->getCurrentstateRequestToken())); } /** * Set the state with a @c StateRefreshPolicy @c NEVER for a @c StateProviderInterface that is not registered with the * @c ContextManager. Expect @c SetStateResult @c SUCCESS is returned. */ TEST_F(ContextManagerTest, testSetStateForUnregisteredProvider) { ASSERT_EQ(SetStateResult::SUCCESS, m_contextManager->setState(ALERTS, ALERTS_PAYLOAD, StateRefreshPolicy::NEVER)); } /** * Set the state with a @c StateRefreshPolicy @c ALWAYS for a @c StateProviderInterface that is not registered with * the @c ContextManager. Expect @c SetStateResult @c STATE_PROVIDER_NOT_REGISTERED is returned. */ TEST_F(ContextManagerTest, testSetStateForUnregisteredProviderWithRefreshPolicyAlways) { m_alerts = MockStateProvider::create( m_contextManager, ALERTS, ALERTS_PAYLOAD, StateRefreshPolicy::NEVER, DEFAULT_SLEEP_TIME); ASSERT_EQ( SetStateResult::STATE_PROVIDER_NOT_REGISTERED, m_contextManager->setState( ALERTS, ALERTS_PAYLOAD, StateRefreshPolicy::ALWAYS, m_alerts->getCurrentstateRequestToken())); } /** * Set the states with a @c StateRefreshPolicy @c ALWAYS for @c StateProviderInterfaces that are registered with the * @c ContextManager. Request for context by calling @c getContext. Expect that the context is returned within the * timeout period. Check the context that is returned by the @c ContextManager. Expect it should match the test value. */ TEST_F(ContextManagerTest, testGetContext) { ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( SPEECH_SYNTHESIZER, SPEECH_SYNTHESIZER_PAYLOAD_PLAYING, StateRefreshPolicy::ALWAYS, m_speechSynthesizer->getCurrentstateRequestToken())); ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( AUDIO_PLAYER, AUDIO_PLAYER_PAYLOAD, StateRefreshPolicy::ALWAYS, m_audioPlayer->getCurrentstateRequestToken())); m_contextManager->getContext(m_contextRequester); ASSERT_TRUE(m_contextRequester->waitForContext(DEFAULT_TIMEOUT)); ASSERT_EQ(CONTEXT_TEST, m_contextRequester->getContextString()); } /** * Set the states with a @c StateRefreshPolicy @c ALWAYS for @c StateProviderInterfaces that are registered with the * @c ContextManager. Request for context by calling @c getContext by multiple requesters. Expect that the context is * returned to each of the requesters within the timeout period. */ TEST_F(ContextManagerTest, testMultipleGetContextRequests) { ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( SPEECH_SYNTHESIZER, SPEECH_SYNTHESIZER_PAYLOAD_PLAYING, StateRefreshPolicy::ALWAYS, m_speechSynthesizer->getCurrentstateRequestToken())); ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( AUDIO_PLAYER, AUDIO_PLAYER_PAYLOAD, StateRefreshPolicy::ALWAYS, m_audioPlayer->getCurrentstateRequestToken())); m_contextRequester2 = MockContextRequester::create(m_contextManager); m_contextManager->getContext(m_contextRequester); m_contextManager->getContext(m_contextRequester2); ASSERT_TRUE(m_contextRequester->waitForContext(DEFAULT_TIMEOUT)); ASSERT_EQ(CONTEXT_TEST, m_contextRequester->getContextString()); ASSERT_TRUE(m_contextRequester2->waitForContext(DEFAULT_TIMEOUT)); ASSERT_EQ(CONTEXT_TEST, m_contextRequester2->getContextString()); } /** * Set the states with a @c StateRefreshPolicy @c ALWAYS for @c StateProviderInterfaces that are registered with the * @c ContextManager. Request for context by calling @c getContext. Expect that the context is returned within the * timeout period. Check the context that is returned by the @c ContextManager. Expect it should match the test value. * Register a registered @c StateProviderInterface again with the @c ContextManager. Then set the state for the same * @c StateProviderInterface with a @c StateRefreshPolicy @c ALWAYS. Expect @c SetStateResult @c SUCCESS is returned. * Request for context by calling @c getContext. Expect that the context is returned within the * timeout period. Check the context that is returned by the @c ContextManager matches the test context. */ TEST_F(ContextManagerTest, testSetProviderTwice) { ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( SPEECH_SYNTHESIZER, SPEECH_SYNTHESIZER_PAYLOAD_PLAYING, StateRefreshPolicy::ALWAYS, m_speechSynthesizer->getCurrentstateRequestToken())); ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( AUDIO_PLAYER, AUDIO_PLAYER_PAYLOAD, StateRefreshPolicy::ALWAYS, m_audioPlayer->getCurrentstateRequestToken())); m_contextManager->getContext(m_contextRequester); ASSERT_TRUE(m_contextRequester->waitForContext(DEFAULT_TIMEOUT)); ASSERT_EQ(CONTEXT_TEST, m_contextRequester->getContextString()); // Call setStateProvider for a registered StateProviderInterface. m_contextManager->setStateProvider(SPEECH_SYNTHESIZER, m_speechSynthesizer); ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( SPEECH_SYNTHESIZER, SPEECH_SYNTHESIZER_PAYLOAD_PLAYING, StateRefreshPolicy::ALWAYS, m_speechSynthesizer->getCurrentstateRequestToken())); m_contextManager->getContext(m_contextRequester); ASSERT_TRUE(m_contextRequester->waitForContext(DEFAULT_TIMEOUT)); ASSERT_EQ(CONTEXT_TEST, m_contextRequester->getContextString()); } /** * Register a @c StateProviderInterfaces with the @c ContextManager which responds slowly to @provideState requests. * Set the states with a @c StateRefreshPolicy @c ALWAYS for @c StateProviderInterfaces. Request for context by calling * @c getContext. Expect that failure occurs due to timeout. */ TEST_F(ContextManagerTest, testProvideStateTimeout) { m_alerts = MockStateProvider::create( m_contextManager, ALERTS, ALERTS_PAYLOAD, StateRefreshPolicy::NEVER, TIMEOUT_SLEEP_TIME); m_contextManager->setStateProvider(ALERTS, m_alerts); ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( SPEECH_SYNTHESIZER, SPEECH_SYNTHESIZER_PAYLOAD_PLAYING, StateRefreshPolicy::ALWAYS, m_speechSynthesizer->getCurrentstateRequestToken())); ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( AUDIO_PLAYER, AUDIO_PLAYER_PAYLOAD, StateRefreshPolicy::ALWAYS, m_audioPlayer->getCurrentstateRequestToken())); ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( ALERTS, ALERTS_PAYLOAD, StateRefreshPolicy::ALWAYS, m_alerts->getCurrentstateRequestToken())); m_contextManager->getContext(m_contextRequester); ASSERT_TRUE(m_contextRequester->waitForFailure(FAILURE_TIMEOUT)); } /** * Remove a @c StateProviderInterface that was registered with the @c ContextManager. Set the state with a * @c StateRefreshPolicy @c ALWAYS for the @c StateProviderInterface that was unregistered. Expect @c SetStateResult * @c STATE_PROVIDER_NOT_REGISTERED is returned. */ TEST_F(ContextManagerTest, testRemoveProvider) { m_contextManager->setStateProvider(SPEECH_SYNTHESIZER, nullptr); ASSERT_EQ( SetStateResult::STATE_PROVIDER_NOT_REGISTERED, m_contextManager->setState( SPEECH_SYNTHESIZER, SPEECH_SYNTHESIZER_PAYLOAD_PLAYING, StateRefreshPolicy::ALWAYS, m_speechSynthesizer->getCurrentstateRequestToken())); } /** * Request for context by calling @c getContextSet. Wait for context. Set the state for a @c StateProviderInterface * that is registered with the @c ContextManager with a wrong token value. Expect that * @c SetStateResult @c STATE_TOKEN_OUTDATED is returned. */ TEST_F(ContextManagerTest, testIncorrectToken) { m_contextManager->getContext(m_contextRequester); ASSERT_TRUE(m_contextRequester->waitForContext(DEFAULT_TIMEOUT)); ASSERT_EQ( SetStateResult::STATE_TOKEN_OUTDATED, m_contextManager->setState( SPEECH_SYNTHESIZER, SPEECH_SYNTHESIZER_PAYLOAD_PLAYING, StateRefreshPolicy::ALWAYS, m_speechSynthesizer->getCurrentstateRequestToken() + 1)); } /** * Set the states with a @c StateRefreshPolicy @c ALWAYS for @c StateProviderInterfaces that are registered with the * @c ContextManager. Request for context by calling @c getContext. Expect that the context is returned within the * timeout period. * * There's a dummyProvider with StateRefreshPolicy @c SOMETIMES that returns an empty context. Check ContextManager is * okay with it and would include the context provided by the dummyProvider. * * Check the context that is returned by the @c ContextManager. Expect it should match the test value. */ TEST_F(ContextManagerTest, testEmptyProvider) { auto dummyProvider = MockStateProvider::create( m_contextManager, DUMMY_PROVIDER, "", StateRefreshPolicy::SOMETIMES, DEFAULT_SLEEP_TIME); m_contextManager->setStateProvider(DUMMY_PROVIDER, dummyProvider); ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( SPEECH_SYNTHESIZER, SPEECH_SYNTHESIZER_PAYLOAD_PLAYING, StateRefreshPolicy::ALWAYS, m_speechSynthesizer->getCurrentstateRequestToken())); ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( AUDIO_PLAYER, AUDIO_PLAYER_PAYLOAD, StateRefreshPolicy::ALWAYS, m_audioPlayer->getCurrentstateRequestToken())); ASSERT_EQ( SetStateResult::SUCCESS, m_contextManager->setState( DUMMY_PROVIDER, "", StateRefreshPolicy::ALWAYS, dummyProvider->getCurrentstateRequestToken())); m_contextManager->getContext(m_contextRequester); ASSERT_TRUE(m_contextRequester->waitForContext(DEFAULT_TIMEOUT)); ASSERT_TRUE(m_contextRequester->checkContextString(CONTEXT_TEST, m_contextRequester->getContextString())); } } // namespace test } // namespace contextManager } // namespace alexaClientSDK