251 lines
8.1 KiB
C++
251 lines
8.1 KiB
C++
|
/*
|
||
|
* Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||
|
* You may not use this file except in compliance with the License.
|
||
|
* A copy of the License is located at
|
||
|
*
|
||
|
* http://aws.amazon.com/apache2.0/
|
||
|
*
|
||
|
* or in the "license" file accompanying this file. This file is distributed
|
||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||
|
* express or implied. See the License for the specific language governing
|
||
|
* permissions and limitations under the License.
|
||
|
*/
|
||
|
|
||
|
/// @file NetworkIntegrationTests.cpp
|
||
|
|
||
|
#include <chrono>
|
||
|
#include <fstream>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include <gtest/gtest.h>
|
||
|
|
||
|
#include <ACL/AVSConnectionManager.h>
|
||
|
#include <AVSCommon/AVS/MessageRequest.h>
|
||
|
#include <AVSCommon/Utils/Logger/Logger.h>
|
||
|
#include <ContextManager/ContextManager.h>
|
||
|
|
||
|
#include "Integration/ACLTestContext.h"
|
||
|
#include "Integration/ConnectionStatusObserver.h"
|
||
|
#include "Integration/JsonHeader.h"
|
||
|
#include "Integration/ObservableMessageRequest.h"
|
||
|
|
||
|
namespace alexaClientSDK {
|
||
|
namespace integration {
|
||
|
namespace test {
|
||
|
|
||
|
using namespace ::testing;
|
||
|
using namespace acl;
|
||
|
using namespace avsCommon::avs;
|
||
|
using namespace avsCommon::avs::attachment;
|
||
|
using namespace avsCommon::utils::sds;
|
||
|
using namespace avsCommon::sdkInterfaces;
|
||
|
|
||
|
static const std::string TAG("NetworkIntegrationTests");
|
||
|
|
||
|
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)
|
||
|
|
||
|
/// Amount of Delay in milliseconds to be added.
|
||
|
static const std::string DELAY_TIME = "1000ms";
|
||
|
/// Amount of Delay for causing a TIMEDOUT status in MessageRequest.
|
||
|
static const std::string LONG_DELAY_TIME = "40000ms";
|
||
|
/// The time to wait for expected message status on sending the message.
|
||
|
static const int TIMEOUT_FOR_SEND_IN_SECONDS = 10;
|
||
|
/// The time to wait for expected message status when delay is longer.
|
||
|
static const int LONG_TIMEOUT_FOR_SEND_IN_SECONDS = 40;
|
||
|
|
||
|
/// Path to the AlexaClientSDKConfig.json file.
|
||
|
std::string g_configPath;
|
||
|
/// The network interface specified for the delay to be added.
|
||
|
std::string network_interface;
|
||
|
|
||
|
/**
|
||
|
* Test class to stress test the ACL Library for slow network connection.
|
||
|
*/
|
||
|
class NetworkIntegrationTests : public ::testing::Test {
|
||
|
public:
|
||
|
void SetUp() override;
|
||
|
void TearDown() override;
|
||
|
|
||
|
/**
|
||
|
* This function enables the @c m_avsConnectionManager to establish a connection to AVS.
|
||
|
*/
|
||
|
void connect();
|
||
|
|
||
|
/**
|
||
|
* This function disables the @c m_avsConnectionManager to tear down the connection.
|
||
|
*/
|
||
|
void disconnect();
|
||
|
|
||
|
/**
|
||
|
* The function to send one message to AVS.
|
||
|
* @param jsonContent The content in json format to send in the message.
|
||
|
* @param expectedStatus The expected status of the message being sent to AVS.
|
||
|
* @param timeout The maximum time to wait for the @c expectedStatus.
|
||
|
* @param attachmentReader The attachment reader for the MessageRequest.
|
||
|
*/
|
||
|
void sendEvent(
|
||
|
const std::string& jsonContent,
|
||
|
MessageRequestObserverInterface::Status expectedStatus,
|
||
|
std::chrono::seconds timeout,
|
||
|
std::shared_ptr<avsCommon::avs::attachment::AttachmentReader> attachmentReader = nullptr);
|
||
|
|
||
|
/**
|
||
|
* The function adds delay to the network.
|
||
|
* @param DelayTime The delay in milliseconds to be introduced in the network.
|
||
|
*/
|
||
|
void addDelay(const std::string& delayTime);
|
||
|
|
||
|
/**
|
||
|
* Remove the delay in the network.
|
||
|
*/
|
||
|
void deleteDelay();
|
||
|
|
||
|
protected:
|
||
|
/// Context for running ACL based tests.
|
||
|
std::unique_ptr<ACLTestContext> m_context;
|
||
|
|
||
|
/// ConnectionStatus Observer for checking the status changes in connection.
|
||
|
std::shared_ptr<ConnectionStatusObserver> m_connectionStatusObserver;
|
||
|
|
||
|
/// Connection Manager for handling the communication between client and AVS.
|
||
|
std::shared_ptr<AVSConnectionManager> m_avsConnectionManager;
|
||
|
|
||
|
/// ContextManager object.
|
||
|
std::shared_ptr<contextManager::ContextManager> m_contextManager;
|
||
|
};
|
||
|
|
||
|
void NetworkIntegrationTests::SetUp() {
|
||
|
m_context = ACLTestContext::create(g_configPath);
|
||
|
ASSERT_TRUE(m_context);
|
||
|
|
||
|
m_avsConnectionManager = AVSConnectionManager::create(
|
||
|
m_context->getMessageRouter(),
|
||
|
false,
|
||
|
{m_context->getConnectionStatusObserver()},
|
||
|
std::unordered_set<std::shared_ptr<MessageObserverInterface>>());
|
||
|
ASSERT_TRUE(m_avsConnectionManager);
|
||
|
}
|
||
|
|
||
|
void NetworkIntegrationTests::TearDown() {
|
||
|
deleteDelay();
|
||
|
}
|
||
|
|
||
|
void NetworkIntegrationTests::connect() {
|
||
|
m_avsConnectionManager->enable();
|
||
|
m_context->waitForConnected();
|
||
|
}
|
||
|
|
||
|
void NetworkIntegrationTests::disconnect() {
|
||
|
if (m_avsConnectionManager) {
|
||
|
m_avsConnectionManager->disable();
|
||
|
m_context->waitForDisconnected();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NetworkIntegrationTests::sendEvent(
|
||
|
const std::string& jsonContent,
|
||
|
MessageRequestObserverInterface::Status expectedStatus,
|
||
|
std::chrono::seconds timeout,
|
||
|
std::shared_ptr<avsCommon::avs::attachment::AttachmentReader> attachmentReader) {
|
||
|
auto messageRequest = std::make_shared<ObservableMessageRequest>(jsonContent, attachmentReader);
|
||
|
m_avsConnectionManager->sendMessage(messageRequest);
|
||
|
ASSERT_TRUE(messageRequest->waitFor(expectedStatus, timeout));
|
||
|
ASSERT_TRUE(messageRequest->hasSendCompleted() || messageRequest->wasExceptionReceived());
|
||
|
}
|
||
|
|
||
|
void NetworkIntegrationTests::addDelay(const std::string& delayTime) {
|
||
|
std::string str = "tc qdisc add dev " + network_interface + " root netem delay " + delayTime;
|
||
|
int ret = system(str.c_str());
|
||
|
ASSERT_TRUE(WIFEXITED(ret)) << "System call didn't terminate normally";
|
||
|
ASSERT_EQ(0, WEXITSTATUS(ret)) << "Child process in system call exited abnormally";
|
||
|
}
|
||
|
|
||
|
void NetworkIntegrationTests::deleteDelay() {
|
||
|
std::string str = "tc qdisc delete dev " + network_interface + " root";
|
||
|
int ret = system(str.c_str());
|
||
|
ASSERT_TRUE(WIFEXITED(ret)) << "System call didn't terminate normally";
|
||
|
ASSERT_EQ(0, WEXITSTATUS(ret)) << "Child process in system call exited abnormally";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test if connection and disconnection can be established after delay is introduced.
|
||
|
*/
|
||
|
TEST_F(NetworkIntegrationTests, testConnectAfterSlowConnection) {
|
||
|
addDelay(DELAY_TIME);
|
||
|
connect();
|
||
|
disconnect();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Establish Connection, and introduce delay and check if @c connectionStatus remains CONNECTED.
|
||
|
*/
|
||
|
TEST_F(NetworkIntegrationTests, testConnectBeforeSlowConnection) {
|
||
|
connect();
|
||
|
addDelay(DELAY_TIME);
|
||
|
disconnect();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Establish connection, introduce delay and test if connect can be done again.
|
||
|
*/
|
||
|
TEST_F(NetworkIntegrationTests, testReConnectAfterDelay) {
|
||
|
connect();
|
||
|
addDelay(DELAY_TIME);
|
||
|
disconnect();
|
||
|
connect();
|
||
|
disconnect();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Establish connection, introduce a delay, send a message, check if the Status of MessageRequest
|
||
|
* is SUCCESS.
|
||
|
*/
|
||
|
TEST_F(NetworkIntegrationTests, testSendEventAfterDelayPass) {
|
||
|
connect();
|
||
|
addDelay(DELAY_TIME);
|
||
|
sendEvent(
|
||
|
SYNCHRONIZE_STATE_JSON,
|
||
|
MessageRequestObserverInterface::Status::SUCCESS,
|
||
|
std::chrono::seconds(TIMEOUT_FOR_SEND_IN_SECONDS));
|
||
|
disconnect();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Establish connection, introduce a longer delay time of greater than 30 seconds, send a message,
|
||
|
* the Status of MessageRequest will be TIMEDOUT.
|
||
|
*/
|
||
|
TEST_F(NetworkIntegrationTests, testSendEventAfterDelayFails) {
|
||
|
connect();
|
||
|
addDelay(LONG_DELAY_TIME);
|
||
|
sendEvent(
|
||
|
SYNCHRONIZE_STATE_JSON,
|
||
|
MessageRequestObserverInterface::Status::TIMEDOUT,
|
||
|
std::chrono::seconds(LONG_TIMEOUT_FOR_SEND_IN_SECONDS));
|
||
|
disconnect();
|
||
|
}
|
||
|
|
||
|
} // namespace test
|
||
|
} // namespace integration
|
||
|
} // namespace alexaClientSDK
|
||
|
|
||
|
int main(int argc, char** argv) {
|
||
|
::testing::InitGoogleTest(&argc, argv);
|
||
|
|
||
|
if (getuid()) {
|
||
|
std::cerr << "You need to be root to run this test" << std::endl;
|
||
|
return 1;
|
||
|
}
|
||
|
if (argc < 3) {
|
||
|
std::cerr << "USAGE: " << std::string(argv[0]) << "<path_to_AlexaClientSDKConfig.json> <Network_Interface_Name>"
|
||
|
<< std::endl;
|
||
|
return 1;
|
||
|
} else {
|
||
|
alexaClientSDK::integration::test::g_configPath = std::string(argv[1]);
|
||
|
alexaClientSDK::integration::test::network_interface = std::string(argv[2]);
|
||
|
return RUN_ALL_TESTS();
|
||
|
}
|
||
|
}
|