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
This commit is contained in:
Родитель
20d4e94160
Коммит
306a8257be
|
@ -66,8 +66,22 @@ class HttpServer : private Reactor::Callback
|
||||||
size_t m_maxRequestHeadersSize, m_maxRequestContentSize;
|
size_t m_maxRequestHeadersSize, m_maxRequestContentSize;
|
||||||
std::string m_serverHost;
|
std::string m_serverHost;
|
||||||
|
|
||||||
|
// Map of killed token to kill duration of that token
|
||||||
|
// Ideally we need a map of string --> std::pair<std::string /* suffix */, uint64_t /* duration */
|
||||||
|
std::map<std::string, uint64_t> m_killedTokens;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
void setKilledToken(std::string token, uint64_t duration)
|
||||||
|
{
|
||||||
|
m_killedTokens[token] = duration;
|
||||||
|
};
|
||||||
|
|
||||||
|
void clearKilledTokens()
|
||||||
|
{
|
||||||
|
m_killedTokens.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void setKeepalive(bool keepAlive)
|
void setKeepalive(bool keepAlive)
|
||||||
{
|
{
|
||||||
allowKeepalive = keepAlive;
|
allowKeepalive = keepAlive;
|
||||||
|
@ -547,6 +561,18 @@ class HttpServer : private Reactor::Callback
|
||||||
conn.response.headers["Connection"] = (conn.keepalive ? "keep-alive" : "close");
|
conn.response.headers["Connection"] = (conn.keepalive ? "keep-alive" : "close");
|
||||||
conn.response.headers["Date"] = formatTimestamp(time(nullptr));
|
conn.response.headers["Date"] = formatTimestamp(time(nullptr));
|
||||||
conn.response.headers["Content-Length"] = std::to_string(conn.response.content.size());
|
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<std::string, std::string>("kill-tokens", val));
|
||||||
|
kill_duration = std::max(kill_duration, (int)kv.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_killedTokens.size() > 0) {
|
||||||
|
conn.response.headers.insert(std::pair<std::string, std::string>("kill-duration", std::to_string(kill_duration)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string formatTimestamp(time_t time)
|
static std::string formatTimestamp(time_t time)
|
||||||
|
|
|
@ -24,6 +24,7 @@ using namespace ARIASDK_NS;
|
||||||
char const* const TEST_STORAGE_FILENAME = "BasicFuncTests.db";
|
char const* const TEST_STORAGE_FILENAME = "BasicFuncTests.db";
|
||||||
|
|
||||||
#define TEST_TOKEN "6d084bbf6a9644ef83f40a77c9e34580-c2d379e0-4408-4325-9b4d-2a7d78131e14-7322"
|
#define TEST_TOKEN "6d084bbf6a9644ef83f40a77c9e34580-c2d379e0-4408-4325-9b4d-2a7d78131e14-7322"
|
||||||
|
#define KILLED_TOKEN "deadbeefdeadbeefdeadbeefdeadbeef-c2d379e0-4408-4325-9b4d-2a7d78131e14-7322"
|
||||||
#define HTTP_PORT 19000
|
#define HTTP_PORT 19000
|
||||||
|
|
||||||
class BasicFuncTests : public ::testing::Test,
|
class BasicFuncTests : public ::testing::Test,
|
||||||
|
@ -99,7 +100,7 @@ public:
|
||||||
LogManager::Initialize(TEST_TOKEN, configuration);
|
LogManager::Initialize(TEST_TOKEN, configuration);
|
||||||
LogManager::ResumeTransmission();
|
LogManager::ResumeTransmission();
|
||||||
|
|
||||||
logger = LogManager::GetLogger(TEST_TOKEN, "source1");
|
logger = LogManager::GetLogger(TEST_TOKEN, "source1");
|
||||||
logger2 = LogManager::GetLogger(TEST_TOKEN, "source2");
|
logger2 = LogManager::GetLogger(TEST_TOKEN, "source2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -852,6 +853,263 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class KillSwitchListener : public DebugEventListener {
|
||||||
|
public :
|
||||||
|
std::atomic<unsigned> numLogged;
|
||||||
|
std::atomic<unsigned> numSent;
|
||||||
|
std::atomic<unsigned> numDropped;
|
||||||
|
std::atomic<unsigned> numReject;
|
||||||
|
std::atomic<unsigned> numHttpError;
|
||||||
|
std::atomic<unsigned> numHttpOK;
|
||||||
|
std::atomic<unsigned> numHttpFailure;
|
||||||
|
std::atomic<unsigned> 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)
|
TEST_F(BasicFuncTests, sendManyRequestsAndCancel)
|
||||||
{
|
{
|
||||||
CleanStorage();
|
CleanStorage();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче