245 lines
9.5 KiB
C++
245 lines
9.5 KiB
C++
|
/*
|
||
|
* Copyright 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 "MockPostConnectObserver.h"
|
||
|
#include "MockPostConnectOperation.h"
|
||
|
#include <ACL/Transport/PostConnectSequencer.h>
|
||
|
#include <AVSCommon/SDKInterfaces/MockPostConnectSendMessage.h>
|
||
|
#include <AVSCommon/Utils/PromiseFuturePair.h>
|
||
|
|
||
|
namespace alexaClientSDK {
|
||
|
namespace acl {
|
||
|
namespace transport {
|
||
|
namespace test {
|
||
|
|
||
|
using namespace avsCommon::sdkInterfaces;
|
||
|
using namespace avsCommon::sdkInterfaces::test;
|
||
|
using namespace avsCommon::utils;
|
||
|
using namespace ::testing;
|
||
|
|
||
|
/// A short delay used in tests.
|
||
|
static const auto SHORT_DELAY = std::chrono::seconds(1);
|
||
|
|
||
|
/**
|
||
|
* Test harness for @c PostConnectSequencer class.
|
||
|
*/
|
||
|
class PostConnectSequencerTest : public Test {
|
||
|
public:
|
||
|
/// initialization for tests.
|
||
|
void SetUp() override;
|
||
|
|
||
|
protected:
|
||
|
/// The mock @c PostConnectObserverInterface.
|
||
|
std::shared_ptr<MockPostConnectObserver> m_mockPostConnectObserver;
|
||
|
|
||
|
/// The mock @c PostConnectSendMessageInterface.
|
||
|
std::shared_ptr<MockPostConnectSendMessage> m_mockPostConnectMessageSender;
|
||
|
};
|
||
|
|
||
|
void PostConnectSequencerTest::SetUp() {
|
||
|
m_mockPostConnectObserver = std::make_shared<NiceMock<MockPostConnectObserver>>();
|
||
|
m_mockPostConnectMessageSender = std::make_shared<NiceMock<MockPostConnectSendMessage>>();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the PostConnectOperationsSet sequences operations based on priority.
|
||
|
*/
|
||
|
TEST_F(PostConnectSequencerTest, test_postConnectOperationsSet) {
|
||
|
auto operation1 = std::make_shared<NiceMock<MockPostConnectOperation>>();
|
||
|
auto operation2 = std::make_shared<NiceMock<MockPostConnectOperation>>();
|
||
|
auto operation3 = std::make_shared<NiceMock<MockPostConnectOperation>>();
|
||
|
|
||
|
EXPECT_CALL(*operation1, getOperationPriority()).WillRepeatedly(Return(3));
|
||
|
EXPECT_CALL(*operation2, getOperationPriority()).WillRepeatedly(Return(2));
|
||
|
EXPECT_CALL(*operation3, getOperationPriority()).WillRepeatedly(Return(1));
|
||
|
|
||
|
PostConnectSequencer::PostConnectOperationsSet operationsSet;
|
||
|
operationsSet.insert(operation1);
|
||
|
operationsSet.insert(operation2);
|
||
|
operationsSet.insert(operation3);
|
||
|
|
||
|
auto it = operationsSet.begin();
|
||
|
ASSERT_EQ(*it, operation3);
|
||
|
it++;
|
||
|
ASSERT_EQ(*it, operation2);
|
||
|
it++;
|
||
|
ASSERT_EQ(*it, operation1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the PostConnectOperationsSet keeps only one instance with the same priority.
|
||
|
*/
|
||
|
TEST_F(PostConnectSequencerTest, test_postConnectOperationsSetRemovesDuplicates) {
|
||
|
auto operation1 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
auto operation2 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
|
||
|
EXPECT_CALL(*operation1, getOperationPriority()).WillRepeatedly(Return(3));
|
||
|
EXPECT_CALL(*operation2, getOperationPriority()).WillRepeatedly(Return(3));
|
||
|
|
||
|
PostConnectSequencer::PostConnectOperationsSet operationsSet;
|
||
|
operationsSet.insert(operation1);
|
||
|
operationsSet.insert(operation2);
|
||
|
|
||
|
ASSERT_EQ(operationsSet.size(), 1U);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if all PostConnectOperations are executed in sequence and the PostConnectObserver will be notified.
|
||
|
*/
|
||
|
TEST_F(PostConnectSequencerTest, test_happyPathAndPostConnectObserverGetsNotified) {
|
||
|
auto operation1 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
auto operation2 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
auto operation3 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
|
||
|
EXPECT_CALL(*operation1, getOperationPriority()).WillRepeatedly(Return(3));
|
||
|
EXPECT_CALL(*operation2, getOperationPriority()).WillRepeatedly(Return(2));
|
||
|
EXPECT_CALL(*operation3, getOperationPriority()).WillRepeatedly(Return(1));
|
||
|
|
||
|
PostConnectSequencer::PostConnectOperationsSet operationsSet;
|
||
|
operationsSet.insert(operation1);
|
||
|
operationsSet.insert(operation2);
|
||
|
operationsSet.insert(operation3);
|
||
|
|
||
|
auto postConnectSequencer = PostConnectSequencer::create(operationsSet);
|
||
|
ASSERT_NE(postConnectSequencer, nullptr);
|
||
|
|
||
|
{
|
||
|
InSequence s;
|
||
|
EXPECT_CALL(*operation3, performOperation(_)).WillOnce(Return(true));
|
||
|
EXPECT_CALL(*operation2, performOperation(_)).WillOnce(Return(true));
|
||
|
EXPECT_CALL(*operation1, performOperation(_)).WillOnce(Return(true));
|
||
|
}
|
||
|
|
||
|
PromiseFuturePair<bool> promiseFuturePair;
|
||
|
EXPECT_CALL(*m_mockPostConnectObserver, onPostConnected()).WillOnce(Invoke([&promiseFuturePair] {
|
||
|
promiseFuturePair.setValue(true);
|
||
|
}));
|
||
|
|
||
|
postConnectSequencer->doPostConnect(m_mockPostConnectMessageSender, m_mockPostConnectObserver);
|
||
|
|
||
|
promiseFuturePair.waitFor(SHORT_DELAY);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if doPostConnect() gets called twice in a row, the method returns false..
|
||
|
*/
|
||
|
TEST_F(PostConnectSequencerTest, test_doPostConnectReturnFalseOnSecondCall) {
|
||
|
auto operation1 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
|
||
|
EXPECT_CALL(*operation1, getOperationPriority()).WillRepeatedly(Return(1));
|
||
|
|
||
|
PostConnectSequencer::PostConnectOperationsSet operationsSet;
|
||
|
operationsSet.insert(operation1);
|
||
|
|
||
|
auto postConnectSequencer = PostConnectSequencer::create(operationsSet);
|
||
|
ASSERT_NE(postConnectSequencer, nullptr);
|
||
|
|
||
|
EXPECT_CALL(*operation1, performOperation(_)).WillOnce(Return(true));
|
||
|
|
||
|
PromiseFuturePair<bool> promiseFuturePair;
|
||
|
EXPECT_CALL(*m_mockPostConnectObserver, onPostConnected()).WillOnce(Invoke([&promiseFuturePair] {
|
||
|
promiseFuturePair.setValue(true);
|
||
|
}));
|
||
|
|
||
|
ASSERT_TRUE(postConnectSequencer->doPostConnect(m_mockPostConnectMessageSender, m_mockPostConnectObserver));
|
||
|
ASSERT_FALSE(postConnectSequencer->doPostConnect(m_mockPostConnectMessageSender, m_mockPostConnectObserver));
|
||
|
|
||
|
promiseFuturePair.waitFor(SHORT_DELAY);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if PostConnectSequencer stops execution of PostConnectOperations if the performOperation() fails on one of
|
||
|
* them.
|
||
|
*/
|
||
|
TEST_F(PostConnectSequencerTest, test_subsequentOperationsDontExecute) {
|
||
|
auto operation1 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
auto operation2 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
auto operation3 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
|
||
|
EXPECT_CALL(*operation1, getOperationPriority()).WillRepeatedly(Return(3));
|
||
|
EXPECT_CALL(*operation2, getOperationPriority()).WillRepeatedly(Return(2));
|
||
|
EXPECT_CALL(*operation3, getOperationPriority()).WillRepeatedly(Return(1));
|
||
|
|
||
|
PostConnectSequencer::PostConnectOperationsSet operationsSet;
|
||
|
operationsSet.insert(operation1);
|
||
|
operationsSet.insert(operation2);
|
||
|
operationsSet.insert(operation3);
|
||
|
|
||
|
auto postConnectSequencer = PostConnectSequencer::create(operationsSet);
|
||
|
ASSERT_NE(postConnectSequencer, nullptr);
|
||
|
|
||
|
EXPECT_CALL(*operation3, performOperation(_)).WillOnce(Return(false));
|
||
|
|
||
|
PromiseFuturePair<bool> promiseFuturePair;
|
||
|
EXPECT_CALL(*m_mockPostConnectObserver, onUnRecoverablePostConnectFailure()).WillOnce(Invoke([&promiseFuturePair] {
|
||
|
promiseFuturePair.setValue(true);
|
||
|
}));
|
||
|
|
||
|
postConnectSequencer->doPostConnect(m_mockPostConnectMessageSender, m_mockPostConnectObserver);
|
||
|
|
||
|
/// It is possible that the destructor gets called first which initiates an abortOperation before the mainLoopThread
|
||
|
/// exits.
|
||
|
EXPECT_CALL(*operation3, abortOperation()).Times(AtMost(1));
|
||
|
|
||
|
promiseFuturePair.waitFor(SHORT_DELAY);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if onDisconnect() stops execution of PostConnectOperations.
|
||
|
*/
|
||
|
TEST_F(PostConnectSequencerTest, test_onDisconnectStopsExecution) {
|
||
|
auto operation1 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
auto operation2 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
auto operation3 = std::make_shared<StrictMock<MockPostConnectOperation>>();
|
||
|
|
||
|
EXPECT_CALL(*operation1, getOperationPriority()).WillRepeatedly(Return(3));
|
||
|
EXPECT_CALL(*operation2, getOperationPriority()).WillRepeatedly(Return(2));
|
||
|
EXPECT_CALL(*operation3, getOperationPriority()).WillRepeatedly(Return(1));
|
||
|
|
||
|
PostConnectSequencer::PostConnectOperationsSet operationsSet;
|
||
|
operationsSet.insert(operation1);
|
||
|
operationsSet.insert(operation2);
|
||
|
operationsSet.insert(operation3);
|
||
|
|
||
|
auto postConnectSequencer = PostConnectSequencer::create(operationsSet);
|
||
|
ASSERT_NE(postConnectSequencer, nullptr);
|
||
|
|
||
|
PromiseFuturePair<bool> notifyOnPerfromOperation, notifyOnAbortOperation;
|
||
|
EXPECT_CALL(*operation3, performOperation(_))
|
||
|
.WillOnce(Invoke([¬ifyOnAbortOperation, ¬ifyOnPerfromOperation](
|
||
|
const std::shared_ptr<PostConnectSendMessageInterface>& postConnectSender) {
|
||
|
notifyOnPerfromOperation.setValue(true);
|
||
|
notifyOnAbortOperation.waitFor(SHORT_DELAY);
|
||
|
return true;
|
||
|
}));
|
||
|
EXPECT_CALL(*operation3, abortOperation()).WillOnce(Invoke([¬ifyOnAbortOperation] {
|
||
|
notifyOnAbortOperation.setValue(true);
|
||
|
}));
|
||
|
|
||
|
postConnectSequencer->doPostConnect(m_mockPostConnectMessageSender, m_mockPostConnectObserver);
|
||
|
notifyOnPerfromOperation.waitFor(SHORT_DELAY);
|
||
|
postConnectSequencer->onDisconnect();
|
||
|
}
|
||
|
|
||
|
} // namespace test
|
||
|
} // namespace transport
|
||
|
} // namespace acl
|
||
|
} // namespace alexaClientSDK
|