SmartAudio/package/avs/avs-sdk/files/avs-device-sdk/ContextManager/test/ContextManagerTest.cpp

795 lines
30 KiB
C++

/*
* 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 <AVSCommon/Utils/Logger/Logger.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#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<MockContextRequester> create(std::shared_ptr<ContextManager> contextManager);
/**
* Constructor
*
* @param contextManager Pointer to an instance of the @c ContextManager.
*/
MockContextRequester(std::shared_ptr<ContextManager> 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<ContextManager> 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> MockContextRequester::create(std::shared_ptr<ContextManager> contextManager) {
auto result = std::make_shared<MockContextRequester>(contextManager);
return result;
}
MockContextRequester::MockContextRequester(std::shared_ptr<ContextManager> contextManager) :
m_contextManager{contextManager},
m_contextAvailable{false},
m_contextFailure{false} {
}
MockContextRequester::~MockContextRequester() {
}
void MockContextRequester::onContextAvailable(const std::string& context) {
std::unique_lock<std::mutex> lock(m_mutexSuccess);
m_context = context;
m_contextAvailable = true;
m_wakeTriggerSuccess.notify_one();
}
void MockContextRequester::onContextFailure(const ContextRequestError error) {
std::unique_lock<std::mutex> lock(m_mutexFailure);
m_contextFailure = true;
m_wakeTriggerFailure.notify_one();
}
bool MockContextRequester::waitForContext(const std::chrono::milliseconds duration) {
std::unique_lock<std::mutex> 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<std::mutex> 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<rapidjson::StringBuffer> 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<MockStateProvider> create(
std::shared_ptr<ContextManager> 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> 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<ContextManager> 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> MockStateProvider::create(
std::shared_ptr<ContextManager> contextManager,
const NamespaceAndName& stateProviderName,
const std::string& state,
const StateRefreshPolicy& refreshPolicy,
const std::chrono::milliseconds delayTime) {
auto result =
std::make_shared<MockStateProvider>(contextManager, stateProviderName, state, refreshPolicy, delayTime);
return result;
}
MockStateProvider::MockStateProvider(
std::shared_ptr<ContextManager> 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<std::mutex> 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<std::mutex> lock(m_providerMutex);
m_provideState = true;
m_providerWakeTrigger.notify_one();
}
void MockStateProvider::doProvideState() {
while (true) {
std::unique_lock<std::mutex> 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<ContextManager> m_contextManager;
/// @c MockStateProviders and @c MockContextRequesters
std::shared_ptr<MockStateProvider> m_speechSynthesizer;
std::shared_ptr<MockStateProvider> m_audioPlayer;
std::shared_ptr<MockStateProvider> m_alerts;
std::shared_ptr<MockContextRequester> m_contextRequester;
std::shared_ptr<MockContextRequester> 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