From 306a8257beee9edef9119af1bbee17abe616b48f Mon Sep 17 00:00:00 2001 From: Miguel Angel Casillas Maldonado Date: Tue, 5 Mar 2019 19:56:07 +0000 Subject: [PATCH] Merged PR 940316: KillSwitch tests Added FunctTests to check KillSwitch feature: - killSwitchWorks checks that a token is banned and events are dropped - killIsTemporary checks that a token is banned for an amount of time and no events are dropped after that Related work items: #1608758 --- tests/common/HttpServer.hpp | 26 +++ tests/functests/BasicFuncTests.cpp | 260 ++++++++++++++++++++++++++++- 2 files changed, 285 insertions(+), 1 deletion(-) diff --git a/tests/common/HttpServer.hpp b/tests/common/HttpServer.hpp index ea920970..7e7f66e3 100644 --- a/tests/common/HttpServer.hpp +++ b/tests/common/HttpServer.hpp @@ -66,8 +66,22 @@ class HttpServer : private Reactor::Callback size_t m_maxRequestHeadersSize, m_maxRequestContentSize; std::string m_serverHost; + // Map of killed token to kill duration of that token + // Ideally we need a map of string --> std::pair m_killedTokens; + public: + void setKilledToken(std::string token, uint64_t duration) + { + m_killedTokens[token] = duration; + }; + + void clearKilledTokens() + { + m_killedTokens.clear(); + } + void setKeepalive(bool keepAlive) { allowKeepalive = keepAlive; @@ -547,6 +561,18 @@ class HttpServer : private Reactor::Callback conn.response.headers["Connection"] = (conn.keepalive ? "keep-alive" : "close"); conn.response.headers["Date"] = formatTimestamp(time(nullptr)); conn.response.headers["Content-Length"] = std::to_string(conn.response.content.size()); + int kill_duration = -1; + for (auto &kv : m_killedTokens) + { + std::string val = kv.first; + val += ":all"; + conn.response.headers.insert(std::pair("kill-tokens", val)); + kill_duration = std::max(kill_duration, (int)kv.second); + } + + if (m_killedTokens.size() > 0) { + conn.response.headers.insert(std::pair("kill-duration", std::to_string(kill_duration))); + } } static std::string formatTimestamp(time_t time) diff --git a/tests/functests/BasicFuncTests.cpp b/tests/functests/BasicFuncTests.cpp index 33240914..4213f979 100644 --- a/tests/functests/BasicFuncTests.cpp +++ b/tests/functests/BasicFuncTests.cpp @@ -24,6 +24,7 @@ using namespace ARIASDK_NS; char const* const TEST_STORAGE_FILENAME = "BasicFuncTests.db"; #define TEST_TOKEN "6d084bbf6a9644ef83f40a77c9e34580-c2d379e0-4408-4325-9b4d-2a7d78131e14-7322" +#define KILLED_TOKEN "deadbeefdeadbeefdeadbeefdeadbeef-c2d379e0-4408-4325-9b4d-2a7d78131e14-7322" #define HTTP_PORT 19000 class BasicFuncTests : public ::testing::Test, @@ -99,7 +100,7 @@ public: LogManager::Initialize(TEST_TOKEN, configuration); LogManager::ResumeTransmission(); - logger = LogManager::GetLogger(TEST_TOKEN, "source1"); + logger = LogManager::GetLogger(TEST_TOKEN, "source1"); logger2 = LogManager::GetLogger(TEST_TOKEN, "source2"); } @@ -852,6 +853,263 @@ public: } }; +class KillSwitchListener : public DebugEventListener { +public : + std::atomic numLogged; + std::atomic numSent; + std::atomic numDropped; + std::atomic numReject; + std::atomic numHttpError; + std::atomic numHttpOK; + std::atomic numHttpFailure; + std::atomic numCached; + + KillSwitchListener() : + numLogged(0), + numSent(0), + numDropped(0), + numReject(0), + numHttpError(0), + numHttpOK(0), + numHttpFailure(0), + numCached(0) + { + } + + virtual void OnDebugEvent(DebugEvent &evt) { + switch (evt.type) { + case EVT_LOG_SESSION: + numLogged++; + break; + case EVT_REJECTED: + numReject++; + break; + case EVT_ADDED: + break; + /* Event counts below would never overflow the size of unsigned int */ + case EVT_CACHED: + numCached += (unsigned int)evt.param1; + break; + case EVT_DROPPED: + numDropped += (unsigned int)evt.param1; + break; + case EVT_SENT: + numSent += (unsigned int)evt.param1; + break; + case EVT_HTTP_FAILURE: + numHttpFailure++; + break; + case EVT_HTTP_ERROR: + numHttpError++; + break; + case EVT_HTTP_OK: + numHttpOK++; + break; + case EVT_UNKNOWN: + default: + break; + }; + } + void printStats(){ + std::cerr << "[ ] numLogged = " << numLogged << std::endl; + std::cerr << "[ ] numSent = " << numSent << std::endl; + std::cerr << "[ ] numDropped = " << numDropped << std::endl; + std::cerr << "[ ] numReject = " << numReject << std::endl; + std::cerr << "[ ] numHttpError = " << numHttpError << std::endl; + std::cerr << "[ ] numHttpOK = " << numHttpOK << std::endl; + std::cerr << "[ ] numHttpFailure = " << numHttpFailure << std::endl; + std::cerr << "[ ] numCached = " << numCached << std::endl; + } +}; + +void addListeners(DebugEventListener &listener) { + LogManager::AddEventListener(DebugEventType::EVT_LOG_SESSION, listener); + LogManager::AddEventListener(DebugEventType::EVT_REJECTED, listener); + LogManager::AddEventListener(DebugEventType::EVT_SENT, listener); + LogManager::AddEventListener(DebugEventType::EVT_DROPPED, listener); + LogManager::AddEventListener(DebugEventType::EVT_HTTP_OK, listener); + LogManager::AddEventListener(DebugEventType::EVT_HTTP_ERROR, listener); + LogManager::AddEventListener(DebugEventType::EVT_HTTP_FAILURE, listener); + LogManager::AddEventListener(DebugEventType::EVT_CACHED, listener); +} + +void removeListeners(DebugEventListener &listener) { + LogManager::RemoveEventListener(DebugEventType::EVT_LOG_SESSION, listener); + LogManager::RemoveEventListener(DebugEventType::EVT_REJECTED, listener); + LogManager::RemoveEventListener(DebugEventType::EVT_SENT, listener); + LogManager::RemoveEventListener(DebugEventType::EVT_DROPPED, listener); + LogManager::RemoveEventListener(DebugEventType::EVT_HTTP_OK, listener); + LogManager::RemoveEventListener(DebugEventType::EVT_HTTP_ERROR, listener); + LogManager::RemoveEventListener(DebugEventType::EVT_HTTP_FAILURE, listener); + LogManager::RemoveEventListener(DebugEventType::EVT_CACHED, listener); +} + +TEST_F(BasicFuncTests, killSwitchWorks) +{ + CleanStorage(); + // Create the configuration to send to fake server + auto configuration = LogManager::GetLogConfiguration(); + + configuration[CFG_INT_TRACE_LEVEL_MASK] = 0xFFFFFFFF; + configuration[CFG_INT_TRACE_LEVEL_MIN] = ACTTraceLevel_Warn; + configuration[CFG_INT_SDK_MODE] = SdkModeTypes::SdkModeTypes_Aria; + + configuration[CFG_INT_RAM_QUEUE_SIZE] = 4096 * 20; + configuration[CFG_STR_CACHE_FILE_PATH] = TEST_STORAGE_FILENAME; + configuration[CFG_INT_MAX_TEARDOWN_TIME] = 2; // 2 seconds wait on shutdown + configuration[CFG_STR_COLLECTOR_URL] = serverAddress.c_str(); + configuration["http"]["compress"] = false; // disable compression for now + configuration["stats"]["interval"] = 30 * 60; // 30 mins + + configuration["name"] = __FILE__; + configuration["version"] = "1.0.0"; + configuration["config"] = { { "host", __FILE__ } }; // Host instance + + // set the killed token on the server + server.setKilledToken(KILLED_TOKEN, 6384); + KillSwitchListener listener; + addListeners(listener); + // Log 100 events from valid and invalid 4 times + int repetitions = 4; + for (int i = 0; i < repetitions; i++) { + // Initialize the logger for the valid token and log 100 events + LogManager::Initialize(TEST_TOKEN, configuration); + LogManager::ResumeTransmission(); + auto myLogger = LogManager::GetLogger(TEST_TOKEN, "killed"); + int numIterations = 100; + while (numIterations--) { + EventProperties event1("fooEvent"); + event1.SetProperty("property", "value"); + myLogger->LogEvent(event1); + } + // Initialize the logger for the killed token and log 100 events + LogManager::Initialize(KILLED_TOKEN, configuration); + LogManager::ResumeTransmission(); + myLogger = LogManager::GetLogger(KILLED_TOKEN, "killed"); + numIterations = 100; + while (numIterations--) { + EventProperties event2("failEvent"); + event2.SetProperty("property", "value"); + myLogger->LogEvent(event2); + } + } + // Try to upload and wait for 2 seconds to complete + LogManager::UploadNow(); + PAL::sleep(2000); + + // Log 100 events with valid logger + LogManager::Initialize(TEST_TOKEN, configuration); + LogManager::ResumeTransmission(); + auto myLogger = LogManager::GetLogger(TEST_TOKEN, "killed"); + int numIterations = 100; + while (numIterations--) { + EventProperties event1("fooEvent"); + event1.SetProperty("property", "value"); + myLogger->LogEvent(event1); + } + + LogManager::Initialize(KILLED_TOKEN, configuration); + LogManager::ResumeTransmission(); + myLogger = LogManager::GetLogger(KILLED_TOKEN, "killed"); + numIterations = 100; + while (numIterations--) { + EventProperties event2("failEvent"); + event2.SetProperty("property", "value"); + myLogger->LogEvent(event2); + } + // Expect all events to be dropped + EXPECT_EQ(100, listener.numDropped); + LogManager::FlushAndTeardown(); + + listener.printStats(); + removeListeners(listener); + server.clearKilledTokens(); +} + +TEST_F(BasicFuncTests, killIsTemporary) +{ + CleanStorage(); + // Create the configuration to send to fake server + auto configuration = LogManager::GetLogConfiguration(); + + configuration[CFG_INT_TRACE_LEVEL_MASK] = 0xFFFFFFFF; + configuration[CFG_INT_TRACE_LEVEL_MIN] = ACTTraceLevel_Warn; + configuration[CFG_INT_SDK_MODE] = SdkModeTypes::SdkModeTypes_Aria; + + configuration[CFG_INT_RAM_QUEUE_SIZE] = 4096 * 20; + configuration[CFG_STR_CACHE_FILE_PATH] = TEST_STORAGE_FILENAME; + configuration[CFG_INT_MAX_TEARDOWN_TIME] = 2; // 2 seconds wait on shutdown + configuration[CFG_STR_COLLECTOR_URL] = serverAddress.c_str(); + configuration["http"]["compress"] = false; // disable compression for now + configuration["stats"]["interval"] = 30 * 60; // 30 mins + + configuration["name"] = __FILE__; + configuration["version"] = "1.0.0"; + configuration["config"] = { { "host", __FILE__ } }; // Host instance + + // set the killed token on the server + server.setKilledToken(KILLED_TOKEN, 10); + KillSwitchListener listener; + addListeners(listener); + // Log 100 events from valid and invalid 4 times + int repetitions = 4; + for (int i = 0; i < repetitions; i++) { + // Initialize the logger for the valid token and log 100 events + LogManager::Initialize(TEST_TOKEN, configuration); + LogManager::ResumeTransmission(); + auto myLogger = LogManager::GetLogger(TEST_TOKEN, "killed"); + int numIterations = 100; + while (numIterations--) { + EventProperties event1("fooEvent"); + event1.SetProperty("property", "value"); + myLogger->LogEvent(event1); + } + // Initialize the logger for the killed token and log 100 events + LogManager::Initialize(KILLED_TOKEN, configuration); + LogManager::ResumeTransmission(); + myLogger = LogManager::GetLogger(KILLED_TOKEN, "killed"); + numIterations = 100; + while (numIterations--) { + EventProperties event2("failEvent"); + event2.SetProperty("property", "value"); + myLogger->LogEvent(event2); + } + } + // Try and wait to upload + LogManager::UploadNow(); + PAL::sleep(2000); + // Sleep for 11 seconds so the killed time has expired, clear the killed tokens on server + PAL::sleep(11000); + server.clearKilledTokens(); + // Log 100 events with valid logger + LogManager::Initialize(TEST_TOKEN, configuration); + LogManager::ResumeTransmission(); + auto myLogger = LogManager::GetLogger(TEST_TOKEN, "killed"); + int numIterations = 100; + while (numIterations--) { + EventProperties event1("fooEvent"); + event1.SetProperty("property", "value"); + myLogger->LogEvent(event1); + } + + LogManager::Initialize(KILLED_TOKEN, configuration); + LogManager::ResumeTransmission(); + myLogger = LogManager::GetLogger(KILLED_TOKEN, "killed"); + numIterations = 100; + while (numIterations--) { + EventProperties event2("failEvent"); + event2.SetProperty("property", "value"); + myLogger->LogEvent(event2); + } + // Expect to 0 events to be dropped + EXPECT_EQ(0, listener.numDropped); + LogManager::FlushAndTeardown(); + + listener.printStats(); + removeListeners(listener); + server.clearKilledTokens(); +} + TEST_F(BasicFuncTests, sendManyRequestsAndCancel) { CleanStorage();