SmartAudio/package/avs/avs-sdk/files/avs-device-sdk/Integration/test/AlertsIntegrationTest.cpp

1333 lines
60 KiB
C++
Raw Normal View History

2018-07-13 01:31:50 +00:00
/*
* 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.
*/
/// @file AlertsIntegrationTest.cpp
#include <chrono>
#include <deque>
#include <fstream>
#include <future>
#include <iostream>
#include <mutex>
#include <string>
#include <unordered_map>
#include <gtest/gtest.h>
#include <ADSL/DirectiveSequencer.h>
#include <ADSL/MessageInterpreter.h>
#include <AFML/FocusManager.h>
#include <AIP/AudioInputProcessor.h>
#include <AIP/AudioProvider.h>
#include <AIP/Initiator.h>
#include <Alerts/AlertObserverInterface.h>
#include <Alerts/AlertsCapabilityAgent.h>
#include <Alerts/Storage/SQLiteAlertStorage.h>
#include <Audio/AlertsAudioFactory.h>
#include <AVSCommon/AVS/Attachment/InProcessAttachmentReader.h>
#include <AVSCommon/AVS/Attachment/InProcessAttachmentWriter.h>
#include <AVSCommon/AVS/BlockingPolicy.h>
#include <AVSCommon/SDKInterfaces/DirectiveHandlerInterface.h>
#include <AVSCommon/SDKInterfaces/DirectiveHandlerResultInterface.h>
#include <AVSCommon/Utils/JSON/JSONUtils.h>
#include <AVSCommon/Utils/LibcurlUtils/HTTPContentFetcherFactory.h>
#include <AVSCommon/Utils/Logger/LogEntry.h>
#include <CertifiedSender/CertifiedSender.h>
#include <CertifiedSender/SQLiteMessageStorage.h>
#include <SpeechSynthesizer/SpeechSynthesizer.h>
#include <System/UserInactivityMonitor.h>
#include "Integration/ACLTestContext.h"
#include "Integration/ObservableMessageRequest.h"
#include "Integration/TestAlertObserver.h"
#include "Integration/TestDirectiveHandler.h"
#include "Integration/TestExceptionEncounteredSender.h"
#include "Integration/TestMessageSender.h"
#include "Integration/TestSpeechSynthesizerObserver.h"
#ifdef GSTREAMER_MEDIA_PLAYER
#include <MediaPlayer/MediaPlayer.h>
#else
#include "Integration/TestMediaPlayer.h"
#endif
namespace alexaClientSDK {
namespace integration {
namespace test {
using namespace acl;
using namespace adsl;
using namespace avsCommon;
using namespace avsCommon::avs;
using namespace avsCommon::avs::attachment;
using namespace avsCommon::sdkInterfaces;
using namespace avsCommon::utils::mediaPlayer;
using namespace certifiedSender;
using namespace sdkInterfaces;
using namespace avsCommon::utils::sds;
using namespace avsCommon::utils::json;
using namespace capabilityAgents::aip;
using namespace afml;
using namespace capabilityAgents::speechSynthesizer;
using namespace capabilityAgents::system;
#ifdef GSTREAMER_MEDIA_PLAYER
using namespace mediaPlayer;
#endif
// This is a 16 bit 16 kHz little endian linear PCM audio file of "Joke" to be recognized.
static const std::string RECOGNIZE_JOKE_AUDIO_FILE_NAME = "/recognize_joke_test.wav";
// This is a 16 bit 16 kHz little endian linear PCM audio file of "What's up" to be recognized.
static const std::string RECOGNIZE_WHATS_UP_AUDIO_FILE_NAME = "/recognize_whats_up_test.wav";
// This is a 16 bit 16 kHz little endian linear PCM audio file of "What's up" to be recognized.
static const std::string RECOGNIZE_WEATHER_AUDIO_FILE_NAME = "/recognize_weather_test.wav";
// This is a 16 bit 16 kHz little endian linear PCM audio file of "Set a timer for 5 seconds" to be recognized.
static const std::string RECOGNIZE_TIMER_AUDIO_FILE_NAME = "/recognize_timer_test.wav";
// This is a 16 bit 16 kHz little endian linear PCM audio file of "Set a timer for 10 seconds" to be recognized.
static const std::string RECOGNIZE_LONG_TIMER_AUDIO_FILE_NAME = "/recognize_long_timer_test.wav";
// This is a 16 bit 16 kHz little endian linear PCM audio file of "Set a timer for 15 seconds" to be recognized.
static const std::string RECOGNIZE_VERY_LONG_TIMER_AUDIO_FILE_NAME = "/recognize_very_long_timer_test.wav";
// This is a 16 bit 16 kHz little endian linear PCM audio file of "Stop" to be recognized.
static const std::string RECOGNIZE_STOP_AUDIO_FILE_NAME = "/recognize_stop_timer_test.wav";
// This is a 16 bit 16 kHz little endian linear PCM audio file of "Cancel the timer" to be recognized.
static const std::string RECOGNIZE_CANCEL_TIMER_AUDIO_FILE_NAME = "/recognize_cancel_timer_test.wav";
// This string to be used for Speak Directives which use the NAMESPACE_SPEECH_SYNTHESIZER namespace.
static const std::string NAME_RECOGNIZE = "Recognize";
// This string to be used for SetAlertFailed Directives which use the NAMESPACE_ALERTS namespace.
static const std::string NAME_SET_ALERT_FAILED = "SetAlertFailed";
// This string to be used for AlertStopped Directives which use the NAMESPACE_ALERTS namespace.
static const std::string NAME_ALERT_STOPPED = "AlertStopped";
// This string to be used for AlertEnteredBackground Directives which use the NAMESPACE_ALERTS namespace.
static const std::string NAME_ALERT_ENTERED_BACKGROUND = "AlertEnteredBackground";
// This string to be used for AlertEnteredForeground Directives which use the NAMESPACE_ALERTS namespace.
static const std::string NAME_ALERT_ENTERED_FOREGROUND = "AlertEnteredForeground";
// This string to be used for DeleteAlertSucceeded Directives which use the NAMESPACE_ALERTS namespace.
static const std::string NAME_DELETE_ALERT_SUCCEEDED = "DeleteAlertSucceeded";
// This string to be used for DeleteAlertFailed Directives which use the NAMESPACE_ALERTS namespace.
static const std::string NAME_DELETE_ALERT_FAILED = "DeleteAlertFailed";
// This string to be used for AlertStarted Directives which use the NAMESPACE_ALERTS namespace.
static const std::string NAME_ALERT_STARTED = "AlertStarted";
// This string to be used for SpeechStarted Directives which use the NAMESPACE_SPEECH_SYNTHESIZER namespace.
static const std::string NAME_SPEECH_STARTED = "SpeechStarted";
// This string to be used for SpeechFinished Directives which use the NAMESPACE_SPEECH_SYNTHESIZER namespace.
static const std::string NAME_SPEECH_FINISHED = "SpeechFinished";
// This string to be used for AlertStarted Directives which use the NAMESPACE_ALERTS namespace.
static const std::string NAME_SET_ALERT_SUCCEEDED = "SetAlertSucceeded";
// Sample dialog activity id.
static const std::string DIALOG_ACTIVITY_ID = "Dialog";
// Sample content activity id.
static const std::string CONTENT_ACTIVITY_ID = "Content";
/// Sample alerts activity id.
static const std::string ALERTS_ACTIVITY_ID = "Alerts";
// This Integer to be used to specify a timeout in seconds.
static const std::chrono::seconds WAIT_FOR_TIMEOUT_DURATION(25);
// This Integer to be used to specify a short timeout in seconds.
static const std::chrono::seconds SHORT_TIMEOUT_DURATION(5);
/// The compatible encoding for AIP.
static const avsCommon::utils::AudioFormat::Encoding COMPATIBLE_ENCODING =
avsCommon::utils::AudioFormat::Encoding::LPCM;
/// The compatible endianness for AIP.
static const avsCommon::utils::AudioFormat::Endianness COMPATIBLE_ENDIANNESS =
avsCommon::utils::AudioFormat::Endianness::LITTLE;
/// The compatible sample rate for AIP.
static const unsigned int COMPATIBLE_SAMPLE_RATE = 16000;
/// The compatible bits per sample for Kitt.ai.
static const unsigned int COMPATIBLE_SAMPLE_SIZE_IN_BITS = 16;
/// The compatible number of channels for Kitt.ai
static const unsigned int COMPATIBLE_NUM_CHANNELS = 1;
/// JSON key to get the event object of a message.
static const std::string JSON_MESSAGE_EVENT_KEY = "event";
/// JSON key to get the directive object of a message.
static const std::string JSON_MESSAGE_DIRECTIVE_KEY = "directive";
/// JSON key to get the header object of a message.
static const std::string JSON_MESSAGE_HEADER_KEY = "header";
/// JSON key to get the namespace value of a header.
static const std::string JSON_MESSAGE_NAMESPACE_KEY = "namespace";
/// JSON key to get the name value of a header.
static const std::string JSON_MESSAGE_NAME_KEY = "name";
/// JSON key to get the messageId value of a header.
static const std::string JSON_MESSAGE_MESSAGE_ID_KEY = "messageId";
/// JSON key to get the dialogRequestId value of a header.
static const std::string JSON_MESSAGE_DIALOG_REQUEST_ID_KEY = "dialogRequestId";
/// JSON key to get the payload object of a message.
static const std::string JSON_MESSAGE_PAYLOAD_KEY = "payload";
/// String to identify log entries originating from this file.
static const std::string TAG("AlertsIntegrationTest");
/**
* 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)
/// Path to the AlexaClientSDKConfig.json file (from command line arguments).
static std::string g_configPath;
/// Path to resources (e.g. audio files) for tests (from command line arguments).
static std::string g_inputPath;
/// A test observer that mocks out the ChannelObserverInterface##onFocusChanged() call.
class TestClient : public ChannelObserverInterface {
public:
/**
* Constructor.
*/
TestClient() : m_focusState(FocusState::NONE), m_focusChangeOccurred(false) {
}
/**
* Implementation of the ChannelObserverInterface##onFocusChanged() callback.
*
* @param focusState The new focus state of the Channel observer.
*/
void onFocusChanged(FocusState focusState) override {
std::unique_lock<std::mutex> lock(m_mutex);
m_focusState = focusState;
m_focusChangeOccurred = true;
m_focusChangedCV.notify_one();
}
/**
* Waits for the ChannelObserverInterface##onFocusChanged() callback.
*
* @param timeout The amount of time to wait for the callback.
* @param focusChanged An output parameter that notifies the caller whether a callback occurred.
* @return Returns @c true if the callback occured within the timeout period and @c false otherwise.
*/
FocusState waitForFocusChange(std::chrono::milliseconds timeout, bool* focusChanged) {
std::unique_lock<std::mutex> lock(m_mutex);
bool success = m_focusChangedCV.wait_for(lock, timeout, [this]() { return m_focusChangeOccurred; });
if (!success) {
*focusChanged = false;
} else {
m_focusChangeOccurred = false;
*focusChanged = true;
}
return m_focusState;
}
private:
/// The focus state of the observer.
FocusState m_focusState;
/// A lock to guard against focus state changes.
std::mutex m_mutex;
/// A condition variable to wait for focus changes.
std::condition_variable m_focusChangedCV;
/// A boolean flag so that we can re-use the observer even after a callback has occurred.
bool m_focusChangeOccurred;
};
class holdToTalkButton {
public:
bool startRecognizing(std::shared_ptr<AudioInputProcessor> aip, std::shared_ptr<AudioProvider> audioProvider) {
return aip->recognize(*audioProvider, Initiator::PRESS_AND_HOLD).get();
}
bool stopRecognizing(std::shared_ptr<AudioInputProcessor> aip) {
return aip->stopCapture().get();
}
};
class AlertsTest : public ::testing::Test {
protected:
virtual void SetUp() override {
m_context = ACLTestContext::create(g_configPath);
ASSERT_TRUE(m_context);
m_exceptionEncounteredSender = std::make_shared<TestExceptionEncounteredSender>();
m_dialogUXStateAggregator = std::make_shared<avsCommon::avs::DialogUXStateAggregator>();
m_directiveSequencer = DirectiveSequencer::create(m_exceptionEncounteredSender);
m_messageInterpreter = std::make_shared<MessageInterpreter>(
m_exceptionEncounteredSender, m_directiveSequencer, m_context->getAttachmentManager());
// Set up connection and connect
m_avsConnectionManager = std::make_shared<TestMessageSender>(
m_context->getMessageRouter(), false, m_context->getConnectionStatusObserver(), m_messageInterpreter);
ASSERT_TRUE(m_avsConnectionManager);
m_focusManager = std::make_shared<FocusManager>(FocusManager::DEFAULT_AUDIO_CHANNELS);
m_testContentClient = std::make_shared<TestClient>();
ASSERT_TRUE(m_focusManager->acquireChannel(
FocusManager::CONTENT_CHANNEL_NAME, m_testContentClient, CONTENT_ACTIVITY_ID));
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
ASSERT_TRUE(focusChanged);
m_testDialogClient = std::make_shared<TestClient>();
#ifdef GSTREAMER_MEDIA_PLAYER
m_speakMediaPlayer =
MediaPlayer::create(std::make_shared<avsCommon::utils::libcurlUtils::HTTPContentFetcherFactory>());
#else
m_speakMediaPlayer = std::make_shared<TestMediaPlayer>();
#endif
m_compatibleAudioFormat.sampleRateHz = COMPATIBLE_SAMPLE_RATE;
m_compatibleAudioFormat.sampleSizeInBits = COMPATIBLE_SAMPLE_SIZE_IN_BITS;
m_compatibleAudioFormat.numChannels = COMPATIBLE_NUM_CHANNELS;
m_compatibleAudioFormat.endianness = COMPATIBLE_ENDIANNESS;
m_compatibleAudioFormat.encoding = COMPATIBLE_ENCODING;
size_t nWords = 1024 * 1024;
size_t wordSize = 2;
size_t maxReaders = 3;
size_t bufferSize = AudioInputStream::calculateBufferSize(nWords, wordSize, maxReaders);
auto m_Buffer = std::make_shared<avsCommon::avs::AudioInputStream::Buffer>(bufferSize);
auto m_Sds = avsCommon::avs::AudioInputStream::create(m_Buffer, wordSize, maxReaders);
ASSERT_NE(nullptr, m_Sds);
m_AudioBuffer = std::move(m_Sds);
m_AudioBufferWriter =
m_AudioBuffer->createWriter(avsCommon::avs::AudioInputStream::Writer::Policy::NONBLOCKABLE);
ASSERT_NE(nullptr, m_AudioBufferWriter);
// Set up hold to talk button.
bool alwaysReadable = true;
bool canOverride = true;
bool canBeOverridden = true;
m_HoldToTalkAudioProvider = std::make_shared<AudioProvider>(
m_AudioBuffer,
m_compatibleAudioFormat,
ASRProfile::CLOSE_TALK,
!alwaysReadable,
canOverride,
!canBeOverridden);
m_holdToTalkButton = std::make_shared<holdToTalkButton>();
m_userInactivityMonitor = UserInactivityMonitor::create(m_avsConnectionManager, m_exceptionEncounteredSender);
m_AudioInputProcessor = AudioInputProcessor::create(
m_directiveSequencer,
m_avsConnectionManager,
m_context->getContextManager(),
m_focusManager,
m_dialogUXStateAggregator,
m_exceptionEncounteredSender,
m_userInactivityMonitor);
ASSERT_NE(nullptr, m_AudioInputProcessor);
m_AudioInputProcessor->addObserver(m_dialogUXStateAggregator);
// Create and register the SpeechSynthesizer.
m_speechSynthesizer = SpeechSynthesizer::create(
m_speakMediaPlayer,
m_avsConnectionManager,
m_focusManager,
m_context->getContextManager(),
m_exceptionEncounteredSender,
m_dialogUXStateAggregator);
ASSERT_NE(nullptr, m_speechSynthesizer);
m_directiveSequencer->addDirectiveHandler(m_speechSynthesizer);
m_speechSynthesizerObserver = std::make_shared<TestSpeechSynthesizerObserver>();
m_speechSynthesizer->addObserver(m_speechSynthesizerObserver);
m_speechSynthesizer->addObserver(m_dialogUXStateAggregator);
#ifdef GSTREAMER_MEDIA_PLAYER
m_rendererMediaPlayer = MediaPlayer::create(nullptr);
#else
m_rendererMediaPlayer = std::make_shared<TestMediaPlayer>();
#endif
m_alertRenderer = renderer::Renderer::create(m_rendererMediaPlayer);
auto alertsAudioFactory = std::make_shared<applicationUtilities::resources::audio::AlertsAudioFactory>();
m_alertStorage = capabilityAgents::alerts::storage::SQLiteAlertStorage::create(
avsCommon::utils::configuration::ConfigurationNode::getRoot(), alertsAudioFactory);
m_alertObserver = std::make_shared<TestAlertObserver>();
auto messageStorage =
SQLiteMessageStorage::create(avsCommon::utils::configuration::ConfigurationNode::getRoot());
m_customerDataManager = std::make_shared<registrationManager::CustomerDataManager>();
m_certifiedSender = CertifiedSender::create(
m_avsConnectionManager,
m_avsConnectionManager->getConnectionManager(),
std::move(messageStorage),
m_customerDataManager);
m_alertsAgent = AlertsCapabilityAgent::create(
m_avsConnectionManager,
m_certifiedSender,
m_focusManager,
m_context->getContextManager(),
m_exceptionEncounteredSender,
m_alertStorage,
alertsAudioFactory,
m_alertRenderer,
m_customerDataManager);
ASSERT_NE(m_alertsAgent, nullptr);
m_alertsAgent->addObserver(m_alertObserver);
m_alertsAgent->onLocalStop();
m_alertsAgent->removeAllAlerts();
m_directiveSequencer->addDirectiveHandler(m_alertsAgent);
m_avsConnectionManager->addConnectionStatusObserver(m_alertsAgent);
connect();
}
void TearDown() override {
disconnect();
// Note that these nullptr checks are needed to avoid segaults if @c SetUp() failed.
if (m_AudioInputProcessor) {
m_AudioInputProcessor->shutdown();
}
if (m_directiveSequencer) {
m_directiveSequencer->shutdown();
}
if (m_speechSynthesizer) {
m_speechSynthesizer->shutdown();
}
if (m_alertsAgent) {
m_alertsAgent->onLocalStop();
m_alertsAgent->removeAllAlerts();
m_alertsAgent->shutdown();
}
if (m_certifiedSender) {
m_certifiedSender->shutdown();
}
if (m_avsConnectionManager) {
m_avsConnectionManager->shutdown();
}
m_context.reset();
#ifdef GSTREAMER_MEDIA_PLAYER
if (m_speakMediaPlayer) {
m_speakMediaPlayer->shutdown();
}
if (m_rendererMediaPlayer) {
m_rendererMediaPlayer->shutdown();
}
#endif
if (m_userInactivityMonitor) {
m_userInactivityMonitor->shutdown();
}
}
/**
* Connect to AVS.
*/
void connect() {
m_avsConnectionManager->enable();
m_context->waitForConnected();
}
/**
* Disconnect from AVS.
*/
void disconnect() {
if (m_avsConnectionManager) {
m_avsConnectionManager->disable();
m_context->waitForDisconnected();
}
}
std::string getSentEventName(TestMessageSender::SendParams sendParams) {
std::string eventString;
std::string eventHeader;
std::string eventName;
jsonUtils::retrieveValue(sendParams.request->getJsonContent(), JSON_MESSAGE_EVENT_KEY, &eventString);
jsonUtils::retrieveValue(eventString, JSON_MESSAGE_HEADER_KEY, &eventHeader);
jsonUtils::retrieveValue(eventHeader, JSON_MESSAGE_NAME_KEY, &eventName);
return eventName;
}
bool checkSentEventName(TestMessageSender::SendParams sendParams, std::string expectedName) {
if (TestMessageSender::SendParams::Type::SEND == sendParams.type) {
std::string eventName;
eventName = getSentEventName(sendParams);
return eventName == expectedName;
}
return false;
}
std::vector<int16_t> readAudioFromFile(const std::string& fileName, bool* errorOccurred) {
const int RIFF_HEADER_SIZE = 44;
std::ifstream inputFile(fileName.c_str(), std::ifstream::binary);
if (!inputFile.good()) {
std::cout << "Couldn't open audio file!" << std::endl;
if (errorOccurred) {
*errorOccurred = true;
}
return {};
}
inputFile.seekg(0, std::ios::end);
int fileLengthInBytes = inputFile.tellg();
if (fileLengthInBytes <= RIFF_HEADER_SIZE) {
std::cout << "File should be larger than 44 bytes, which is the size of the RIFF header" << std::endl;
if (errorOccurred) {
*errorOccurred = true;
}
return {};
}
inputFile.seekg(RIFF_HEADER_SIZE, std::ios::beg);
int numSamples = (fileLengthInBytes - RIFF_HEADER_SIZE) / 2;
std::vector<int16_t> retVal(numSamples, 0);
inputFile.read((char*)&retVal[0], numSamples * 2);
if (inputFile.gcount() != numSamples * 2) {
std::cout << "Error reading audio file" << std::endl;
if (errorOccurred) {
*errorOccurred = true;
}
return {};
}
inputFile.close();
if (errorOccurred) {
*errorOccurred = false;
}
return retVal;
}
void sendAudioFileAsRecognize(std::string audioFile) {
// Signal to the AIP to start recognizing.
ASSERT_NE(nullptr, m_HoldToTalkAudioProvider);
ASSERT_TRUE(m_holdToTalkButton->startRecognizing(m_AudioInputProcessor, m_HoldToTalkAudioProvider));
// Put audio onto the SDS saying "Tell me a joke".
bool error = false;
std::string file = g_inputPath + audioFile;
std::vector<int16_t> audioData = readAudioFromFile(file, &error);
ASSERT_FALSE(error);
ASSERT_FALSE(audioData.empty());
m_AudioBufferWriter->write(audioData.data(), audioData.size());
// Stop holding the button.
ASSERT_TRUE(m_holdToTalkButton->stopRecognizing(m_AudioInputProcessor));
}
/// Context for running ACL based tests.
std::unique_ptr<ACLTestContext> m_context;
std::shared_ptr<TestMessageSender> m_avsConnectionManager;
std::shared_ptr<CertifiedSender> m_certifiedSender;
std::shared_ptr<TestExceptionEncounteredSender> m_exceptionEncounteredSender;
std::shared_ptr<TestDirectiveHandler> m_directiveHandler;
std::shared_ptr<DirectiveSequencerInterface> m_directiveSequencer;
std::shared_ptr<MessageInterpreter> m_messageInterpreter;
std::shared_ptr<FocusManager> m_focusManager;
std::shared_ptr<TestClient> m_testContentClient;
std::shared_ptr<TestClient> m_testDialogClient;
std::shared_ptr<TestAlertObserver> m_AlertsAgentObserver;
std::shared_ptr<SpeechSynthesizer> m_speechSynthesizer;
std::shared_ptr<AlertsCapabilityAgent> m_alertsAgent;
std::shared_ptr<TestSpeechSynthesizerObserver> m_speechSynthesizerObserver;
std::shared_ptr<capabilityAgents::alerts::storage::SQLiteAlertStorage> m_alertStorage;
std::shared_ptr<renderer::RendererInterface> m_alertRenderer;
std::shared_ptr<TestAlertObserver> m_alertObserver;
std::shared_ptr<holdToTalkButton> m_holdToTalkButton;
std::shared_ptr<AudioProvider> m_HoldToTalkAudioProvider;
avsCommon::utils::AudioFormat m_compatibleAudioFormat;
std::unique_ptr<AudioInputStream::Writer> m_AudioBufferWriter;
std::shared_ptr<AudioInputStream> m_AudioBuffer;
std::shared_ptr<AudioInputProcessor> m_AudioInputProcessor;
std::shared_ptr<UserInactivityMonitor> m_userInactivityMonitor;
std::shared_ptr<registrationManager::CustomerDataManager> m_customerDataManager;
FocusState m_focusState;
std::mutex m_mutex;
std::condition_variable m_focusChangedCV;
bool m_focusChangeOccurred;
std::shared_ptr<avsCommon::avs::DialogUXStateAggregator> m_dialogUXStateAggregator;
#ifdef GSTREAMER_MEDIA_PLAYER
std::shared_ptr<MediaPlayer> m_speakMediaPlayer;
std::shared_ptr<MediaPlayer> m_rendererMediaPlayer;
#else
std::shared_ptr<TestMediaPlayer> m_speakMediaPlayer;
std::shared_ptr<TestMediaPlayer> m_rendererMediaPlayer;
#endif
};
/**
* Test when one timer is stopped locally
*
* Set a 5 second timer, ensure it goes off, then use local stop and make sure the timer is stopped.
*/
TEST_F(AlertsTest, handleOneTimerWithLocalStop) {
// Write audio to SDS saying "Set a timer for 5 seconds"
sendAudioFileAsRecognize(RECOGNIZE_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// SetAlertSucceeded Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
ASSERT_EQ(m_alertObserver->waitForNext(WAIT_FOR_TIMEOUT_DURATION).state, AlertObserverInterface::State::READY);
// AlertStarted Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
ASSERT_EQ(m_alertObserver->waitForNext(WAIT_FOR_TIMEOUT_DURATION).state, AlertObserverInterface::State::STARTED);
// The test channel client has been notified the content channel has been backgrounded.
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
// Locally stop the alarm.
m_alertsAgent->onLocalStop();
ASSERT_EQ(m_alertObserver->waitForNext(WAIT_FOR_TIMEOUT_DURATION).state, AlertObserverInterface::State::STOPPED);
// AlertStopped Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STOPPED));
// Low priority Test client gets back permission to the test channel
EXPECT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
EXPECT_TRUE(focusChanged);
}
/**
* Test when one timer is stopped verbally
*
* Set two second timer, ensure they go off, then stop both timers.
*/
TEST_F(AlertsTest, handleMultipleTimersWithLocalStop) {
// Write audio to SDS saying "Set a timer for 15 seconds".
sendAudioFileAsRecognize(RECOGNIZE_VERY_LONG_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// The test channel client has been notified the content channel has been backgrounded.
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
ASSERT_TRUE(focusChanged);
// Write audio to SDS saying "Set a timer for 5 seconds".
sendAudioFileAsRecognize(RECOGNIZE_TIMER_AUDIO_FILE_NAME);
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
ASSERT_TRUE(focusChanged);
// SetAlertSucceeded Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
// Speech is handled.
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// SetAlertSucceeded Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
// AlertStarted Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
// The test channel client has been notified the content channel has been backgrounded.
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
// Locally stop the alarm.
m_focusManager->stopForegroundActivity();
// AlertStopped Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STOPPED));
// AlertStarted Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
// The test channel client has been notified the content channel has been backgrounded.
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
std::this_thread::sleep_for(std::chrono::milliseconds(600));
// Locally stop the second alarm.
m_focusManager->stopForegroundActivity();
// AlertStopped Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STOPPED));
// Low priority Test client gets back permission to the test channel.
EXPECT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
EXPECT_TRUE(focusChanged);
}
/**
* Test when the Alerts channel is acqired by a different client when an alert is active
*
* Set a 5 second timer, ensure it goes off, then have a test client acquire the Alerts channel. Ensure that the alert
* is stopped.
*/
TEST_F(AlertsTest, stealChannelFromActiveAlert) {
// Write audio to SDS saying "Set a timer for 5 seconds"
sendAudioFileAsRecognize(RECOGNIZE_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// SetAlertSucceeded Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
// AlertStarted Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
ASSERT_EQ(m_alertObserver->waitForNext(WAIT_FOR_TIMEOUT_DURATION).state, AlertObserverInterface::State::READY);
ASSERT_EQ(m_alertObserver->waitForNext(WAIT_FOR_TIMEOUT_DURATION).state, AlertObserverInterface::State::STARTED);
// The test channel client has been notified the content channel has been backgrounded.
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
// Steal the alerts channel.
ASSERT_TRUE(
m_focusManager->acquireChannel(FocusManager::ALERTS_CHANNEL_NAME, m_testDialogClient, ALERTS_ACTIVITY_ID));
// AlertStopped Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STOPPED));
ASSERT_EQ(m_alertObserver->waitForNext(WAIT_FOR_TIMEOUT_DURATION).state, AlertObserverInterface::State::STOPPED);
// Release the alerts channel.
m_focusManager->releaseChannel(FocusManager::ALERTS_CHANNEL_NAME, m_testDialogClient);
// Low priority Test client gets back permission to the test channel.
EXPECT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
EXPECT_TRUE(focusChanged);
}
/**
* Test when a disconnect and reconnect happens while an alert is active
*
* Set a 5 second timer, then call disconnect, wait for the alert to become active and reconnect.
* Locally stop the alert and ensure AlertStopped is sent.
*/
TEST_F(AlertsTest, DisconnectAndReconnectBeforeLocalStop) {
// Write audio to SDS saying "Set a timer for 5 seconds"
sendAudioFileAsRecognize(RECOGNIZE_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// SetAlertSucceeded Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
// allow time for the certified sender to send the message ok.
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
disconnect();
// Wait for the alarm to go off.
std::this_thread::sleep_for(std::chrono::milliseconds(6000));
// The test channel client has been notified the content channel has been backgrounded.
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
connect();
// allow time for the other components to become aware of the connection status change.
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
// Locally stop the alarm.
m_alertsAgent->onLocalStop();
// AlertStarted Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
// AlertStopped Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STOPPED));
// Low priority Test client gets back permission to the test channel
EXPECT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
EXPECT_TRUE(focusChanged);
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged);
ASSERT_FALSE(focusChanged);
}
/**
* Test when a disconnect and reconnect happens before an alert is active
*
* Set a 5 second timer, then call disconnect then reconnect. Once the alert is active, locally stop the alert
* and ensure AlertStopped is sent.
*/
TEST_F(AlertsTest, DisconnectAndReconnect) {
// Write audio to SDS saying "Set a timer for 5 seconds"
sendAudioFileAsRecognize(RECOGNIZE_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// SetAlertSucceeded Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
disconnect();
// Wait for the alarm to go off.
std::this_thread::sleep_for(std::chrono::milliseconds(6000));
// The test channel client has been notified the content channel has been backgrounded.
bool focusChanged = false;
EXPECT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
EXPECT_TRUE(focusChanged);
// Locally stop the alarm.
m_alertsAgent->onLocalStop();
connect();
// AlertStopped Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_FALSE(checkSentEventName(sendParams, NAME_ALERT_STOPPED));
// Low priority Test client gets back permission to the test channel
EXPECT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
EXPECT_TRUE(focusChanged);
}
/**
* Test when all alerts are cleared from storage before an alert is active
*
* Set a 5 second timer, then call removeAllAlerts. Wait and ensure that the alert does not become active and no
* events are sent for it.
*/
TEST_F(AlertsTest, RemoveAllAlertsBeforeAlertIsActive) {
// Write audio to SDS saying "Set a timer for 5 seconds"
sendAudioFileAsRecognize(RECOGNIZE_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
bool focusChanged = false;
FocusState state;
state = m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged);
ASSERT_TRUE(focusChanged);
ASSERT_EQ(state, FocusState::BACKGROUND);
state = m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged);
ASSERT_TRUE(focusChanged);
ASSERT_EQ(state, FocusState::FOREGROUND);
// SetAlertSucceeded Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
// Remove all alerts.
m_alertsAgent->removeAllAlerts();
// AlertStarted Event is not sent.
sendParams = m_avsConnectionManager->waitForNext(SHORT_TIMEOUT_DURATION);
ASSERT_FALSE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
// AlertStopped Event is not sent.
sendParams = m_avsConnectionManager->waitForNext(SHORT_TIMEOUT_DURATION);
ASSERT_FALSE(checkSentEventName(sendParams, NAME_ALERT_STOPPED));
// Focus has not changed.
focusChanged = false;
state = m_testContentClient->waitForFocusChange(SHORT_TIMEOUT_DURATION, &focusChanged);
ASSERT_FALSE(focusChanged);
ASSERT_EQ(state, FocusState::FOREGROUND);
}
/**
* Test when an alert is canceled before it is due
*
* Set a 10 second timer, then send audio of "Cancel the timer" as a recognize event. Ensure the timer does not go off
* and the DeleteAlertSucceeded event is sent.
*/
TEST_F(AlertsTest, cancelAlertBeforeItIsActive) {
// Write audio to SDS saying "Set a timer for 10 seconds"
sendAudioFileAsRecognize(RECOGNIZE_LONG_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// SetAlertSucceeded Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
// Write audio to SDS sying "Cancel the timer"
sendAudioFileAsRecognize(RECOGNIZE_CANCEL_TIMER_AUDIO_FILE_NAME);
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// DeleteAlertSucceeded Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_DELETE_ALERT_SUCCEEDED));
// Speech is handled.
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// Low priority Test client gets back permission to the test channel.
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
// AlertStarted Event is not sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_FALSE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
}
/**
* Test when the storage is removed before an alert is set
*
* Close the storage before asking for a 5 second timer. SetAlertFailed and DeleteAlertFailed events are then sent.
*/
TEST_F(AlertsTest, RemoveStorageBeforeAlarmIsSet) {
m_alertStorage->close();
// Write audio to SDS saying "Set a timer for 5 seconds"
sendAudioFileAsRecognize(RECOGNIZE_LONG_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
ASSERT_TRUE(focusChanged);
// SetAlertFailed Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_FAILED));
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
if (checkSentEventName(sendParams, NAME_SPEECH_STARTED)) {
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
if (checkSentEventName(sendParams, NAME_SPEECH_FINISHED)) {
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
}
}
// DeleteAlertFailed is sent.
ASSERT_TRUE(checkSentEventName(sendParams, NAME_DELETE_ALERT_FAILED));
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
// Low priority Test client gets back permission to the test channel.
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
ASSERT_TRUE(focusChanged);
}
/**
* Test when an alert is active and the user barges in and gets one speak in response
*
* Set a 5 second timer and wait until it is active. Send a recognize event asking for joke and see that the alert goes
* into the background. When the speak is complete, the alert is forgrounded and can be locally stopped.
*/
TEST_F(AlertsTest, UserShortUnrelatedBargeInOnActiveTimer) {
// Write audio to SDS saying "Set a timer for 5 seconds"
sendAudioFileAsRecognize(RECOGNIZE_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// SetAlertSucceeded Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
// AlertStarted Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
// The test channel client has been notified the content channel has been backgrounded.
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
// Write audio to SDS sying "Tell me a joke"
sendAudioFileAsRecognize(RECOGNIZE_JOKE_AUDIO_FILE_NAME);
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
if (getSentEventName(sendParams) == NAME_ALERT_ENTERED_BACKGROUND) {
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
} else {
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_ENTERED_BACKGROUND));
}
// Speech is handled.
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_ENTERED_FOREGROUND));
std::this_thread::sleep_for(std::chrono::milliseconds(600));
// Locally stop the alarm.
m_alertsAgent->onLocalStop();
// AlertStopped Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
EXPECT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STOPPED));
// Low priority Test client gets back permission to the test channel
EXPECT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
EXPECT_TRUE(focusChanged);
}
/**
* Test when an alert is active and the user barges in and gets multiple speaks in response
*
* Set a 5 second timer and wait until it is active. Send a recognize event asking "what's up" and see that the alert
* goes into the background. When all the speaks are complete, the alert is forgrounded and can be locally stopped.
*/
TEST_F(AlertsTest, DISABLED_UserLongUnrelatedBargeInOnActiveTimer) {
// Write audio to SDS saying "Set a timer for 5 seconds"
sendAudioFileAsRecognize(RECOGNIZE_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// SetAlertSucceeded Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
// Wait for the alarm to go off.
std::this_thread::sleep_for(std::chrono::milliseconds(6000));
// AlertStarted Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
// The test channel client has been notified the content channel has been backgrounded.
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
// Write audio to SDS sying "What's up"
sendAudioFileAsRecognize(RECOGNIZE_WHATS_UP_AUDIO_FILE_NAME);
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
if (getSentEventName(sendParams) == NAME_ALERT_ENTERED_BACKGROUND) {
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
EXPECT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
} else {
EXPECT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_ENTERED_BACKGROUND));
}
// Speech is handled.
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_FINISHED));
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_ALERT_ENTERED_FOREGROUND));
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_ALERT_ENTERED_BACKGROUND));
while (checkSentEventName(sendStartedParams, NAME_ALERT_ENTERED_BACKGROUND)) {
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_FINISHED));
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_ALERT_ENTERED_FOREGROUND));
sendStartedParams = m_avsConnectionManager->waitForNext(SHORT_TIMEOUT_DURATION);
}
std::this_thread::sleep_for(std::chrono::milliseconds(600));
// Locally stop the alarm.
m_alertsAgent->onLocalStop();
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_ALERT_STOPPED));
// Low priority Test client gets back permission to the test channel
EXPECT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
EXPECT_TRUE(focusChanged);
}
/**
* Test when the user is speaking to Alexa and an alert becomes active
*
* Set a 5 second timer then start a recognize event using a hold to talk initiator but do not call stopCapture until
* the alert has become active in the background. Once the alert is active, call stopCapture and see that is is in the
* foreground before locally stopping it.
*/
TEST_F(AlertsTest, UserSpeakingWhenAlertShouldBeActive) {
// Write audio to SDS saying "Set a timer for 10 seconds"
sendAudioFileAsRecognize(RECOGNIZE_LONG_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// Speech is handled.
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// SetAlertSucceeded Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
// Signal to the AIP to start recognizing.
ASSERT_NE(nullptr, m_HoldToTalkAudioProvider);
ASSERT_TRUE(m_holdToTalkButton->startRecognizing(m_AudioInputProcessor, m_HoldToTalkAudioProvider));
// Put audio onto the SDS saying "Tell me a joke".
bool error = false;
std::string file = g_inputPath + RECOGNIZE_WEATHER_AUDIO_FILE_NAME;
std::vector<int16_t> audioData = readAudioFromFile(file, &error);
ASSERT_FALSE(error);
ASSERT_FALSE(audioData.empty());
m_AudioBufferWriter->write(audioData.data(), audioData.size());
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
// The test channel client has been notified the content channel has been backgrounded.
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
// AlertStarted Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
// Stop holding the button.
ASSERT_TRUE(m_holdToTalkButton->stopRecognizing(m_AudioInputProcessor));
// Speech is handled.
sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
if (getSentEventName(sendParams) == NAME_SPEECH_FINISHED) {
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_ENTERED_FOREGROUND));
} else {
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
}
std::this_thread::sleep_for(std::chrono::milliseconds(800));
// Locally stop the alarm.
m_alertsAgent->onLocalStop();
// Low priority Test client gets back permission to the test channel
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
ASSERT_TRUE(focusChanged);
}
TEST_F(AlertsTest, handleOneTimerWithVocalStop) {
// Write audio to SDS saying "Set a timer for 5 seconds"
sendAudioFileAsRecognize(RECOGNIZE_TIMER_AUDIO_FILE_NAME);
TestMessageSender::SendParams sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
TestMessageSender::SendParams sendStartedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendStartedParams, NAME_SPEECH_STARTED));
// SpeechFinished is sent here.
TestMessageSender::SendParams sendFinishedParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendFinishedParams, NAME_SPEECH_FINISHED));
// SetAlertSucceeded Event is sent
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_SET_ALERT_SUCCEEDED));
// AlertStarted Event is sent.
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STARTED));
ASSERT_EQ(m_alertObserver->waitForNext(WAIT_FOR_TIMEOUT_DURATION).state, AlertObserverInterface::State::READY);
ASSERT_EQ(m_alertObserver->waitForNext(WAIT_FOR_TIMEOUT_DURATION).state, AlertObserverInterface::State::STARTED);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
// The test channel client has been notified the content channel has been backgrounded.
bool focusChanged = false;
ASSERT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::BACKGROUND);
ASSERT_TRUE(focusChanged);
// Write audio to SDS sying "Stop"
sendAudioFileAsRecognize(RECOGNIZE_STOP_AUDIO_FILE_NAME);
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
if (getSentEventName(sendParams) == NAME_ALERT_ENTERED_BACKGROUND) {
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
EXPECT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
} else {
EXPECT_TRUE(checkSentEventName(sendParams, NAME_RECOGNIZE));
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_ENTERED_BACKGROUND));
}
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_DELETE_ALERT_SUCCEEDED));
sendParams = m_avsConnectionManager->waitForNext(WAIT_FOR_TIMEOUT_DURATION);
ASSERT_TRUE(checkSentEventName(sendParams, NAME_ALERT_STOPPED));
ASSERT_EQ(
m_alertObserver->waitForNext(WAIT_FOR_TIMEOUT_DURATION).state,
AlertObserverInterface::State::FOCUS_ENTERED_BACKGROUND);
ASSERT_EQ(m_alertObserver->waitForNext(WAIT_FOR_TIMEOUT_DURATION).state, AlertObserverInterface::State::STOPPED);
// Low priority Test client gets back permission to the test channel
EXPECT_EQ(
m_testContentClient->waitForFocusChange(WAIT_FOR_TIMEOUT_DURATION, &focusChanged), FocusState::FOREGROUND);
EXPECT_TRUE(focusChanged);
}
} // namespace test
} // namespace integration
} // namespace alexaClientSDK
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
if (argc < 3) {
std::cerr << "USAGE: " << std::string(argv[0]) << " <path_to_AlexaClientSDKConfig.json> <path_to_inputs_folder>"
<< std::endl;
return 1;
} else {
alexaClientSDK::integration::test::g_configPath = std::string(argv[1]);
alexaClientSDK::integration::test::g_inputPath = std::string(argv[2]);
return RUN_ALL_TESTS();
}
}