First release of open-appsec source code

This commit is contained in:
roybarda
2022-10-26 19:33:19 +03:00
parent 3883109caf
commit a883352f79
1353 changed files with 276290 additions and 1 deletions

View File

@@ -0,0 +1,3 @@
add_library(environment environment.cc context.cc parsing.cc base_evaluators.cc trace.cc span.cc param_attr.cc)
add_subdirectory(environment_ut)

View File

@@ -0,0 +1,103 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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 "environment_evaluator.h"
#include "evaluator_registration.h"
using namespace std;
using namespace EnvironmentHelper;
class AllEvaluator : public EnvironmentEvaluator<bool>
{
public:
AllEvaluator(const vector<string> &params)
{
for (const auto &param : params) {
conditions.push_back(getMatcher<bool>(param));
}
}
Maybe<bool, Context::Error>
evalVariable() const override
{
for (auto &cond : conditions) {
auto res = cond->evalVariable();
if (!res.ok()) return res;
if (res.unpack() == false) return false;
}
return true;
}
static std::string getName() { return "All"; }
private:
vector<EvaluatorPtr<bool>> conditions;
};
class AnyEvaluator : public EnvironmentEvaluator<bool>
{
public:
AnyEvaluator(const vector<string> &params)
{
for (const auto &param : params) {
conditions.push_back(getMatcher<bool>(param));
}
}
Maybe<bool, Context::Error>
evalVariable() const override
{
for (auto &cond : conditions) {
auto res = cond->evalVariable();
if (!res.ok()) return res;
if (res.unpack() == true) return true;
}
return false;
}
static std::string getName() { return "Any"; }
private:
vector<EvaluatorPtr<bool>> conditions;
};
class NotEvaluator : public EnvironmentEvaluator<bool>
{
public:
NotEvaluator(const vector<string> &params)
{
if (params.size() != 1) reportWrongNumberOfParams(getName(), params.size(), 1, 1);
cond = getMatcher<bool>(params[0]);
}
Maybe<bool, Context::Error>
evalVariable() const override
{
auto res = cond->evalVariable();
if (!res.ok()) return res;
return !(res.unpack());
}
static std::string getName() { return "Not"; }
private:
EvaluatorPtr<bool> cond;
};
void
registerBaseEvaluators()
{
addMatcher<AllEvaluator>();
addMatcher<AnyEvaluator>();
addMatcher<NotEvaluator>();
}

101
core/environment/context.cc Normal file
View File

@@ -0,0 +1,101 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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 "context.h"
#include "i_environment.h"
#include "singleton.h"
using namespace std;
void
Context::activate()
{
Singleton::Consume<I_Environment>::by<Context>()->registerContext(this);
}
void
Context::deactivate()
{
Singleton::Consume<I_Environment>::by<Context>()->unregisterContext(this);
}
map<string, string>
Context::getAllStrings(const EnvKeyAttr::ParamAttr &param) const
{
map<string, string> result;
for (auto &entry : values) {
if (entry.first.doesMatch(param)) {
auto entry_value = entry.second->getString();
if (entry_value.ok()) result[entry.first.first] = *entry_value;
}
}
return result;
}
const std::string
Context::convertToString(MetaDataType type)
{
switch (type) {
case MetaDataType::File: return "file";
case MetaDataType::SubjectIpAddr: return "subjectIp";
case MetaDataType::OtherIpAddr: return "otherIp";
case MetaDataType::Port: return "port";
case MetaDataType::Protocol: return "protocol";
case MetaDataType::Service: return "service";
case MetaDataType::User: return "user";
case MetaDataType::Domain: return "domain";
case MetaDataType::Url: return "url";
case MetaDataType::Direction: return "direction";
case MetaDataType::Email: return "email";
case MetaDataType::COUNT:
dbgAssert(false) << "COUNT is not a valid meta data type";
}
dbgAssert(false) << "Reached impossible case with type=" << static_cast<int>(type);
return "";
}
map<string, uint64_t>
Context::getAllUints(const EnvKeyAttr::ParamAttr &param) const
{
map<string, uint64_t> result;
for (auto &entry : values) {
if (entry.first.doesMatch(param)) {
auto entry_value = entry.second->getUint();
if (entry_value.ok()) result[entry.first.first] = *entry_value;
}
}
return result;
}
map<string, bool>
Context::getAllBools(const EnvKeyAttr::ParamAttr &param) const
{
map<string, bool> result;
for (auto &entry : values) {
if (entry.first.doesMatch(param)) {
auto entry_value = entry.second->getBool();
if (entry_value.ok()) result[entry.first.first] = *entry_value;
}
}
return result;
}
ScopedContext::ScopedContext()
{
activate();
}
ScopedContext::~ScopedContext()
{
deactivate();
}

View File

@@ -0,0 +1,421 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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 "environment.h"
#include "context.h"
#include "singleton.h"
#include "common.h"
#include "debug.h"
#include "evaluator_registration.h"
#include "environment_evaluator.h"
#include "i_rest_api.h"
#include "rest.h"
#include "environment/trace.h"
#include "boost/uuid/uuid.hpp"
#include "boost/uuid/uuid_generators.hpp"
#include "boost/uuid/uuid_io.hpp"
#include "config.h"
#include "environment/tracing_metric.h"
using namespace std;
USE_DEBUG_FLAG(D_ENVIRONMENT);
USE_DEBUG_FLAG(D_TRACE);
class Environment::Impl
:
public Singleton::Provide<I_Environment>::From<Environment>
{
public:
void init();
void fini();
void preload();
void setActiveTenant(const string &tenant_id) override;
void unsetActiveTenant() override;
void registerContext(Context *ptr) override;
void unregisterContext(Context *ptr) override;
ActiveContexts createEnvironment() override;
ActiveContexts saveEnvironment() override;
void loadEnvironment(ActiveContexts &&env) override;
Context & getConfigurationContext() override;
map<string, string> getAllStrings(const EnvKeyAttr::ParamAttr &params) const override;
map<string, uint64_t> getAllUints(const EnvKeyAttr::ParamAttr &params) const override;
map<string, bool> getAllBools(const EnvKeyAttr::ParamAttr &params) const override;
string getCurrentTrace() const override;
string getCurrentSpan() const override;
string getCurrentHeaders() override;
void startNewTrace(bool new_span, const string &_trace_id) override;
void startNewSpan(Span::ContextType _type, const string &prev_span, const string &trace) override;
using on_exit = scope_exit<function<void(void)>>;
on_exit startNewSpanScope(Span::ContextType _type, const string &prev_span, const string &trace) override;
void finishTrace(const string &trace) override;
void finishSpan(const string &span) override;
private:
const ActiveContexts & getActiveContexts() const override { return active_contexts; }
void loadEnvConfig();
I_TenantManager *tenant_manager = nullptr;
ActiveContexts active_contexts;
Context global;
map<string, TraceWrapper> active_traces;
map<string, SpanWrapper> active_spans;
map<string, int> tracing_stats;
TracingMetric tracing_metric;
TraceEvent trace_event;
TraceFinishEvent trace_finish_event;
bool is_metric_enabled = false;
TracingStatus tracing_status = TracingStatus::OFF;
bool was_initialized = false;
};
class DeclareBooleanVariable : public ServerRest
{
public:
void
doCall() override
{
auto func = genEvaluator<bool>(expr);
if (!func.ok()) {
dbgWarning(D_ENVIRONMENT) << "Failed to generate boolean function: " << func.getErr();
return;
}
dbgTrace(D_ENVIRONMENT) << "Boolean function was generated";
auto env = Singleton::Consume<I_Environment>::from<Environment>();
env->getConfigurationContext().registerFunc(name, func.unpackMove());
}
private:
C2S_PARAM(string, name);
C2S_PARAM(string, expr);
};
void
Environment::Impl::loadEnvConfig()
{
auto tracing_conf = getConfigurationWithDefault<bool>(false, "environment", "enable tracing");
if (tracing_status == TracingStatus::DISABLED) return;
tracing_status = tracing_conf ? TracingStatus::ON : TracingStatus::OFF;
if (tracing_status == TracingStatus::ON && !is_metric_enabled) {
auto metric_report_interval = chrono::seconds(
getConfigurationWithDefault<uint>(600, "environment", "tracingMetricReportInterval")
);
tracing_metric.init(
"tracing",
ReportIS::AudienceTeam::AGENT_CORE,
ReportIS::IssuingEngine::AGENT_CORE,
metric_report_interval,
false
);
tracing_metric.registerListener();
is_metric_enabled = true;
}
}
void
Environment::Impl::init()
{
was_initialized = true;
loadEnvConfig();
if (!Singleton::exists<I_RestApi>()) return;
auto rest = Singleton::Consume<I_RestApi>::by<Environment>();
rest->addRestCall<DeclareBooleanVariable>(RestAction::ADD, "declare-boolean-variable");
}
void
Environment::Impl::fini()
{
global.deactivate();
}
void
Environment::Impl::setActiveTenant(const string &tenant_id)
{
if (tenant_manager == nullptr) tenant_manager = Singleton::Consume<I_TenantManager>::by<Environment>();
tenant_manager->addActiveTenant(tenant_id);
registerValue<string>("ActiveTenantId", tenant_id);
}
void
Environment::Impl::unsetActiveTenant()
{
getConfigurationContext().unregisterKey<string>("ActiveTenantId");
}
map<string, string>
Environment::Impl::getAllStrings(const EnvKeyAttr::ParamAttr &params) const
{
map<string, string> result;
for (auto &iter : active_contexts.first) {
auto partial_results = iter->getAllStrings(params);
for (auto &entry : partial_results) {
result.emplace(entry);
}
}
return result;
}
map<string, uint64_t>
Environment::Impl::getAllUints(const EnvKeyAttr::ParamAttr &params) const
{
map<string, uint64_t> result;
for (auto &iter : active_contexts.first) {
auto partial_results = iter->getAllUints(params);
for (auto &entry : partial_results) {
result.emplace(entry);
}
}
return result;
}
map<string, bool>
Environment::Impl::getAllBools(const EnvKeyAttr::ParamAttr &params) const
{
map<string, bool> result;
for (auto &iter : active_contexts.first) {
auto partial_results = iter->getAllBools(params);
for (auto &entry : partial_results) {
result.emplace(entry);
}
}
return result;
}
void
Environment::Impl::registerContext(Context *ptr)
{
active_contexts.first.push_back(ptr);
}
void
Environment::Impl::unregisterContext(Context *ptr)
{
dbgAssert(active_contexts.first.back() == ptr) <<
"Contexts are supposed to unregister in reverse order to their registration";
active_contexts.first.pop_back();
}
string
Environment::Impl::getCurrentTrace() const
{
if (tracing_status != TracingStatus::ON) return "";
auto trace = get<string>("trace id");
if (trace.ok()) return trace.unpack();
return "";
}
string
Environment::Impl::getCurrentSpan() const
{
if (tracing_status != TracingStatus::ON) return "";
auto span = get<string>("span id");
if (span.ok()) return span.unpack();
return "";
}
string
Environment::Impl::getCurrentHeaders()
{
string tracing_headers;
auto trace_id = getCurrentTrace();
if (!trace_id.empty()) {
tracing_headers += "X-Trace-Id: " + trace_id + "\r\n";
} else {
string correlation_id_string = "00000000-0000-0000-0000-000000000000";
try {
boost::uuids::random_generator uuid_random_gen;
correlation_id_string = boost::uuids::to_string(uuid_random_gen());
} catch (const boost::uuids::entropy_error &e) {
dbgTrace(D_ENVIRONMENT)
<< "Failed to generate random correlation id - entropy exception. Exception: "
<< e.what();
tracing_status = TracingStatus::DISABLED;
}
tracing_headers += "X-Trace-Id: " + correlation_id_string + "\r\n";
}
auto span_id = getCurrentSpan();
if (!span_id.empty()) {
tracing_headers += "X-Span-Id: " + span_id + "\r\n";
}
return tracing_headers;
}
void
Environment::Impl::startNewTrace(bool new_span, const string &_trace_id)
{
if (tracing_status != TracingStatus::ON) return;
try {
TraceWrapper trace(_trace_id);
auto trace_id = trace.getTraceId();
active_traces.emplace(trace_id, trace);
tracing_stats[trace_id] = 0;
if (new_span) {
SpanWrapper span(trace_id);
auto span_id = span.getSpanId();
active_spans.emplace(span_id, span);
}
trace_event.setTraceAmount(active_traces.size());
trace_event.notify();
} catch (const boost::uuids::entropy_error &e) {
tracing_status = TracingStatus::DISABLED;
dbgWarning(D_TRACE)
<< "Failed to generate random id - entropy exception. Exception: "
<< e.what();
return;
}
}
void
Environment::Impl::startNewSpan(Span::ContextType context_type, const string &prev_span, const string &trace)
{
if (tracing_status != TracingStatus::ON) return;
string selected_trace = !trace.empty() ? trace : getCurrentTrace();
string selected_span = !prev_span.empty() ? prev_span : getCurrentSpan();
try {
SpanWrapper span(selected_trace, context_type, selected_span);
active_spans.emplace(span.getSpanId(), span);
} catch (const boost::uuids::entropy_error &e) {
tracing_status = TracingStatus::DISABLED;
dbgWarning(D_TRACE)
<< "Failed to generate random id - entropy exception. Exception: "
<< e.what();
return;
}
}
void
Environment::Impl::finishTrace(const string &trace)
{
if (tracing_status != TracingStatus::ON) return;
auto deleted_trace = trace.empty() ? getCurrentTrace() : trace;
if (deleted_trace.empty()) {
dbgWarning(D_ENVIRONMENT) << "There is no current trace to finish";
return;
}
trace_finish_event.setSpanAmount(tracing_stats[deleted_trace]);
active_traces.erase(deleted_trace);
tracing_stats.erase(deleted_trace);
trace_event.setTraceAmount(active_traces.size());
trace_event.notify();
trace_finish_event.notify();
}
void
Environment::Impl::finishSpan(const string &span)
{
if (tracing_status != TracingStatus::ON) return;
auto deleted_span = span.empty() ? getCurrentSpan() : span;
if (deleted_span.empty()) {
dbgWarning(D_ENVIRONMENT) << "There is no current span to finish";
return;
}
auto span_iter = active_spans.find(deleted_span);
if (span_iter != active_spans.end()) {
auto trace_id = span_iter->second.getTraceId();
tracing_stats[trace_id]++;
}
active_spans.erase(deleted_span);
}
scope_exit<function<void(void)>>
Environment::Impl::startNewSpanScope(Span::ContextType context_type, const string &prev_span, const string &trace)
{
startNewSpan(context_type, prev_span, trace);
function<void(void)> release_function = [&] () { finishSpan(""); };
return make_scope_exit(move(release_function));
}
I_Environment::ActiveContexts
Environment::Impl::createEnvironment()
{
return ActiveContexts({ &global }, Debug::DebugLockState::getState());
}
I_Environment::ActiveContexts
Environment::Impl::saveEnvironment()
{
return move(active_contexts);
}
void
Environment::Impl::loadEnvironment(ActiveContexts &&env)
{
active_contexts = move(env);
Debug::DebugLockState::setState(active_contexts.second);
}
Context &
Environment::Impl::getConfigurationContext()
{
return global;
}
void
Environment::Impl::preload()
{
registerBaseEvaluators();
global.activate();
registerExpectedConfiguration<bool>("environment", "enable tracing");
registerExpectedConfiguration<uint>("environment", "tracingMetricReportInterval");
registerConfigLoadCb(
[this] ()
{
if (was_initialized) loadEnvConfig();
}
);
}
Environment::Environment() : Component("Environment"), pimpl(make_unique<Impl>()) {}
Environment::~Environment() {}
void
Environment::init()
{
pimpl->init();
}
void
Environment::fini()
{
pimpl->fini();
}
void
Environment::preload()
{
pimpl->preload();
}

View File

@@ -0,0 +1,5 @@
add_unit_test(
environment_ut
"context_ut.cc;parsing_ut.cc;base_evaluators_ut.cc;environment_rest_ut.cc;span_ut.cc;trace_ut.cc;tracing_ut.cc;environment_ut.cc"
"environment;singleton;rest;mainloop;metric;-lboost_context;event_is;-lboost_regex"
)

View File

@@ -0,0 +1,199 @@
#include "environment_evaluator.h"
#include "cptest.h"
#include "environment.h"
#include "config.h"
#include "config_component.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_time_get.h"
using namespace std;
using namespace testing;
class EvaluatorTest : public Test
{
public:
EvaluatorTest() {
env.preload();
env.init();
}
~EvaluatorTest() {
env.fini();
}
private:
NiceMock<MockMainLoop> mock_mainloop;
NiceMock<MockTimeGet> mock_timer;
ConfigComponent conf;
::Environment env;
};
std::ostream & operator<<(std::ostream &os, const Context::Error &);
std::ostream &
operator<<(std::ostream &os, const std::function<Maybe<bool, Context::Error>()> &)
{
return os;
}
TEST_F(EvaluatorTest, empty_all)
{
auto eval = genEvaluator<bool>("All()");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(true));
}
TEST_F(EvaluatorTest, empty_any)
{
auto eval = genEvaluator<bool>("Any()");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(false));
}
TEST_F(EvaluatorTest, not_true)
{
auto eval = genEvaluator<bool>("Not(All())");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(false));
}
TEST_F(EvaluatorTest, not_false)
{
auto eval = genEvaluator<bool>("Not(Any())");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(true));
}
TEST_F(EvaluatorTest, no_true_any)
{
auto eval = genEvaluator<bool>("Any(Any(),Any(),Any())");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(false));
}
TEST_F(EvaluatorTest, one_true_any)
{
auto eval = genEvaluator<bool>("Any(Any(),All(),Any())");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(true));
}
TEST_F(EvaluatorTest, one_false_all)
{
auto eval = genEvaluator<bool>("All(All(),All(),Any())");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(false));
}
TEST_F(EvaluatorTest, all_true_all)
{
auto eval = genEvaluator<bool>("All(All(),All(),All())");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(true));
}
TEST_F(EvaluatorTest, all_true_all_with_spaces)
{
auto eval = genEvaluator<bool>("All(All() , All( ) ,All() )");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(true));
}
TEST_F(EvaluatorTest, select_all_all)
{
auto eval = genEvaluator<bool>("Select(All(),All())");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(true));
}
TEST_F(EvaluatorTest, select_all_any)
{
auto eval = genEvaluator<bool>("Select(All(),Any())");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(true));
}
TEST_F(EvaluatorTest, select_any_all)
{
auto eval = genEvaluator<bool>("Select(Any(),All())");
EXPECT_TRUE(eval.ok());
auto function = eval.unpack();
EXPECT_THAT(function(), IsValue(false));
}
TEST_F(EvaluatorTest, empty_not)
{
auto eval = genEvaluator<bool>("Not()");
EXPECT_THAT(eval, IsError("Wrong number of parameters for 'Not'. Got 0 parameters instead of expected 1"));
}
TEST_F(EvaluatorTest, too_many_inputs_not)
{
auto eval = genEvaluator<bool>("Not(Any(), Any())");
EXPECT_THAT(eval, IsError("Wrong number of parameters for 'Not'. Got 2 parameters instead of expected 1"));
}
TEST_F(EvaluatorTest, malformed_evaluator_leading_comma)
{
auto eval = genEvaluator<bool>("Any(, Any())");
EXPECT_THAT(eval, IsError("Could not find the opening bracket in the string"));
}
TEST_F(EvaluatorTest, malformed_evaluator_fake_evaluator)
{
auto eval = genEvaluator<bool>("Not(NOTHING())");
EXPECT_THAT(eval, IsError("Evaluator 'NOTHING' doesn't exist for the required type"));
}
TEST_F(EvaluatorTest, malformed_evaluator_fake_evaluator2)
{
auto eval = genEvaluator<bool>("All(Any(), NOTHING())");
EXPECT_THAT(eval, IsError("Evaluator 'NOTHING' doesn't exist for the required type"));
}
TEST_F(EvaluatorTest, empty_get)
{
auto eval = genEvaluator<bool>("Get()");
EXPECT_THAT(eval, IsError("Wrong number of parameters for 'Get'. Got 0 parameters instead of expected 1"));
}
TEST_F(EvaluatorTest, empty_select)
{
auto eval = genEvaluator<bool>("Select()");
EXPECT_THAT(
eval,
IsError("Wrong number of parameters for 'Select'. Got 0 parameters instead of expected more than 2")
);
}
TEST_F(EvaluatorTest, single_in_select)
{
auto eval = genEvaluator<bool>("Select(one)");
EXPECT_THAT(
eval,
IsError("Wrong number of parameters for 'Select'. Got 1 parameters instead of expected more than 2")
);
}
TEST_F(EvaluatorTest, select_bad_evaluators)
{
auto eval = genEvaluator<bool>("Select(X(),Y())");
EXPECT_THAT(eval, IsError("Evaluator 'X' doesn't exist for the required type"));
}
TEST_F(EvaluatorTest, malformed_evaluator_within_parameter)
{
auto eval = genEvaluator<bool>("Any(All(), Any(BOB()))");
EXPECT_THAT(eval, IsError("Evaluator 'BOB' doesn't exist for the required type"));
}

View File

@@ -0,0 +1,237 @@
#include "cptest.h"
#include "context.h"
#include "environment.h"
#include "config.h"
#include "config_component.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_time_get.h"
using namespace std;
using namespace testing;
class ContextTest : public Test
{
public:
Context ctx;
class TestObject
{
public:
TestObject(const string &_x, int _y) : x(_x), y(_y) {};
bool
operator==(const TestObject &rsh) const
{
return x == rsh.x && y == rsh.y;
}
private:
string x;
int y;
};
static Maybe<int, Context::Error> maybeIntFunc() { return 1; }
static Maybe<double, Context::Error> maybeDoubleFunc() { return 1.1; }
static Maybe<string, Context::Error> maybeStrFunc() { return string("str1"); }
static Maybe<char, Context::Error> maybeCharFunc() { return 'a'; }
static Maybe<TestObject, Context::Error> maybeObjectFunc() { return ContextTest::TestObject("test_object", 1); }
static int intFunc() { return 2; }
static double doubleFunc() { return 2.2; }
static string strFunc() { return string("str2"); }
static char charFunc() { return 'b'; }
static TestObject objectFunc() { return ContextTest::TestObject("test_object", 2); }
};
std::ostream &
operator<<(std::ostream &os, const Context::Error &)
{
return os;
}
std::ostream &
operator<<(std::ostream &os, const ContextTest::TestObject &)
{
return os;
}
TEST_F(ContextTest, register_int)
{
ctx.registerValue("_int", 10);
EXPECT_THAT(ctx.get<int>("_int"), IsValue(10));
}
TEST_F(ContextTest, register_double)
{
ctx.registerValue("_double", 2.2);
EXPECT_THAT(ctx.get<double>("_double"), IsValue(2.2));
}
TEST_F(ContextTest, register_char)
{
ctx.registerValue("_char", 'a');
EXPECT_THAT(ctx.get<char>("_char"), IsValue('a'));
}
TEST_F(ContextTest, register_string)
{
ctx.registerValue("_string", string("string"));
EXPECT_THAT(ctx.get<string>("_string"), IsValue("string"));
}
TEST_F(ContextTest, register_object)
{
ctx.registerValue("_obj", ContextTest::TestObject("value", 1));
EXPECT_THAT(ctx.get<TestObject>("_obj"), IsValue(ContextTest::TestObject("value", 1)));
}
TEST_F(ContextTest, register_2_values_same_key)
{
ctx.registerValue("same_value_key", 1);
ctx.registerValue("same_value_key", 2);
EXPECT_THAT(ctx.get<int>("same_value_key"), IsValue(2));
}
TEST_F(ContextTest, register_2_values_same_key_diff_context)
{
ConfigComponent conf;
NiceMock<MockMainLoop> mock_mainloop;
NiceMock<MockTimeGet> mock_timer;
::Environment env;
auto i_env = Singleton::Consume<I_Environment>::from(env);
ctx.registerValue("same_value_key", 1);
ctx.activate();
EXPECT_THAT(i_env->get<int>("same_value_key"), IsValue(1));
Context another_ctx;
another_ctx.registerValue("same_value_key", 2);
another_ctx.activate();
EXPECT_THAT(i_env->get<int>("same_value_key"), IsValue(2));
}
TEST_F(ContextTest, register_2_func_same_key)
{
ctx.registerFunc<int>("same_func_key", ContextTest::maybeIntFunc);
ctx.registerFunc<double>("same_func_key", ContextTest::maybeDoubleFunc);
EXPECT_THAT(ctx.get<double>("same_func_key"), IsValue(1.1));
}
TEST_F(ContextTest, register_return_maybe_obj_func)
{
ctx.registerFunc<TestObject>("maybe_obj_func", ContextTest::maybeObjectFunc);
EXPECT_THAT(ctx.get<TestObject>("maybe_obj_func"), IsValue(ContextTest::TestObject("test_object", 1)));
}
TEST_F(ContextTest, register_return_maybe_int_func)
{
ctx.registerFunc<int>("maybe_int_func", ContextTest::maybeIntFunc);
EXPECT_THAT(ctx.get<int>("maybe_int_func"), IsValue(1));
}
TEST_F(ContextTest, register_return_maybe_str_func)
{
ctx.registerFunc<string>("maybe_str_func", ContextTest::maybeStrFunc);
EXPECT_THAT(ctx.get<string>("maybe_str_func"), IsValue("str1"));
}
TEST_F(ContextTest, register_return_maybe_double_func)
{
ctx.registerFunc<double>("maybe_double_func", ContextTest::maybeDoubleFunc);
EXPECT_THAT(ctx.get<double>("maybe_double_func"), IsValue(1.1));
}
TEST_F(ContextTest, register_return_maybe_char_func)
{
ctx.registerFunc<char>("maybe_char_func", ContextTest::maybeCharFunc);
EXPECT_THAT(ctx.get<char>("maybe_char_func"), IsValue('a'));
}
TEST_F(ContextTest, register_return_obj_func)
{
ctx.registerFunc<TestObject>("obj_func", ContextTest::objectFunc);
EXPECT_THAT(ctx.get<TestObject>("obj_func"), IsValue(ContextTest::TestObject("test_object", 2)));
}
TEST_F(ContextTest, register_return_int_func)
{
ctx.registerFunc<int>("int_func", ContextTest::intFunc);
EXPECT_THAT(ctx.get<int>("int_func"), IsValue(2));
}
TEST_F(ContextTest, register_return_str_func)
{
ctx.registerFunc<string>("str_func", ContextTest::strFunc);
EXPECT_THAT(ctx.get<string>("str_func"), IsValue("str2"));
}
TEST_F(ContextTest, register_return_double_func)
{
ctx.registerFunc<double>("double_func", ContextTest::doubleFunc);
EXPECT_THAT(ctx.get<double>("double_func"), IsValue(2.2));
}
TEST_F(ContextTest, register_return_char_func)
{
ctx.registerFunc<char>("char_func", ContextTest::charFunc);
EXPECT_THAT(ctx.get<char>("char_func"), IsValue('b'));
}
TEST_F(ContextTest, get_wrong_type_value)
{
ctx.registerValue("wrong_type", 1);
EXPECT_THAT(ctx.get<string>("wrong_type"), IsError(Context::Error::NO_VALUE));
}
TEST_F(ContextTest, get_wrong_key_name)
{
ctx.registerValue("wrong_key", 1);
EXPECT_THAT(ctx.get<int>("wrong_keyy"), IsError(Context::Error::NO_VALUE));
}
TEST_F(ContextTest, unregister_key_of_value)
{
ctx.registerValue("new_value_key", 1);
ctx.unregisterKey<int>("new_value_key");
EXPECT_THAT(ctx.get<int>("new_value_key"), IsError(Context::Error::NO_VALUE));
}
TEST_F(ContextTest, unregister_key_of_func)
{
ctx.registerFunc<int>("new_func_key", maybeIntFunc);
ctx.unregisterKey<int>("new_func_key");
EXPECT_THAT(ctx.get<int>("new_func_key"), IsError(Context::Error::NO_VALUE));
}
TEST(ParamTest, matching)
{
using namespace EnvKeyAttr;
ParamAttr empty;
ParamAttr verb1(Verbosity::LOW);
ParamAttr verb2(Verbosity::HIGH);
ParamAttr log(LogSection::SOURCE);
ParamAttr both1(LogSection::SOURCE, Verbosity::LOW);
ParamAttr both2(Verbosity::LOW, LogSection::SOURCE);
ParamAttr both3(LogSection::SOURCE, Verbosity::HIGH);
EXPECT_TRUE(empty.doesMatch(empty));
EXPECT_TRUE(verb1.doesMatch(empty));
EXPECT_TRUE(log.doesMatch(empty));
EXPECT_TRUE(both1.doesMatch(empty));
EXPECT_FALSE(empty.doesMatch(verb1));
EXPECT_FALSE(empty.doesMatch(log));
EXPECT_FALSE(empty.doesMatch(both1));
EXPECT_TRUE(verb1.doesMatch(verb1));
EXPECT_TRUE(both1.doesMatch(verb1));
EXPECT_FALSE(verb2.doesMatch(verb1));
EXPECT_FALSE(log.doesMatch(verb1));
EXPECT_FALSE(both3.doesMatch(verb1));
EXPECT_TRUE(both1.doesMatch(log));
EXPECT_TRUE(both1.doesMatch(both1));
EXPECT_TRUE(both1.doesMatch(both2));
EXPECT_FALSE(both1.doesMatch(both3));
}

View File

@@ -0,0 +1,68 @@
#include "environment.h"
#include "cptest.h"
#include "mock/mock_rest_api.h"
#include "config.h"
#include "config_component.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_time_get.h"
using namespace std;
using namespace testing;
class EnvRestTest : public Test
{
public:
EnvRestTest()
{
EXPECT_CALL(mock_rs, mockRestCall(RestAction::ADD, "declare-boolean-variable", _))
.WillOnce(WithArg<2>(Invoke(this, &EnvRestTest::declareVariable)));
env.preload();
env.init();
i_env = Singleton::Consume<I_Environment>::from(env);
}
unique_ptr<ServerRest> declare_variable;
I_Environment *i_env;
private:
bool declareVariable(const unique_ptr<RestInit> &p) { declare_variable = p->getRest(); return true; }
NiceMock<MockMainLoop> mock_mainloop;
NiceMock<MockTimeGet> mock_timer;
ConfigComponent conf;
::Environment env;
StrictMock<MockRestApi> mock_rs;
};
static ostream & operator<<(ostream &os, const Context::Error &) { return os; }
TEST_F(EnvRestTest, declare_variable)
{
EXPECT_THAT(i_env->get<bool>("true_val"), IsError(Context::Error::NO_VALUE));
stringstream is;
is << "{\"name\": \"true_val\", \"expr\": \"All()\"}";
auto output = declare_variable->performRestCall(is);
EXPECT_THAT(output, IsValue(""));
EXPECT_THAT(i_env->get<bool>("true_val"), IsValue(true));
}
TEST_F(EnvRestTest, no_expr)
{
stringstream is;
is << "{\"name\": \"true_val\"}";
auto output = declare_variable->performRestCall(is);
EXPECT_THAT(output, IsError("Couldn't get variable expr"));
}
TEST_F(EnvRestTest, no_name)
{
stringstream is;
is << "{\"expr\": \"All()\"}";
auto output = declare_variable->performRestCall(is);
EXPECT_THAT(output, IsError("Couldn't get variable name"));
}

View File

@@ -0,0 +1,87 @@
#include "environment.h"
#include "cptest.h"
using namespace testing;
using namespace std;
class EnvironmentTest : public Test
{
public:
EnvironmentTest() { ctx.activate(); ctx2.activate(); }
~EnvironmentTest() { ctx2.deactivate(); ctx.deactivate(); }
::Environment env;
I_Environment *i_env = Singleton::Consume<I_Environment>::from(env);
Context ctx, ctx2;
};
class ConvertableToString
{
public:
ConvertableToString(int _i, int _j) : i(_i), j(_j) {}
int i, j;
};
ostream &
operator<<(ostream &os, const ConvertableToString &obj)
{
return os << obj.i << "---" << obj.j;
}
TEST_F(EnvironmentTest, all_strings)
{
string key_a = "A";
string key_b = "B";
string key_c = "C";
string key_d = "D";
string key_e = "E";
string key_f = "F";
string key_g = "G";
string val_num = "123";
string val_alpha = "abc";
ctx.registerValue(key_a, val_num);
ctx.registerValue(key_b, val_alpha, EnvKeyAttr::LogSection::SOURCE);
ctx.registerValue(key_c, ConvertableToString(2, 9), EnvKeyAttr::LogSection::DATA, EnvKeyAttr::Verbosity::LOW);
ctx.registerValue(key_g, false, EnvKeyAttr::Verbosity::HIGH);
ctx2.registerValue(key_d, ConvertableToString(5, 3), EnvKeyAttr::LogSection::DATA);
ctx2.registerValue(key_e, 9);
ctx2.registerValue(key_f, true);
EXPECT_THAT(
i_env->getAllStrings(),
UnorderedElementsAre(
make_pair(key_a, val_num),
make_pair(key_b, val_alpha),
make_pair(key_d, "5---3"),
make_pair(key_c, "2---9")
)
);
EXPECT_THAT(
i_env->getAllStrings(EnvKeyAttr::Verbosity::HIGH),
UnorderedElementsAre()
);
EXPECT_THAT(
i_env->getAllStrings(EnvKeyAttr::LogSection::SOURCE),
UnorderedElementsAre(
make_pair(key_b, val_alpha)
)
);
EXPECT_THAT(
i_env->getAllStrings(EnvKeyAttr::LogSection::DATA),
UnorderedElementsAre(
make_pair(key_d, "5---3"),
make_pair(key_c, "2---9")
)
);
EXPECT_THAT(i_env->getAllUints(), UnorderedElementsAre(make_pair(key_e, 9)));
EXPECT_THAT(i_env->getAllBools(), UnorderedElementsAre(make_pair(key_f, true), make_pair(key_g, false)));
}

View File

@@ -0,0 +1,156 @@
#include "cptest.h"
#include "environment_evaluator.h"
using namespace std;
using namespace testing;
using namespace EnvironmentHelper;
static const string error = "EvaluatorParseError not thrown as it should have been! Test Failed.";
TEST(ParsingTest, wrong_param_number_test_range)
{
try {
reportWrongNumberOfParams("wrong_param_number_test_range", 4, 1, 3);
}
catch (EvaluatorParseError e) {
string output = e.getError();
string expected = "Wrong number of parameters for 'wrong_param_number_test_range'. "
"Got 4 parameters instead of expected between 1 and 3";
EXPECT_EQ(output, expected);
return;
}
ADD_FAILURE() << error;
}
TEST(ParsingTest, wrong_param_number_test_min_eq_max)
{
try {
reportWrongNumberOfParams("wrong_param_number_test_min_eq_max", 0, 1, 1);
}
catch (EvaluatorParseError e) {
string output = e.getError();
string expected = "Wrong number of parameters for 'wrong_param_number_test_min_eq_max'. "
"Got 0 parameters instead of expected 1";
EXPECT_EQ(output, expected);
return;
}
ADD_FAILURE() << error;
}
TEST(ParsingTest, wrong_param_number_test_too_few)
{
try {
reportWrongNumberOfParams("wrong_param_number_test_too_few", 0, 2, -1);
}
catch (EvaluatorParseError e) {
string output = e.getError();
string expected = "Wrong number of parameters for 'wrong_param_number_test_too_few'. "
"Got 0 parameters instead of expected more than 2";
EXPECT_EQ(output, expected);
return;
}
ADD_FAILURE() << error;
}
TEST(ParsingTest, wrong_param_type_test)
{
try {
reportWrongParamType("wrong_param_type_test", "bad_param", "good_reason");
}
catch (EvaluatorParseError e) {
string output = e.getError();
string expected = "Parameter 'bad_param' for 'wrong_param_type_test' is of the "
"wrong type because: good_reason";
EXPECT_EQ(output, expected);
return;
}
ADD_FAILURE() << error;
}
TEST(ParsingTest, unkown_evaluator_type_test)
{
try {
reportUnknownEvaluatorType("bad_eval");
}
catch (EvaluatorParseError e) {
string output = e.getError();
string expected = "Evaluator 'bad_eval' doesn't exist for the required type";
EXPECT_EQ(output, expected);
return;
}
ADD_FAILURE() << error;
}
TEST(ParsingTest, break_to_params_test_empty_input)
{
vector<string> res;
EXPECT_EQ(breakEvaluatorString("()").second, res);
}
TEST(ParsingTest, break_to_params_test_single_in)
{
vector<string> res = { "(X)" };
EXPECT_EQ(breakEvaluatorString("((X))").second, res);
}
TEST(ParsingTest, break_to_params_common_use)
{
vector<string> res = { "a", "1234 asd", "((1+2)*3)" };
EXPECT_EQ(breakEvaluatorString("(a , 1234 asd ,((1+2)*3))").second, res);
}
TEST(ParsingTest, break_to_params_test_commas_and_ignore_spaces)
{
vector<string> res = { "", "", "" };
EXPECT_EQ(breakEvaluatorString("(,, , )").second, res);
}
TEST(ParsingTest, break_to_params_bracket_games)
{
vector<string> res = { ") ,x x(()", ")))," };
EXPECT_EQ(breakEvaluatorString("() ,x x((),))),)").second, res);
}
TEST(ParsingTest, break_evaluator_string_test_empty_legal_input)
{
string normalized = "()";
auto pair = breakEvaluatorString(normalized);
string s = "";
vector<string> v;
EXPECT_EQ(pair, make_pair(s, v));
}
TEST(ParsingTest, break_evaluator_string_test_legal_input)
{
string normalized = "CMD((3 + 3 ) * 7 (), abc)";
auto pair = breakEvaluatorString(normalized);
string s = "CMD";
vector<string> v = { "(3 + 3 ) * 7 ()", "abc" };
EXPECT_EQ(pair, make_pair(s, v));
}
TEST(ParsingTest, break_evaluator_string_test_no_open_bracket)
{
try {
breakEvaluatorString("EVALUATOR)");
}
catch (EvaluatorParseError e) {
EXPECT_EQ(e.getError(), "Could not find the opening bracket in the string");
return;
}
ADD_FAILURE() << error;
}
TEST(ParsingTest, break_evaluator_string_test_no_close_bracket)
{
try {
breakEvaluatorString("EVALUATOR(x+1 = 3");
}
catch (EvaluatorParseError e) {
EXPECT_EQ(e.getError(), "Could not find the closing bracket in the string");
return;
}
ADD_FAILURE() << error;
}

View File

@@ -0,0 +1,95 @@
#include "environment/span.h"
#include "cptest.h"
#include "environment.h"
#include "debug.h"
#include "config.h"
#include "config_component.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_time_get.h"
using namespace std;
using namespace testing;
USE_DEBUG_FLAG(D_TRACE);
class SpanTest : public Test
{
public:
SpanTest()
{
Debug::setNewDefaultStdout(&debug_output);
Debug::setUnitTestFlag(D_TRACE, Debug::DebugLevel::TRACE);
}
~SpanTest()
{
Debug::setNewDefaultStdout(&cout);
}
template <typename T>
void
getSpanValues(const T &span)
{
trace_id_str = span.getTraceId();
span_id_str = span.getSpanId();
prev_id_str = span.getPrevSpanId();
type = span.getSpanContextType();
}
NiceMock<MockMainLoop> mock_mainloop;
NiceMock<MockTimeGet> mock_timer;
ConfigComponent conf;
::Environment env;
stringstream debug_output;
string trace_id = "4cc6bce7-4f68-42d6-94fc-e4127ac65ded";
string prev_span_id = "4cc6bce7-4f68-42d6-94fc-e4127ac65fef";
string trace_id_str;
string span_id_str;
string prev_id_str;
Span::ContextType type = Span::ContextType::NEW;
};
TEST_F(SpanTest, newSpanInNewTraceTest)
{
{
Span span(trace_id);
getSpanValues<Span>(span);
}
EXPECT_EQ(type, Span::ContextType::NEW);
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + span_id_str));
EXPECT_THAT(debug_output.str(), HasSubstr("trace id "+ trace_id_str));
EXPECT_THAT(debug_output.str(), HasSubstr("context type New"));
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + span_id_str));
}
TEST_F(SpanTest, newSpanTest)
{
{
Span span(trace_id, Span::ContextType::CHILD_OF, prev_span_id);
getSpanValues<Span>(span);
}
EXPECT_EQ(type, Span::ContextType::CHILD_OF);
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + span_id_str));
EXPECT_THAT(debug_output.str(), HasSubstr("trace id " + trace_id_str));
EXPECT_THAT(debug_output.str(), HasSubstr("context type Child of"));
EXPECT_THAT(debug_output.str(), HasSubstr("previous span id " + prev_id_str));
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + span_id_str));
}
TEST_F(SpanTest, newSpanWrapperTest)
{
{
SpanWrapper span(trace_id, Span::ContextType::CHILD_OF, prev_span_id);
getSpanValues<SpanWrapper>(span);
}
EXPECT_EQ(type, Span::ContextType::CHILD_OF);
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + span_id_str));
EXPECT_THAT(debug_output.str(), HasSubstr("trace id " + trace_id_str));
EXPECT_THAT(debug_output.str(), HasSubstr("context type Child of"));
EXPECT_THAT(debug_output.str(), HasSubstr("previous span id " + prev_id_str));
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + span_id_str));
}

View File

@@ -0,0 +1,59 @@
#include "environment/trace.h"
#include "cptest.h"
#include "environment.h"
#include "debug.h"
#include "config.h"
#include "config_component.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_time_get.h"
using namespace std;
using namespace testing;
USE_DEBUG_FLAG(D_TRACE);
class TraceTest : public Test
{
public:
TraceTest()
{
Debug::setNewDefaultStdout(&debug_output);
Debug::setUnitTestFlag(D_TRACE, Debug::DebugLevel::TRACE);
}
~TraceTest()
{
Debug::setNewDefaultStdout(&cout);
}
NiceMock<MockMainLoop> mock_mainloop;
NiceMock<MockTimeGet> mock_timer;
ConfigComponent conf;
::Environment env;
stringstream debug_output;
};
TEST_F(TraceTest, defaultTraceTest)
{
string trace_id;
{
Trace trace;
trace_id = trace.getTraceId();
}
EXPECT_THAT(debug_output.str(), HasSubstr("New trace was created " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("Current trace has ended " + trace_id));
}
TEST_F(TraceTest, nonDefaultTraceTest)
{
string trace_id("4cc6bce7-4f68-42d6-94fc-e4127ac65ded");
string trace_id_str;
{
Trace trace(trace_id);
trace_id_str = trace.getTraceId();
}
EXPECT_THAT(debug_output.str(), HasSubstr("New trace was created " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("Current trace has ended " + trace_id));
}

View File

@@ -0,0 +1,384 @@
#include "environment.h"
#include "cptest.h"
#include "i_mainloop.h"
#include "mainloop.h"
#include "config.h"
#include "config_component.h"
#include "mock/mock_time_get.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_messaging.h"
#include "mock/mock_agent_details.h"
#include "config.h"
using namespace std;
using namespace testing;
USE_DEBUG_FLAG(D_TRACE);
USE_DEBUG_FLAG(D_METRICS);
class TracingTest : public Test
{
public:
TracingTest()
{
env.preload();
i_env = Singleton::Consume<I_Environment>::from(env);
Debug::setNewDefaultStdout(&debug_output);
Debug::setUnitTestFlag(D_TRACE, Debug::DebugLevel::TRACE);
Debug::setUnitTestFlag(D_METRICS, Debug::DebugLevel::TRACE);
setConfiguration<bool>(true, "environment", "enable tracing");
setConfiguration<bool>(false, string("metric"), string("fogMetricSendEnable"));
EXPECT_CALL(mock_mainloop, addRecurringRoutine(I_MainLoop::RoutineType::System, _, _, _, _))
.WillOnce(DoAll(SaveArg<2>(&routine), Return(0)));
env.init();
}
~TracingTest()
{
Debug::setNewDefaultStdout(&cout);
}
I_MainLoop::Routine routine;
StrictMock<MockMainLoop> mock_mainloop;
StrictMock<MockTimeGet> mock_timer;
ConfigComponent conf;
::Environment env;
I_Environment *i_env;
stringstream debug_output;
};
TEST_F(TracingTest, noTraceTest)
{
auto empty_trace = i_env->getCurrentTrace();
EXPECT_EQ("", empty_trace);
auto empty_span = i_env->getCurrentSpan();
EXPECT_EQ("", empty_span);
}
TEST_F(TracingTest, disabledTraces)
{
setConfiguration<bool>(false, "environment", "enable tracing");
env.init();
i_env->startNewTrace();
auto trace_id = i_env->getCurrentTrace();
auto span_id = i_env->getCurrentSpan();
EXPECT_EQ("", i_env->getCurrentSpan());
EXPECT_EQ("", i_env->getCurrentTrace());
EXPECT_EQ("", debug_output.str());
i_env->finishSpan();
EXPECT_EQ("", debug_output.str());
EXPECT_EQ("", i_env->getCurrentSpan());
i_env->finishTrace();
EXPECT_EQ("", debug_output.str());
EXPECT_EQ("", i_env->getCurrentTrace());
}
TEST_F(TracingTest, newTraceSpanTest)
{
i_env->startNewTrace();
auto trace_id = i_env->getCurrentTrace();
auto span_id = i_env->getCurrentSpan();
EXPECT_NE("", i_env->getCurrentSpan());
EXPECT_NE("", i_env->getCurrentTrace());
EXPECT_THAT(debug_output.str(), HasSubstr("New trace was created " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + span_id));
EXPECT_THAT(debug_output.str(), HasSubstr(", trace id " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr(", context type New"));
i_env->finishSpan();
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + span_id));
EXPECT_EQ("", i_env->getCurrentSpan());
routine();
EXPECT_THAT(debug_output.str(), HasSubstr("\"Metric\": \"tracing\""));
EXPECT_THAT(debug_output.str(), HasSubstr("\"currentTraceNumber\": 1"));
i_env->finishTrace();
EXPECT_THAT(debug_output.str(), HasSubstr("Current trace has ended " + trace_id));
EXPECT_EQ("", i_env->getCurrentTrace());
routine();
EXPECT_THAT(debug_output.str(), HasSubstr("\"Metric\": \"tracing\""));
EXPECT_THAT(debug_output.str(), HasSubstr("\"currentTraceNumber\": 0"));
EXPECT_THAT(debug_output.str(), HasSubstr("\"maxSpanPerTrace\": 1"));
EXPECT_THAT(debug_output.str(), HasSubstr("\"avgSpanPerTrace\": 1.0"));
}
TEST_F(TracingTest, newSpanScopeTest)
{
string trace_id;
string span_id;
i_env->startNewTrace(false);
EXPECT_NE("", i_env->getCurrentTrace());
EXPECT_EQ("", i_env->getCurrentSpan());
trace_id = i_env->getCurrentTrace();
EXPECT_THAT(debug_output.str(), HasSubstr("New trace was created " + trace_id));
{
auto span_scope = i_env->startNewSpanScope(Span::ContextType::NEW);
span_id = i_env->getCurrentSpan();
EXPECT_NE("", i_env->getCurrentSpan());
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + span_id));
EXPECT_THAT(debug_output.str(), HasSubstr(", trace id " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr(", context type New"));
EXPECT_NE("", i_env->getCurrentSpan());
}
EXPECT_EQ("", i_env->getCurrentSpan());
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + span_id));
i_env->finishTrace();
EXPECT_THAT(debug_output.str(), HasSubstr("Current trace has ended " + trace_id));
EXPECT_EQ("", i_env->getCurrentTrace());
routine();
EXPECT_THAT(debug_output.str(), HasSubstr("\"Metric\": \"tracing\""));
EXPECT_THAT(debug_output.str(), HasSubstr("\"currentTraceNumber\": 0"));
EXPECT_THAT(debug_output.str(), HasSubstr("\"maxSpanPerTrace\": 1"));
EXPECT_THAT(debug_output.str(), HasSubstr("\"avgSpanPerTrace\": 1.0"));
}
TEST_F(TracingTest, oldTraceNewSpanTest)
{
i_env->startNewTrace(true, "a687b388-1108-4083-9852-07c33b1074e9");
auto trace_id = i_env->getCurrentTrace();
auto span_id = i_env->getCurrentSpan();
EXPECT_EQ(trace_id, "a687b388-1108-4083-9852-07c33b1074e9");
EXPECT_NE("", i_env->getCurrentSpan());
EXPECT_NE("", i_env->getCurrentTrace());
EXPECT_THAT(debug_output.str(), HasSubstr("New trace was created " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + span_id));
EXPECT_THAT(debug_output.str(), HasSubstr("trace id " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("context type New"));
i_env->finishSpan();
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + span_id));
EXPECT_EQ("", i_env->getCurrentSpan());
i_env->finishTrace();
EXPECT_THAT(debug_output.str(), HasSubstr("Current trace has ended " + trace_id));
EXPECT_EQ("", i_env->getCurrentTrace());
}
TEST_F(TracingTest, finishSpecificTraceSpan)
{
i_env->startNewTrace(true, "a687b388-1108-4083-9852-07c33b1074e9");
auto trace_id = i_env->getCurrentTrace();
auto span_id = i_env->getCurrentSpan();
EXPECT_EQ(trace_id, "a687b388-1108-4083-9852-07c33b1074e9");
EXPECT_NE("", i_env->getCurrentSpan());
EXPECT_NE("", i_env->getCurrentTrace());
EXPECT_THAT(debug_output.str(), HasSubstr("New trace was created " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + span_id));
EXPECT_THAT(debug_output.str(), HasSubstr("trace id " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("context type New"));
i_env->finishSpan(span_id);
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + span_id));
EXPECT_EQ("", i_env->getCurrentSpan());
i_env->finishTrace(trace_id);
EXPECT_THAT(debug_output.str(), HasSubstr("Current trace has ended " + trace_id));
EXPECT_EQ("", i_env->getCurrentTrace());
}
TEST_F(TracingTest, 2SpansSameFlow)
{
i_env->startNewTrace(true, "a687b388-1108-4083-9852-07c33b1074e9");
auto trace_id = i_env->getCurrentTrace();
auto span_id = i_env->getCurrentSpan();
EXPECT_EQ(trace_id, "a687b388-1108-4083-9852-07c33b1074e9");
EXPECT_NE("", i_env->getCurrentSpan());
EXPECT_NE("", i_env->getCurrentTrace());
EXPECT_THAT(debug_output.str(), HasSubstr("New trace was created " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + span_id));
EXPECT_THAT(debug_output.str(), HasSubstr("trace id " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("context type New"));
i_env->finishSpan();
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + span_id));
EXPECT_EQ("", i_env->getCurrentSpan());
i_env->startNewSpan(Span::ContextType::FOLLOWS_FROM, span_id);
auto another_span_id = i_env->getCurrentSpan();
EXPECT_EQ(trace_id, i_env->getCurrentTrace());
EXPECT_NE(another_span_id, span_id);
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + another_span_id));
EXPECT_THAT(debug_output.str(), HasSubstr("trace id " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("context type Follows from"));
i_env->finishSpan();
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + another_span_id));
EXPECT_EQ("", i_env->getCurrentSpan());
i_env->finishTrace();
EXPECT_THAT(debug_output.str(), HasSubstr("Current trace has ended " + trace_id));
EXPECT_EQ("", i_env->getCurrentTrace());
routine();
EXPECT_THAT(debug_output.str(), HasSubstr("\"Metric\": \"tracing\""));
EXPECT_THAT(debug_output.str(), HasSubstr("\"currentTraceNumber\": 0"));
EXPECT_THAT(debug_output.str(), HasSubstr("\"maxSpanPerTrace\": 2"));
EXPECT_THAT(debug_output.str(), HasSubstr("\"avgSpanPerTrace\": 2.0"));
}
TEST_F(TracingTest, metricTracingTest)
{
i_env->startNewTrace();
auto span_id = i_env->getCurrentSpan();
i_env->finishSpan();
i_env->startNewSpan(Span::ContextType::FOLLOWS_FROM, span_id);
auto another_span_id = i_env->getCurrentSpan();
i_env->finishSpan();
i_env->startNewSpan(Span::ContextType::FOLLOWS_FROM, another_span_id);
i_env->finishSpan();
i_env->finishTrace();
routine();
EXPECT_THAT(debug_output.str(), HasSubstr("\"Metric\": \"tracing\""));
EXPECT_THAT(debug_output.str(), HasSubstr("\"currentTraceNumber\": 0"));
EXPECT_THAT(debug_output.str(), HasSubstr("\"maxSpanPerTrace\": 3"));
EXPECT_THAT(debug_output.str(), HasSubstr("\"avgSpanPerTrace\": 3.0"));
i_env->startNewTrace();
i_env->finishSpan();
i_env->finishTrace();
routine();
EXPECT_THAT(debug_output.str(), HasSubstr("\"Metric\": \"tracing\""));
EXPECT_THAT(debug_output.str(), HasSubstr("\"currentTraceNumber\": 0"));
EXPECT_THAT(debug_output.str(), HasSubstr("\"maxSpanPerTrace\": 3"));
EXPECT_THAT(debug_output.str(), HasSubstr("\"avgSpanPerTrace\": 2.0"));
}
class TracingCompRoutinesTest : public Test
{
public:
TracingCompRoutinesTest()
{
env.preload();
setConfiguration<bool>(true, "environment", "enable tracing");
env.init();
mainloop_comp.init();
mainloop = Singleton::Consume<I_MainLoop>::from(mainloop_comp);
i_env = Singleton::Consume<I_Environment>::from(env);
Debug::setNewDefaultStdout(&debug_output);
Debug::setUnitTestFlag(D_TRACE, Debug::DebugLevel::TRACE);
I_MainLoop::Routine another_routine = [&] () {
while (!stop) {
mainloop->yield(true);
}
i_env->startNewTrace(true, "a687b388-1108-4083-9852-07c33b107589");
auto another_trace_id = i_env->getCurrentTrace();
auto another_span_id = i_env->getCurrentSpan();
EXPECT_NE(trace_id, another_trace_id);
EXPECT_NE(span_id, another_span_id);
EXPECT_NE("", i_env->getCurrentSpan());
EXPECT_NE("", i_env->getCurrentTrace());
EXPECT_THAT(debug_output.str(), HasSubstr("New trace was created " + another_trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + another_span_id));
EXPECT_THAT(debug_output.str(), HasSubstr("trace id " + another_trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("context type New"));
i_env->finishSpan();
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + another_span_id));
EXPECT_EQ("", i_env->getCurrentSpan());
i_env->finishTrace();
EXPECT_THAT(debug_output.str(), HasSubstr("Current trace has ended " + another_trace_id));
EXPECT_EQ("", i_env->getCurrentTrace());
};
mainloop->addOneTimeRoutine(
I_MainLoop::RoutineType::RealTime,
another_routine,
"TracingCompRoutinesTest routine",
true
);
}
~TracingCompRoutinesTest()
{
Debug::setNewDefaultStdout(&cout);
mainloop_comp.fini();
}
bool stop = false;
stringstream debug_output;
ConfigComponent config;
NiceMock<MockAgentDetails> agent_details_mocker;
NiceMock<MockTimeGet> mock_time;
NiceMock<MockMessaging> mock_messaging;
MainloopComponent mainloop_comp;
::Environment env;
I_MainLoop *mainloop;
I_Environment *i_env;
string trace_id;
string span_id;
};
TEST_F(TracingCompRoutinesTest, 2SpansDifFlow)
{
ON_CALL(mock_messaging, mockSendPersistentMessage(_, _, _, _, _, _, _)).WillByDefault(Return(string()));
I_MainLoop::Routine routine = [&] () {
i_env->startNewTrace(true, "a687b388-1108-4083-9852-07c33b1074e9");
trace_id = i_env->getCurrentTrace();
span_id = i_env->getCurrentSpan();
string headers = i_env->getCurrentHeaders();
EXPECT_THAT(headers, HasSubstr("X-Trace-Id: " + trace_id));
EXPECT_THAT(headers, HasSubstr("X-Span-Id: " + span_id));
EXPECT_EQ(trace_id, "a687b388-1108-4083-9852-07c33b1074e9");
EXPECT_NE("", i_env->getCurrentSpan());
EXPECT_NE("", i_env->getCurrentTrace());
EXPECT_THAT(debug_output.str(), HasSubstr("New trace was created " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("New span was created " + span_id));
EXPECT_THAT(debug_output.str(), HasSubstr("trace id " + trace_id));
EXPECT_THAT(debug_output.str(), HasSubstr("context type New"));
stop = true;
mainloop->yield(true);
i_env->finishSpan();
EXPECT_THAT(debug_output.str(), HasSubstr("Current span has ended " + span_id));
EXPECT_EQ("", i_env->getCurrentSpan());
i_env->finishTrace();
EXPECT_THAT(debug_output.str(), HasSubstr("Current trace has ended " + trace_id));
EXPECT_EQ("", i_env->getCurrentTrace());
};
mainloop->addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, routine, "2SpansDifFlow test routine");
try {
mainloop->run();
} catch(...) {
}
}

View File

@@ -0,0 +1,19 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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.
#ifndef __EVALUATOR_REGISTRATION_H__
#define __EVALUATOR_REGISTRATION_H__
void registerBaseEvaluators();
#endif // __EVALUATOR_REGISTRATION_H__

View File

@@ -0,0 +1,23 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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 "context.h"
bool
EnvKeyAttr::ParamAttr::doesMatch(const EnvKeyAttr::ParamAttr &param) const
{
if (param.log_section != LogSection::NONE && param.log_section != log_section) return false;
if (param.verbosity_level != Verbosity::NONE && param.verbosity_level != verbosity_level) return false;
return true;
}

137
core/environment/parsing.cc Normal file
View File

@@ -0,0 +1,137 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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 "environment_evaluator.h"
#include <sstream>
#include <algorithm>
#include "enum_range.h"
using namespace std;
using namespace EnvironmentHelper;
USE_DEBUG_FLAG(D_ENVIRONMENT);
void
reportWrongNumberOfParams(const string &eval_name, uint no_params, uint min, uint max)
{
ostringstream os;
os <<
"Wrong number of parameters for '" <<
eval_name <<
"'. Got " <<
no_params <<
" parameters instead of expected ";
if (min == max) {
os << min;
} else if (max == static_cast<uint>(-1)) {
os << "more than " << min;
} else {
os << "between " << min << " and " << max;
}
dbgTrace(D_ENVIRONMENT) << os.str();
EvaluatorParseError err(os.str());
throw err;
}
void
reportWrongParamType(const string &eval_name, const string &param, const string &reason)
{
ostringstream os;
os << "Parameter '" << param << "' for '" << eval_name << "' is of the wrong type because: " << reason;
dbgTrace(D_ENVIRONMENT) << os.str();
EvaluatorParseError err(os.str());
throw err;
}
void
reportUnknownEvaluatorType(const string &eval_name)
{
ostringstream os;
os << "Evaluator '" << eval_name << "' doesn't exist for the required type";
dbgTrace(D_ENVIRONMENT) << os.str();
EvaluatorParseError err(os.str());
throw err;
}
static string
trim(const string &str)
{
auto first = str.find_first_not_of(' ');
if (first == string::npos) return "";
auto last = str.find_last_not_of(' ');
return str.substr(first, (last-first+1));
}
static vector<string>
breakToParams(const string &list)
{
vector<string> res;
uint brackets = 0;
uint start = 0;
for (uint iter : makeRange(list.size())) {
switch (list[iter]) {
case ',': {
if (brackets == 0) {
res.push_back(trim(list.substr(start, iter-start)));
start = iter + 1;
}
break;
}
case '(': {
brackets++;
break;
}
case ')': {
brackets--;
break;
}
default: {
break;
}
}
}
// Add the last section
if (start < list.size()) res.push_back(trim(list.substr(start, list.size()-start)));
dbgTrace(D_ENVIRONMENT) << "Param vector size: " << res.size();
return res;
}
pair<string, vector<string>>
EnvironmentHelper::breakEvaluatorString(const string &str)
{
auto trimmed = trim(str);
auto open_bracket = trimmed.find('(');
if (open_bracket == string::npos) {
dbgTrace(D_ENVIRONMENT) << "Could not find the opening bracket in the string";
throw EvaluatorParseError("Could not find the opening bracket in the string");
}
auto close_bracket = trimmed.size() - 1;
if (trimmed[close_bracket] != ')') {
dbgTrace(D_ENVIRONMENT) << "Could not find the closing bracket in the string";
throw EvaluatorParseError("Could not find the closing bracket in the string");
}
auto command = trimmed.substr(0, open_bracket);
auto params = trimmed.substr(open_bracket + 1, close_bracket - open_bracket - 1);
dbgTrace(D_ENVIRONMENT) << "Breaking evaluator string passed successfully";
return make_pair(trim(command), breakToParams(trim(params)));
}

131
core/environment/span.cc Executable file
View File

@@ -0,0 +1,131 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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 "environment/span.h"
#include "boost/uuid/uuid.hpp"
#include "boost/uuid/uuid_generators.hpp"
#include "boost/uuid/uuid_io.hpp"
#include "debug.h"
using namespace std;
using namespace boost::uuids;
USE_DEBUG_FLAG(D_TRACE);
Span::Span(string _trace_id, ContextType _type, string _prev_span)
:
trace_id(_trace_id),
context_type(_type),
prev_span_id(_prev_span)
{
if (trace_id.empty()) {
dbgError(D_TRACE) << "Provided trace id is empty. Span cannot be created";
return;
}
if (context_type != ContextType::NEW && prev_span_id.empty()) {
dbgError(D_TRACE) << "The provided previous span ID is empty. Cannot create span.";
return;
}
boost::uuids::random_generator uuid_random_gen;
span_id = to_string(uuid_random_gen());
context.registerValue<string>("span id", span_id);
context.activate();
dbgTrace(D_TRACE) << "New span was created " << span_id
<< ", trace id " << trace_id
<< ", context type " << convertSpanContextTypeToString(context_type)
<< (context_type == ContextType::NEW ? string() : ", previous span id " + prev_span_id);
}
Span::~Span()
{
dbgTrace(D_TRACE) << "Current span has ended " << span_id;
context.unregisterKey<string>("span id");
context.deactivate();
}
string
Span::getTraceId() const
{
return trace_id;
}
string
Span::getSpanId() const
{
return span_id;
}
Span::ContextType
Span::getSpanContextType() const
{
return context_type;
}
string
Span::getPrevSpanId() const
{
return prev_span_id;
}
string
Span::convertSpanContextTypeToString(ContextType type)
{
switch(type) {
case ContextType::NEW: {
return "New";
}
case ContextType::CHILD_OF: {
return "Child of";
}
case ContextType::FOLLOWS_FROM: {
return "Follows from";
}
}
dbgAssert(false) << "Span context not supported";
return string();
}
SpanWrapper::SpanWrapper(string _trace_id, Span::ContextType _type, string _prev_span)
:
span(make_shared<Span>(_trace_id, _type, _prev_span))
{}
string
SpanWrapper::getTraceId() const
{
return span->getTraceId();
}
string
SpanWrapper::getSpanId() const
{
return span->getSpanId();
}
Span::ContextType
SpanWrapper::getSpanContextType() const
{
return span->getSpanContextType();
}
string
SpanWrapper::getPrevSpanId() const
{
return span->getPrevSpanId();
}

58
core/environment/trace.cc Executable file
View File

@@ -0,0 +1,58 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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 "environment/trace.h"
#include "boost/uuid/uuid.hpp"
#include "boost/uuid/uuid_generators.hpp"
#include "boost/uuid/uuid_io.hpp"
#include "debug.h"
using namespace std;
using namespace boost::uuids;
USE_DEBUG_FLAG(D_TRACE);
Trace::Trace(string _id)
:
trace_id(_id)
{
if (trace_id.empty()) {
boost::uuids::random_generator uuid_random_gen;
trace_id = to_string(uuid_random_gen());
}
context.registerValue<string>("trace id", trace_id);
context.activate();
dbgTrace(D_TRACE) << "New trace was created " << trace_id;
}
Trace::~Trace()
{
dbgTrace(D_TRACE) << "Current trace has ended " << trace_id;
context.unregisterKey<string>("trace id");
context.deactivate();
}
string
Trace::getTraceId() const
{
return trace_id;
}
TraceWrapper::TraceWrapper(string _id) : trace(make_shared<Trace>(_id)) {}
string
TraceWrapper::getTraceId() const
{
return trace->getTraceId();
}