avs-device-sdk/Settings/test/LocaleWakeWordsSettingTest.cpp

634 lines
28 KiB
C++

/*
* 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.
*/
#include <condition_variable>
#include <memory>
#include <mutex>
#include <set>
#include <string>
#include <tuple>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <AVSCommon/SDKInterfaces/MockLocaleAssetsManager.h>
#include <AVSCommon/Utils/JSON/JSONUtils.h>
#include <AVSCommon/Utils/WaitEvent.h>
#include <Settings/SettingEventMetadata.h>
#include <Settings/SettingObserverInterface.h>
#include <Settings/SettingStringConversion.h>
#include <Settings/Types/LocaleWakeWordsSetting.h>
#include "Settings/MockDeviceSettingStorage.h"
#include "Settings/MockSettingEventSender.h"
#include "Settings/MockSettingObserver.h"
namespace alexaClientSDK {
namespace settings {
namespace test {
using namespace avsCommon::sdkInterfaces;
using namespace avsCommon::sdkInterfaces::test;
using namespace avsCommon::utils::json;
using namespace avsCommon::utils;
using namespace storage::test;
using namespace testing;
using namespace types;
/// Constant representing "ALEXA" enabled.
static const std::string ALEXA_VALUE = "ALEXA";
/// Constant representing "ECHO" enabled value.
static const std::string ECHO_VALUE = "ECHO";
/// Constant representing "en-CA" enabled db value.
static const std::string ENGLISH_CANADA_VALUE = "en-CA";
/// Constant representing "fr-CA" enabled db value.
static const std::string FRENCH_CANADA_VALUE = "fr-CA";
/// Constant representing an invalid wake word / locale value.
static const std::string INVALID_VALUE = "INVALID";
/// Constant representing the timeout for test events.
/// @note Use a large enough value that should not fail even in slower systems.
static const std::chrono::seconds MY_WAIT_TIMEOUT{5};
/// Set of combinations of supported wake words.
static const MockLocaleAssetsManager::LocaleAssetsManagerInterface::WakeWordsSets SUPPORTED_WAKE_WORDS_COMBINATION{
{ALEXA_VALUE},
{ECHO_VALUE},
{ALEXA_VALUE, ECHO_VALUE}};
/// Set of supported locales.
static const std::set<std::string> SUPPORTED_LOCALES{ENGLISH_CANADA_VALUE, FRENCH_CANADA_VALUE};
/// A vector of locales that contains only en-CA.
static const std::vector<std::string> ENGLISH_LOCALES{ENGLISH_CANADA_VALUE};
/// The database key to be used to save wake words.
static const std::string WAKE_WORDS_KEY = "SpeechRecognizer.wakeWords";
/// The database key to be used to save wake words.
static const std::string LOCALES_KEY = "System.locales";
/**
* The test class.
*/
class LocaleWakeWordsSettingTest : public Test {
protected:
/**
* Create protocol object and dependencies mocks.
*/
void SetUp() override;
/**
* Function to generate the json representation of wake words and locales.
*
* @param values The values to be converted to a json string array.
* @return A string representing the json string array.
*/
std::string toJson(std::set<std::string> values) const;
/**
* Function used to create and initialize the setting with the given values. Function will also add the observers.
*
* This function asserts that the object is created successfully.
*
* @param locale The initial value for locale.
* @param wakeWords The initial value for wakeWords.
*/
void initializeSetting(const LocalesSetting::ValueType& locale, const WakeWordsSetting::ValueType wakeWords);
/// Mock event sender for wake words.
std::shared_ptr<MockSettingEventSender> m_wakeWordsSenderMock;
/// Mock event sender for locales.
std::shared_ptr<MockSettingEventSender> m_localesSenderMock;
/// Mock setting storage
std::shared_ptr<MockDeviceSettingStorage> m_storageMock;
/// Mock locale assets manager.
std::shared_ptr<MockLocaleAssetsManager> m_assetsManagerMock;
/// Mock locale setting observer.
std::shared_ptr<MockSettingObserver<LocalesSetting>> m_localeObserver;
/// Mock wake words setting observer.
std::shared_ptr<MockSettingObserver<WakeWordsSetting>> m_wakeWordsObserver;
/// The class under test.
std::shared_ptr<LocaleWakeWordsSetting> m_setting;
};
void LocaleWakeWordsSettingTest::SetUp() {
m_wakeWordsSenderMock = std::make_shared<StrictMock<MockSettingEventSender>>();
m_localesSenderMock = std::make_shared<StrictMock<MockSettingEventSender>>();
m_storageMock = std::make_shared<StrictMock<MockDeviceSettingStorage>>();
m_assetsManagerMock = std::make_shared<StrictMock<MockLocaleAssetsManager>>();
m_localeObserver = std::make_shared<MockSettingObserver<LocalesSetting>>();
m_wakeWordsObserver = std::make_shared<MockSettingObserver<WakeWordsSetting>>();
EXPECT_CALL(*m_assetsManagerMock, getDefaultLocale()).WillRepeatedly(Return(ENGLISH_CANADA_VALUE));
EXPECT_CALL(*m_assetsManagerMock, getSupportedLocales()).WillRepeatedly(Return(SUPPORTED_LOCALES));
EXPECT_CALL(*m_assetsManagerMock, getDefaultSupportedWakeWords())
.WillRepeatedly(Return(SUPPORTED_WAKE_WORDS_COMBINATION));
EXPECT_CALL(*m_assetsManagerMock, getSupportedWakeWords(_))
.WillRepeatedly(Return(SUPPORTED_WAKE_WORDS_COMBINATION));
// Destructor might be called before a request is cleared. This should not be a problem, so expect 0..1 cancel call.
EXPECT_CALL(*m_assetsManagerMock, cancelOngoingChange()).Times(AtMost(1));
}
std::string LocaleWakeWordsSettingTest::toJson(std::set<std::string> values) const {
return jsonUtils::convertToJsonString(values);
}
/**
* Creates a vector of tuples given of setting key, value, and status
*
* @param key The setting key.
* @param value The setting value.
* @param status The setting status.
* @return The setting vector tuple.
*/
std::vector<std::tuple<std::string, std::string, SettingStatus>> convertToDBData(
std::string key,
std::string value,
SettingStatus status) {
std::vector<std::tuple<std::string, std::string, SettingStatus>> datum;
datum.push_back(std::make_tuple(key, value, status));
return datum;
}
void LocaleWakeWordsSettingTest::initializeSetting(
const LocalesSetting::ValueType& locales,
const WakeWordsSetting::ValueType wakeWords) {
WaitEvent e;
EXPECT_CALL(*m_assetsManagerMock, getDefaultLocale()).WillOnce(Return(FRENCH_CANADA_VALUE));
EXPECT_CALL(*m_storageMock, loadSetting(LOCALES_KEY))
.WillOnce(Return(
std::make_pair(SettingStatus::SYNCHRONIZED, settings::toSettingString<DeviceLocales>(locales).second)));
EXPECT_CALL(*m_storageMock, loadSetting(WAKE_WORDS_KEY))
.WillOnce(Return(std::make_pair(SettingStatus::SYNCHRONIZED, jsonUtils::convertToJsonString(wakeWords))));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(locales, wakeWords)).WillOnce(InvokeWithoutArgs([&e] {
e.wakeUp();
return true;
}));
m_setting =
LocaleWakeWordsSetting::create(m_localesSenderMock, m_wakeWordsSenderMock, m_storageMock, m_assetsManagerMock);
ASSERT_THAT(m_setting, NotNull());
LocalesSetting& localeSetting = *m_setting;
WakeWordsSetting& wakeWordsSetting = *m_setting;
ASSERT_EQ(localeSetting.get(), locales);
ASSERT_EQ(wakeWordsSetting.get(), wakeWords);
localeSetting.addObserver(m_localeObserver);
wakeWordsSetting.addObserver(m_wakeWordsObserver);
e.wait(MY_WAIT_TIMEOUT);
}
/// Test create with null event senders.
TEST_F(LocaleWakeWordsSettingTest, test_nullEventSenders) {
ASSERT_FALSE(LocaleWakeWordsSetting::create(nullptr, m_wakeWordsSenderMock, m_storageMock, m_assetsManagerMock));
ASSERT_FALSE(LocaleWakeWordsSetting::create(m_localesSenderMock, nullptr, m_storageMock, m_assetsManagerMock));
}
/// Test create with null storage.
TEST_F(LocaleWakeWordsSettingTest, test_nullStorage) {
ASSERT_FALSE(
LocaleWakeWordsSetting::create(m_localesSenderMock, m_wakeWordsSenderMock, nullptr, m_assetsManagerMock));
}
/// Test create with null assets manager.
TEST_F(LocaleWakeWordsSettingTest, test_nullAssetsManager) {
ASSERT_FALSE(LocaleWakeWordsSetting::create(m_localesSenderMock, m_wakeWordsSenderMock, m_storageMock, nullptr));
}
/// Test restore when all values are available and synchronized.
TEST_F(LocaleWakeWordsSettingTest, test_restoreSynchronized) {
initializeSetting({ENGLISH_CANADA_VALUE}, WakeWordsSetting::ValueType({ALEXA_VALUE}));
}
/// Test success flow for avs wake word request.
TEST_F(LocaleWakeWordsSettingTest, test_AVSChangeWakeWordsRequest) {
initializeSetting({ENGLISH_CANADA_VALUE}, WakeWordsSetting::ValueType({ALEXA_VALUE}));
WakeWordsSetting::ValueType newWakeWords{ALEXA_VALUE, ECHO_VALUE};
auto newWakeWordsJson = toJson({ALEXA_VALUE, ECHO_VALUE});
WaitEvent event;
EXPECT_CALL(
*m_storageMock,
storeSettings(convertToDBData(WAKE_WORDS_KEY, newWakeWordsJson, SettingStatus::AVS_CHANGE_IN_PROGRESS)))
.WillOnce(Return(true));
EXPECT_CALL(*m_wakeWordsObserver, onSettingNotification(_, SettingNotifications::AVS_CHANGE_IN_PROGRESS));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(ENGLISH_LOCALES, newWakeWords)).WillOnce(Return(true));
EXPECT_CALL(*m_wakeWordsObserver, onSettingNotification(newWakeWords, SettingNotifications::AVS_CHANGE));
EXPECT_CALL(*m_wakeWordsSenderMock, sendReportEvent(newWakeWordsJson)).WillOnce(InvokeWithoutArgs([] {
std::promise<bool> retPromise;
retPromise.set_value(true);
return retPromise.get_future();
}));
{
InSequence dummy;
EXPECT_CALL(*m_storageMock, updateSettingStatus(WAKE_WORDS_KEY, SettingStatus::AVS_CHANGE_IN_PROGRESS))
.WillOnce(Return(true));
EXPECT_CALL(*m_storageMock, updateSettingStatus(WAKE_WORDS_KEY, SettingStatus::SYNCHRONIZED))
.WillOnce(InvokeWithoutArgs([&event] {
event.wakeUp();
return true;
}));
}
m_setting->setAvsChange(newWakeWords);
EXPECT_TRUE(event.wait(MY_WAIT_TIMEOUT));
EXPECT_EQ(static_cast<std::shared_ptr<WakeWordsSetting>>(m_setting)->get(), newWakeWords);
}
/// Test that if the set value fails for avs request, the value doesn't change and report event is sent with original
/// value.
TEST_F(LocaleWakeWordsSettingTest, test_AVSChangeWakeWordsRequestSetFailed) {
WakeWordsSetting::ValueType initialWakeWords{ALEXA_VALUE};
initializeSetting({ENGLISH_CANADA_VALUE}, initialWakeWords);
WakeWordsSetting::ValueType newWakeWords{ALEXA_VALUE, ECHO_VALUE};
WaitEvent event;
EXPECT_CALL(*m_wakeWordsObserver, onSettingNotification(_, SettingNotifications::AVS_CHANGE_IN_PROGRESS));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(ENGLISH_LOCALES, newWakeWords)).WillOnce(Return(false));
EXPECT_CALL(*m_wakeWordsObserver, onSettingNotification(initialWakeWords, SettingNotifications::AVS_CHANGE_FAILED));
EXPECT_CALL(*m_wakeWordsSenderMock, sendReportEvent(toJson({ALEXA_VALUE}))).WillOnce(InvokeWithoutArgs([] {
std::promise<bool> retPromise;
retPromise.set_value(true);
return retPromise.get_future();
}));
{
InSequence dummy;
EXPECT_CALL(*m_storageMock, updateSettingStatus(WAKE_WORDS_KEY, SettingStatus::AVS_CHANGE_IN_PROGRESS))
.WillOnce(Return(true));
EXPECT_CALL(*m_storageMock, updateSettingStatus(WAKE_WORDS_KEY, SettingStatus::SYNCHRONIZED))
.WillOnce(InvokeWithoutArgs([&event] {
event.wakeUp();
return true;
}));
}
m_setting->setAvsChange(newWakeWords);
EXPECT_TRUE(event.wait(MY_WAIT_TIMEOUT));
EXPECT_EQ(static_cast<std::shared_ptr<WakeWordsSetting>>(m_setting)->get(), initialWakeWords);
}
/// Test send event failed for avs request.
TEST_F(LocaleWakeWordsSettingTest, test_AVSChangeWakeWordsRequestSendEventFailed) {
initializeSetting({ENGLISH_CANADA_VALUE}, WakeWordsSetting::ValueType({ALEXA_VALUE}));
WakeWordsSetting::ValueType newWakeWords{ALEXA_VALUE, ECHO_VALUE};
auto newWakeWordsJson = toJson({ALEXA_VALUE, ECHO_VALUE});
WaitEvent event;
EXPECT_CALL(*m_storageMock, updateSettingStatus(WAKE_WORDS_KEY, SettingStatus::AVS_CHANGE_IN_PROGRESS))
.WillOnce(Return(true));
EXPECT_CALL(*m_storageMock, updateSettingStatus(WAKE_WORDS_KEY, SettingStatus::SYNCHRONIZED)).Times(0);
EXPECT_CALL(
*m_storageMock,
storeSettings(convertToDBData(WAKE_WORDS_KEY, newWakeWordsJson, SettingStatus::AVS_CHANGE_IN_PROGRESS)))
.WillOnce(Return(true));
EXPECT_CALL(*m_wakeWordsObserver, onSettingNotification(_, SettingNotifications::AVS_CHANGE_IN_PROGRESS));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(ENGLISH_LOCALES, newWakeWords)).WillOnce(Return(true));
EXPECT_CALL(*m_wakeWordsObserver, onSettingNotification(newWakeWords, SettingNotifications::AVS_CHANGE));
EXPECT_CALL(*m_wakeWordsSenderMock, sendReportEvent(newWakeWordsJson)).WillOnce(InvokeWithoutArgs([&] {
std::promise<bool> retPromise;
retPromise.set_value(false);
event.wakeUp();
return retPromise.get_future();
}));
m_setting->setAvsChange(newWakeWords);
EXPECT_TRUE(event.wait(MY_WAIT_TIMEOUT));
EXPECT_EQ(static_cast<std::shared_ptr<WakeWordsSetting>>(m_setting)->get(), newWakeWords);
}
/// Test success flow for avs locale request.
TEST_F(LocaleWakeWordsSettingTest, test_AVSChangeLocaleRequest) {
WakeWordsSetting::ValueType wakeWords{ALEXA_VALUE};
initializeSetting({ENGLISH_CANADA_VALUE}, wakeWords);
LocalesSetting::ValueType newLocale{FRENCH_CANADA_VALUE};
auto newLocaleJson = toSettingString<DeviceLocales>(newLocale).second;
WaitEvent event;
EXPECT_CALL(
*m_storageMock,
storeSettings(convertToDBData(LOCALES_KEY, newLocaleJson, SettingStatus::AVS_CHANGE_IN_PROGRESS)))
.WillOnce(Return(true));
EXPECT_CALL(*m_localeObserver, onSettingNotification(_, SettingNotifications::AVS_CHANGE_IN_PROGRESS));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(newLocale, wakeWords)).WillOnce(Return(true));
EXPECT_CALL(*m_localeObserver, onSettingNotification(newLocale, SettingNotifications::AVS_CHANGE));
EXPECT_CALL(*m_localesSenderMock, sendReportEvent(newLocaleJson)).WillOnce(InvokeWithoutArgs([] {
std::promise<bool> retPromise;
retPromise.set_value(true);
return retPromise.get_future();
}));
InSequence dummy;
{
EXPECT_CALL(*m_storageMock, updateSettingStatus(LOCALES_KEY, SettingStatus::AVS_CHANGE_IN_PROGRESS))
.WillOnce(Return(true));
EXPECT_CALL(*m_storageMock, updateSettingStatus(LOCALES_KEY, SettingStatus::SYNCHRONIZED))
.WillOnce(InvokeWithoutArgs([&event] {
event.wakeUp();
return true;
}));
}
m_setting->setAvsChange(newLocale);
EXPECT_TRUE(event.wait(MY_WAIT_TIMEOUT));
EXPECT_EQ(static_cast<std::shared_ptr<LocalesSetting>>(m_setting)->get(), newLocale);
}
/// Test set value failed for avs request.
TEST_F(LocaleWakeWordsSettingTest, test_AVSChangeLocaleRequestSetFailed) {
WakeWordsSetting::ValueType wakeWords{ALEXA_VALUE};
initializeSetting({ENGLISH_CANADA_VALUE}, wakeWords);
LocalesSetting::ValueType newLocale{FRENCH_CANADA_VALUE};
auto initialLocaleJson = toSettingString<DeviceLocales>({ENGLISH_CANADA_VALUE}).second;
WaitEvent event;
EXPECT_CALL(*m_localeObserver, onSettingNotification(_, SettingNotifications::AVS_CHANGE_IN_PROGRESS));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(newLocale, wakeWords)).WillOnce(Return(false));
EXPECT_CALL(
*m_localeObserver,
onSettingNotification(DeviceLocales({ENGLISH_CANADA_VALUE}), SettingNotifications::AVS_CHANGE_FAILED));
EXPECT_CALL(*m_localesSenderMock, sendReportEvent(initialLocaleJson)).WillOnce(InvokeWithoutArgs([] {
std::promise<bool> retPromise;
retPromise.set_value(true);
return retPromise.get_future();
}));
InSequence dummy;
{
EXPECT_CALL(*m_storageMock, updateSettingStatus(LOCALES_KEY, SettingStatus::AVS_CHANGE_IN_PROGRESS))
.WillOnce(Return(true));
EXPECT_CALL(*m_storageMock, updateSettingStatus(LOCALES_KEY, SettingStatus::SYNCHRONIZED))
.WillOnce(InvokeWithoutArgs([&event] {
event.wakeUp();
return true;
}));
}
m_setting->setAvsChange(newLocale);
EXPECT_TRUE(event.wait(MY_WAIT_TIMEOUT));
EXPECT_EQ(
static_cast<std::shared_ptr<LocalesSetting>>(m_setting)->get(),
LocalesSetting::ValueType{ENGLISH_CANADA_VALUE});
}
/// Test send event failed for avs request.
TEST_F(LocaleWakeWordsSettingTest, test_AVSChangeLocaleRequestSendEventFailed) {
WakeWordsSetting::ValueType wakeWords{ALEXA_VALUE};
initializeSetting({ENGLISH_CANADA_VALUE}, wakeWords);
LocalesSetting::ValueType newLocale{FRENCH_CANADA_VALUE};
auto newLocaleJson = toSettingString<DeviceLocales>(newLocale).second;
WaitEvent event;
EXPECT_CALL(*m_storageMock, updateSettingStatus(LOCALES_KEY, SettingStatus::AVS_CHANGE_IN_PROGRESS))
.WillOnce(Return(true));
EXPECT_CALL(*m_storageMock, updateSettingStatus(WAKE_WORDS_KEY, SettingStatus::SYNCHRONIZED)).Times(0);
EXPECT_CALL(
*m_storageMock,
storeSettings(convertToDBData(LOCALES_KEY, newLocaleJson, SettingStatus::AVS_CHANGE_IN_PROGRESS)))
.WillOnce(Return(true));
EXPECT_CALL(*m_localeObserver, onSettingNotification(_, SettingNotifications::AVS_CHANGE_IN_PROGRESS));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(newLocale, wakeWords)).WillOnce(Return(true));
EXPECT_CALL(*m_localeObserver, onSettingNotification(newLocale, SettingNotifications::AVS_CHANGE));
EXPECT_CALL(*m_localesSenderMock, sendReportEvent(newLocaleJson)).WillOnce(InvokeWithoutArgs([&] {
std::promise<bool> retPromise;
retPromise.set_value(false);
event.wakeUp();
return retPromise.get_future();
}));
m_setting->setAvsChange(newLocale);
EXPECT_TRUE(event.wait(MY_WAIT_TIMEOUT));
EXPECT_EQ(static_cast<std::shared_ptr<LocalesSetting>>(m_setting)->get(), newLocale);
}
/// Test restore when no value is available in the database. This should run local change to both wake words and locale.
TEST_F(LocaleWakeWordsSettingTest, test_restoreValueNotAvailable) {
EXPECT_CALL(*m_assetsManagerMock, getDefaultLocale()).WillOnce(Return(FRENCH_CANADA_VALUE));
EXPECT_CALL(*m_storageMock, loadSetting(LOCALES_KEY))
.WillOnce(Return(std::make_pair(SettingStatus::NOT_AVAILABLE, "")));
EXPECT_CALL(*m_storageMock, loadSetting(WAKE_WORDS_KEY))
.WillOnce(Return(std::make_pair(SettingStatus::NOT_AVAILABLE, "")));
WakeWordsSetting::ValueType initialWakeWords{{ALEXA_VALUE}};
LocalesSetting::ValueType initialLocale{FRENCH_CANADA_VALUE};
auto wakeWordsJson = toJson({ALEXA_VALUE});
auto localeJson = toSettingString<DeviceLocales>(DeviceLocales{FRENCH_CANADA_VALUE}).second;
std::vector<std::tuple<std::string, std::string, SettingStatus>> datum;
datum.push_back(std::make_tuple(LOCALES_KEY, localeJson, SettingStatus::LOCAL_CHANGE_IN_PROGRESS));
datum.push_back(std::make_tuple(WAKE_WORDS_KEY, wakeWordsJson, SettingStatus::LOCAL_CHANGE_IN_PROGRESS));
EXPECT_CALL(*m_storageMock, storeSettings(datum)).WillOnce(Return(true));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(initialLocale, initialWakeWords)).WillOnce(Return(true));
EXPECT_CALL(*m_wakeWordsSenderMock, sendChangedEvent(wakeWordsJson)).WillOnce(InvokeWithoutArgs([] {
std::promise<bool> retPromise;
retPromise.set_value(true);
return retPromise.get_future();
}));
EXPECT_CALL(*m_localesSenderMock, sendChangedEvent(localeJson)).WillOnce(InvokeWithoutArgs([] {
std::promise<bool> retPromise;
retPromise.set_value(true);
return retPromise.get_future();
}));
std::condition_variable updatedCV;
bool wakeWordStateUpdated = false;
bool localeStateUpdated = false;
std::mutex statusMutex;
EXPECT_CALL(*m_storageMock, updateSettingStatus(WAKE_WORDS_KEY, SettingStatus::SYNCHRONIZED))
.WillOnce(InvokeWithoutArgs([&wakeWordStateUpdated, &statusMutex, &updatedCV] {
std::lock_guard<std::mutex> lock{statusMutex};
wakeWordStateUpdated = true;
updatedCV.notify_all();
return true;
}));
EXPECT_CALL(*m_storageMock, updateSettingStatus(LOCALES_KEY, SettingStatus::SYNCHRONIZED))
.WillOnce(InvokeWithoutArgs([&localeStateUpdated, &statusMutex, &updatedCV] {
std::lock_guard<std::mutex> lock{statusMutex};
localeStateUpdated = true;
updatedCV.notify_all();
return true;
}));
m_setting =
LocaleWakeWordsSetting::create(m_localesSenderMock, m_wakeWordsSenderMock, m_storageMock, m_assetsManagerMock);
ASSERT_THAT(m_setting, NotNull());
std::unique_lock<std::mutex> statusLock{statusMutex};
EXPECT_TRUE(updatedCV.wait_for(statusLock, MY_WAIT_TIMEOUT, [&wakeWordStateUpdated, &localeStateUpdated] {
return wakeWordStateUpdated && localeStateUpdated;
}));
EXPECT_EQ(static_cast<std::shared_ptr<LocalesSetting>>(m_setting)->get(), initialLocale);
EXPECT_EQ(static_cast<std::shared_ptr<WakeWordsSetting>>(m_setting)->get(), initialWakeWords);
}
/// Test success flow for local request for wake word change.
TEST_F(LocaleWakeWordsSettingTest, test_localChangeWakeWordsRequest) {
initializeSetting({ENGLISH_CANADA_VALUE}, WakeWordsSetting::ValueType({ALEXA_VALUE}));
WakeWordsSetting::ValueType newWakeWords{ALEXA_VALUE, ECHO_VALUE};
auto newWakeWordsJson = toJson({ALEXA_VALUE, ECHO_VALUE});
WaitEvent event;
EXPECT_CALL(
*m_storageMock,
storeSettings(convertToDBData(WAKE_WORDS_KEY, newWakeWordsJson, SettingStatus::LOCAL_CHANGE_IN_PROGRESS)))
.WillOnce(Return(true));
EXPECT_CALL(*m_wakeWordsObserver, onSettingNotification(_, SettingNotifications::LOCAL_CHANGE_IN_PROGRESS));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(ENGLISH_LOCALES, newWakeWords)).WillOnce(Return(true));
EXPECT_CALL(*m_wakeWordsObserver, onSettingNotification(newWakeWords, SettingNotifications::LOCAL_CHANGE));
EXPECT_CALL(*m_wakeWordsSenderMock, sendChangedEvent(newWakeWordsJson)).WillOnce(InvokeWithoutArgs([] {
std::promise<bool> retPromise;
retPromise.set_value(true);
return retPromise.get_future();
}));
EXPECT_CALL(*m_storageMock, updateSettingStatus(WAKE_WORDS_KEY, SettingStatus::SYNCHRONIZED))
.WillOnce(InvokeWithoutArgs([&event] {
event.wakeUp();
return true;
}));
m_setting->setLocalChange(newWakeWords);
EXPECT_TRUE(event.wait(MY_WAIT_TIMEOUT));
EXPECT_EQ(static_cast<std::shared_ptr<WakeWordsSetting>>(m_setting)->get(), newWakeWords);
}
/// Test set value failed during local request for wake word change.
TEST_F(LocaleWakeWordsSettingTest, test_localChangeWakeWordsRequestSetFailed) {
WakeWordsSetting::ValueType initialWakeWords{{ALEXA_VALUE}};
initializeSetting({ENGLISH_CANADA_VALUE}, initialWakeWords);
WakeWordsSetting::ValueType newWakeWords{ALEXA_VALUE, ECHO_VALUE};
auto initialWakeWordsJson = toJson({ALEXA_VALUE});
WaitEvent event;
EXPECT_CALL(*m_wakeWordsObserver, onSettingNotification(_, SettingNotifications::LOCAL_CHANGE_IN_PROGRESS));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(ENGLISH_LOCALES, newWakeWords)).WillOnce(Return(false));
EXPECT_CALL(
*m_wakeWordsObserver, onSettingNotification(initialWakeWords, SettingNotifications::LOCAL_CHANGE_FAILED))
.WillOnce(InvokeWithoutArgs([&event] { event.wakeUp(); }));
EXPECT_CALL(*m_storageMock, updateSettingStatus(WAKE_WORDS_KEY, SettingStatus::SYNCHRONIZED)).Times(0);
m_setting->setLocalChange(newWakeWords);
EXPECT_TRUE(event.wait(MY_WAIT_TIMEOUT));
EXPECT_EQ(static_cast<std::shared_ptr<WakeWordsSetting>>(m_setting)->get(), initialWakeWords);
}
/// TODO: Test send changed event failed while processing wake words local request.
TEST_F(LocaleWakeWordsSettingTest, test_localChangeWakeWordsRequestSendEventFailed) {
}
/// TODO: Test success flow for local request for wake word change.
TEST_F(LocaleWakeWordsSettingTest, test_localChangeLocaleRequest) {
}
/// TODO: Test set value failed during local request for wake word change.
TEST_F(LocaleWakeWordsSettingTest, test_localChangeLocaleRequestSetFailed) {
}
/// TODO: Test send changed event failed while processing wake words local request.
TEST_F(LocaleWakeWordsSettingTest, test_localChangeLocaleRequestSendEventFailed) {
}
/// TODO: Test locale change when current wake word is not available.
TEST_F(LocaleWakeWordsSettingTest, test_localeChangeTriggerWakeWordsChange) {
}
/// TODO: Test locale change when pending request has a wake word that's not available.
TEST_F(LocaleWakeWordsSettingTest, test_localeChangeCancelPendingWakeWordsChange) {
}
/// TODO: Test locale change when pending request has a valid wake word selected in the current locale.
TEST_F(LocaleWakeWordsSettingTest, test_localeChangeMergePendingWakeWordsChange) {
}
/// TODO: Test wake word change when current locale doesn't support requested wake word.
TEST_F(LocaleWakeWordsSettingTest, test_wakeWordChangeRequestFailedOnCurrentLocale) {
}
/// Test synchronization once the SDK is re-connected and there was an offline change.
TEST_F(LocaleWakeWordsSettingTest, test_reconnectAfterOfflineChange) {
WakeWordsSetting::ValueType wakeWords{ALEXA_VALUE};
initializeSetting({ENGLISH_CANADA_VALUE}, wakeWords);
LocalesSetting::ValueType newLocale{FRENCH_CANADA_VALUE};
auto newLocaleJson = toSettingString<DeviceLocales>({newLocale}).second;
// Set offline changes expectations.
WaitEvent event;
EXPECT_CALL(*m_storageMock, updateSettingStatus(LOCALES_KEY, SettingStatus::AVS_CHANGE_IN_PROGRESS))
.WillOnce(Return(true));
EXPECT_CALL(
*m_storageMock,
storeSettings(convertToDBData(LOCALES_KEY, newLocaleJson, SettingStatus::AVS_CHANGE_IN_PROGRESS)))
.WillOnce(Return(true));
EXPECT_CALL(*m_localeObserver, onSettingNotification(_, SettingNotifications::AVS_CHANGE_IN_PROGRESS));
EXPECT_CALL(*m_assetsManagerMock, changeAssets(newLocale, wakeWords)).WillOnce(Return(true));
EXPECT_CALL(*m_localeObserver, onSettingNotification(newLocale, SettingNotifications::AVS_CHANGE));
EXPECT_CALL(*m_localesSenderMock, sendReportEvent(newLocaleJson)).WillOnce(InvokeWithoutArgs([&] {
std::promise<bool> retPromise;
retPromise.set_value(false);
event.wakeUp();
return retPromise.get_future();
}));
// Trigger offline change.
m_setting->setAvsChange(newLocale);
ASSERT_TRUE(event.wait(MY_WAIT_TIMEOUT));
// Set reconnect expectations.
event.reset();
EXPECT_CALL(*m_localesSenderMock, sendReportEvent(newLocaleJson)).WillOnce(InvokeWithoutArgs([] {
std::promise<bool> retPromise;
retPromise.set_value(true);
return retPromise.get_future();
}));
EXPECT_CALL(*m_storageMock, updateSettingStatus(LOCALES_KEY, SettingStatus::SYNCHRONIZED))
.WillOnce(InvokeWithoutArgs([&event] {
event.wakeUp();
return true;
}));
m_setting->onConnectionStatusChanged(
ConnectionStatusObserverInterface::Status::CONNECTED,
ConnectionStatusObserverInterface::ChangedReason::SUCCESS);
ASSERT_TRUE(event.wait(MY_WAIT_TIMEOUT));
}
} // namespace test
} // namespace settings
} // namespace alexaClientSDK