259 lines
9.4 KiB
C++
259 lines
9.4 KiB
C++
/*
|
|
* Copyright 2018-2019 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 <memory>
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <AVSCommon/SDKInterfaces/MockDirectiveSequencer.h>
|
|
#include <AVSCommon/SDKInterfaces/MockExceptionEncounteredSender.h>
|
|
#include <AVSCommon/SDKInterfaces/MockMessageSender.h>
|
|
#include <Settings/MockDeviceSettingStorage.h>
|
|
|
|
#include "DoNotDisturbCA/DoNotDisturbCapabilityAgent.h"
|
|
|
|
namespace alexaClientSDK {
|
|
namespace capabilityAgents {
|
|
namespace doNotDisturb {
|
|
namespace test {
|
|
|
|
using namespace ::testing;
|
|
using namespace avsCommon::avs;
|
|
using namespace avsCommon::sdkInterfaces;
|
|
using namespace avsCommon::sdkInterfaces::test;
|
|
using namespace avsCommon::utils;
|
|
using namespace registrationManager;
|
|
using namespace settings::storage;
|
|
using namespace settings::storage::test;
|
|
using namespace settings;
|
|
|
|
/// Amount of time for the test to wait for event to be sent.
|
|
static const std::chrono::seconds WAIT_TIMEOUT(2);
|
|
|
|
/// A sample Directive JSON string for the purposes of creating an AVSDirective object.
|
|
static const std::string SETDNDMODE_DIRECTIVE_VALID_JSON_STRING = R"delim(
|
|
{
|
|
"directive": {
|
|
"header": {
|
|
"namespace": "DoNotDisturb",
|
|
"name": "SetDoNotDisturb",
|
|
"messageId": "12345"
|
|
},
|
|
"payload": {
|
|
"enabled": true
|
|
}
|
|
}
|
|
})delim";
|
|
|
|
/// "Report" event for DoNotDisturb API
|
|
static const std::string DND_REPORT_EVENT = "ReportDoNotDisturb";
|
|
/// "Changed" event for DoNotDisturb API
|
|
static const std::string DND_CHANGE_EVENT = "DoNotDisturbChanged";
|
|
|
|
/// Test harness for @c DoNotDisturbCapabilityAgent class.
|
|
class DoNotDisturbCapabilityAgentTest : public ::testing::Test {
|
|
public:
|
|
/// Set up the test harness for running a test.
|
|
void SetUp() override;
|
|
|
|
protected:
|
|
void TearDown() override;
|
|
|
|
public:
|
|
/// Helper method to set up mocks for an upcoming event.
|
|
bool expectEventSend(
|
|
const std::string& eventName,
|
|
MessageRequestObserverInterface::Status statusReported,
|
|
std::function<void()> triggerOperation);
|
|
|
|
protected:
|
|
/// The InteractionModelCapabilityAgent instance to be tested
|
|
std::shared_ptr<DoNotDisturbCapabilityAgent> m_dndCA;
|
|
|
|
/// Message sender mock to track messages being sent.
|
|
std::shared_ptr<MockMessageSender> m_messageSender;
|
|
|
|
/// The mock @c ExceptionEncounteredSenderInterface.
|
|
std::shared_ptr<avsCommon::sdkInterfaces::test::MockExceptionEncounteredSender> m_mockExceptionEncounteredSender;
|
|
|
|
/// Storage for the settings.
|
|
std::shared_ptr<MockDeviceSettingStorage> m_settingsStorage;
|
|
};
|
|
|
|
void DoNotDisturbCapabilityAgentTest::SetUp() {
|
|
m_messageSender = std::make_shared<MockMessageSender>();
|
|
|
|
m_mockExceptionEncounteredSender =
|
|
std::make_shared<avsCommon::sdkInterfaces::test::MockExceptionEncounteredSender>();
|
|
|
|
m_settingsStorage = std::make_shared<MockDeviceSettingStorage>();
|
|
EXPECT_CALL(*m_settingsStorage, storeSetting(_, _, _)).WillRepeatedly(Return(true));
|
|
EXPECT_CALL(*m_settingsStorage, updateSettingStatus(_, _)).WillRepeatedly(Return(true));
|
|
EXPECT_CALL(*m_settingsStorage, loadSetting(_))
|
|
.WillRepeatedly(Return(std::make_pair(SettingStatus::SYNCHRONIZED, "true")));
|
|
|
|
m_dndCA = DoNotDisturbCapabilityAgent::create(m_mockExceptionEncounteredSender, m_messageSender, m_settingsStorage);
|
|
|
|
ASSERT_NE(m_dndCA, nullptr);
|
|
}
|
|
|
|
bool DoNotDisturbCapabilityAgentTest::expectEventSend(
|
|
const std::string& eventName,
|
|
MessageRequestObserverInterface::Status statusReported,
|
|
std::function<void()> triggerOperation) {
|
|
std::promise<bool> eventPromise;
|
|
EXPECT_CALL(*m_messageSender, sendMessage(_))
|
|
.Times(1)
|
|
.WillOnce(Invoke([statusReported, &eventName, &eventPromise](std::shared_ptr<MessageRequest> request) {
|
|
if (request->getJsonContent().find(eventName) != std::string::npos) {
|
|
request->sendCompleted(statusReported);
|
|
eventPromise.set_value(true);
|
|
return;
|
|
}
|
|
// Unexpected event
|
|
eventPromise.set_value(false);
|
|
}));
|
|
|
|
triggerOperation();
|
|
|
|
auto future = eventPromise.get_future();
|
|
bool isFutureReady = future.wait_for(WAIT_TIMEOUT) == std::future_status::ready;
|
|
EXPECT_TRUE(isFutureReady);
|
|
|
|
if (!isFutureReady) {
|
|
return false;
|
|
}
|
|
return future.get();
|
|
}
|
|
|
|
void DoNotDisturbCapabilityAgentTest::TearDown() {
|
|
if (m_dndCA) {
|
|
m_dndCA->shutdown();
|
|
}
|
|
}
|
|
|
|
TEST_F(DoNotDisturbCapabilityAgentTest, test_givenInvalidParameters_create_shouldFail) {
|
|
auto dndCA = DoNotDisturbCapabilityAgent::create(nullptr, m_messageSender, m_settingsStorage);
|
|
EXPECT_THAT(dndCA, IsNull());
|
|
|
|
dndCA = DoNotDisturbCapabilityAgent::create(m_mockExceptionEncounteredSender, nullptr, m_settingsStorage);
|
|
EXPECT_THAT(dndCA, IsNull());
|
|
|
|
dndCA = DoNotDisturbCapabilityAgent::create(m_mockExceptionEncounteredSender, m_messageSender, nullptr);
|
|
EXPECT_THAT(dndCA, IsNull());
|
|
}
|
|
|
|
TEST_F(DoNotDisturbCapabilityAgentTest, test_givenValidSetDNDDirective_handleDirective_shouldSucceed) {
|
|
// Become online
|
|
bool initialReportSent =
|
|
expectEventSend(DND_REPORT_EVENT, MessageRequestObserverInterface::Status::SUCCESS, [this]() {
|
|
m_dndCA->onConnectionStatusChanged(
|
|
ConnectionStatusObserverInterface::Status::CONNECTED,
|
|
ConnectionStatusObserverInterface::ChangedReason::SUCCESS);
|
|
});
|
|
|
|
ASSERT_TRUE(initialReportSent);
|
|
|
|
auto directivePair = AVSDirective::create(SETDNDMODE_DIRECTIVE_VALID_JSON_STRING, nullptr, "");
|
|
std::shared_ptr<AVSDirective> directive = std::move(directivePair.first);
|
|
|
|
bool directiveResponseEventSent =
|
|
expectEventSend(DND_REPORT_EVENT, MessageRequestObserverInterface::Status::SUCCESS, [this, &directive]() {
|
|
m_dndCA->handleDirectiveImmediately(directive);
|
|
});
|
|
|
|
ASSERT_TRUE(directiveResponseEventSent);
|
|
}
|
|
|
|
TEST_F(DoNotDisturbCapabilityAgentTest, test_beingOnline_applyLocalChange_shouldSendReport) {
|
|
bool initialReportSent =
|
|
expectEventSend(DND_REPORT_EVENT, MessageRequestObserverInterface::Status::SUCCESS, [this]() {
|
|
m_dndCA->onConnectionStatusChanged(
|
|
ConnectionStatusObserverInterface::Status::CONNECTED,
|
|
ConnectionStatusObserverInterface::ChangedReason::SUCCESS);
|
|
});
|
|
|
|
ASSERT_TRUE(initialReportSent);
|
|
|
|
bool changeEventSent =
|
|
expectEventSend(DND_CHANGE_EVENT, MessageRequestObserverInterface::Status::SUCCESS, [this]() {
|
|
m_dndCA->sendChangedEvent("true");
|
|
});
|
|
|
|
ASSERT_TRUE(changeEventSent);
|
|
}
|
|
|
|
TEST_F(DoNotDisturbCapabilityAgentTest, test_beingOffline_applyLocalChangeAndBecomeOnline_shouldSendChanged) {
|
|
// Apply change while offline
|
|
m_dndCA->sendChangedEvent("true");
|
|
|
|
bool changeEventSent =
|
|
expectEventSend(DND_CHANGE_EVENT, MessageRequestObserverInterface::Status::SUCCESS, [this]() {
|
|
m_dndCA->onConnectionStatusChanged(
|
|
ConnectionStatusObserverInterface::Status::CONNECTED,
|
|
ConnectionStatusObserverInterface::ChangedReason::SUCCESS);
|
|
});
|
|
|
|
ASSERT_TRUE(changeEventSent);
|
|
}
|
|
|
|
TEST_F(DoNotDisturbCapabilityAgentTest, test_whileSendingChangedEvent_sendChangedFail_shouldSendReport) {
|
|
// Become online and ignore the first "report" event.
|
|
|
|
bool initialReportSent =
|
|
expectEventSend(DND_REPORT_EVENT, MessageRequestObserverInterface::Status::SUCCESS, [this]() {
|
|
m_dndCA->onConnectionStatusChanged(
|
|
ConnectionStatusObserverInterface::Status::CONNECTED,
|
|
ConnectionStatusObserverInterface::ChangedReason::SUCCESS);
|
|
});
|
|
|
|
ASSERT_TRUE(initialReportSent);
|
|
|
|
int eventMask = 0;
|
|
|
|
std::promise<bool> eventPromise;
|
|
EXPECT_CALL(*m_messageSender, sendMessage(_))
|
|
.Times(2)
|
|
.WillRepeatedly(Invoke([&eventMask, &eventPromise](std::shared_ptr<MessageRequest> request) {
|
|
if (request->getJsonContent().find(DND_CHANGE_EVENT) != std::string::npos) {
|
|
eventMask <<= 1;
|
|
eventMask |= 1;
|
|
request->sendCompleted(MessageRequestObserverInterface::Status::INTERNAL_ERROR);
|
|
return;
|
|
} else if (request->getJsonContent().find(DND_REPORT_EVENT) != std::string::npos) {
|
|
eventMask <<= 1;
|
|
eventPromise.set_value(true);
|
|
return;
|
|
}
|
|
|
|
// Unexpected event
|
|
eventPromise.set_value(false);
|
|
}));
|
|
|
|
m_dndCA->sendChangedEvent("true");
|
|
|
|
auto future = eventPromise.get_future();
|
|
bool isFutureReady = future.wait_for(WAIT_TIMEOUT) == std::future_status::ready;
|
|
EXPECT_TRUE(isFutureReady);
|
|
// Check the order and existence of the events: Changed first, Report second, both happened.
|
|
EXPECT_EQ(eventMask, 2);
|
|
}
|
|
|
|
} // namespace test
|
|
} // namespace doNotDisturb
|
|
} // namespace capabilityAgents
|
|
} // namespace alexaClientSDK
|