From 8bcae97ecce97fb30b677a8c0bf23136f0254ebe Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Wed, 30 Aug 2023 16:34:36 +0200 Subject: [PATCH 1/6] Introduce Dictionary#GetRef() --- lib/base/dictionary.cpp | 14 ++++++++++++++ lib/base/dictionary.hpp | 1 + 2 files changed, 15 insertions(+) diff --git a/lib/base/dictionary.cpp b/lib/base/dictionary.cpp index aca7d519c7b..43df4af8f0b 100644 --- a/lib/base/dictionary.cpp +++ b/lib/base/dictionary.cpp @@ -67,6 +67,20 @@ bool Dictionary::Get(const String& key, Value *result) const return true; } +/** + * Retrieves a value's address from a dictionary. + * + * @param key The key whose value's address should be retrieved. + * @returns nullptr if the key was not found. + */ +const Value * Dictionary::GetRef(const String& key) const +{ + std::shared_lock lock (m_DataMutex); + auto it (m_Data.find(key)); + + return it == m_Data.end() ? nullptr : &it->second; +} + /** * Sets a value in the dictionary. * diff --git a/lib/base/dictionary.hpp b/lib/base/dictionary.hpp index 352c29ef95c..ffccd630f3c 100644 --- a/lib/base/dictionary.hpp +++ b/lib/base/dictionary.hpp @@ -42,6 +42,7 @@ class Dictionary final : public Object Value Get(const String& key) const; bool Get(const String& key, Value *result) const; + const Value * GetRef(const String& key) const; void Set(const String& key, Value value, bool overrideFrozen = false); bool Contains(const String& key) const; From a04cef189046c1fa7b32e3151a381840ac16b55d Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 31 Aug 2023 12:46:28 +0200 Subject: [PATCH 2/6] Introduce DictExpression#GetExpressions() --- lib/config/expression.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index 7be667a2b99..644548d286e 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -622,6 +622,11 @@ class DictExpression final : public DebuggableExpression void MakeInline(); + inline const std::vector>& GetExpressions() const noexcept + { + return m_Expressions; + } + protected: ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; From 15191bcd7486f8cd2cd87b42bdacebb1e24754e3 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 21 Nov 2023 14:36:32 +0100 Subject: [PATCH 3/6] ApplyRule::GetTarget*s(): support constant strings from variables in addition to literal strings. This is for sandboxed filters with some variables pre-set by the caller. They're "constant" in that scope, too. --- lib/config/applyrule-targeted.cpp | 66 ++++++++++++++++++------------- lib/config/applyrule.hpp | 13 +++--- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/lib/config/applyrule-targeted.cpp b/lib/config/applyrule-targeted.cpp index 210c6776436..c5bfe2086de 100644 --- a/lib/config/applyrule-targeted.cpp +++ b/lib/config/applyrule-targeted.cpp @@ -96,16 +96,16 @@ bool ApplyRule::AddTargetedRule(const ApplyRule::Ptr& rule, const String& target * * @returns Whether the given assign filter is like above. */ -bool ApplyRule::GetTargetHosts(Expression* assignFilter, std::vector& hosts) +bool ApplyRule::GetTargetHosts(Expression* assignFilter, std::vector& hosts, const Dictionary::Ptr& constants) { auto lor (dynamic_cast(assignFilter)); if (lor) { - return GetTargetHosts(lor->GetOperand1().get(), hosts) - && GetTargetHosts(lor->GetOperand2().get(), hosts); + return GetTargetHosts(lor->GetOperand1().get(), hosts, constants) + && GetTargetHosts(lor->GetOperand2().get(), hosts, constants); } - auto name (GetComparedName(assignFilter, "host")); + auto name (GetComparedName(assignFilter, "host", constants)); if (name) { hosts.emplace_back(name); @@ -124,16 +124,16 @@ bool ApplyRule::GetTargetHosts(Expression* assignFilter, std::vector>& services) +bool ApplyRule::GetTargetServices(Expression* assignFilter, std::vector>& services, const Dictionary::Ptr& constants) { auto lor (dynamic_cast(assignFilter)); if (lor) { - return GetTargetServices(lor->GetOperand1().get(), services) - && GetTargetServices(lor->GetOperand2().get(), services); + return GetTargetServices(lor->GetOperand1().get(), services, constants) + && GetTargetServices(lor->GetOperand2().get(), services, constants); } - auto service (GetTargetService(assignFilter)); + auto service (GetTargetService(assignFilter, constants)); if (service.first) { services.emplace_back(service); @@ -152,7 +152,7 @@ bool ApplyRule::GetTargetServices(Expression* assignFilter, std::vector ApplyRule::GetTargetService(Expression* assignFilter) +std::pair ApplyRule::GetTargetService(Expression* assignFilter, const Dictionary::Ptr& constants) { auto land (dynamic_cast(assignFilter)); @@ -162,15 +162,15 @@ std::pair ApplyRule::GetTargetService(Expression auto op1 (land->GetOperand1().get()); auto op2 (land->GetOperand2().get()); - auto host (GetComparedName(op1, "host")); + auto host (GetComparedName(op1, "host", constants)); if (!host) { std::swap(op1, op2); - host = GetComparedName(op1, "host"); + host = GetComparedName(op1, "host", constants); } if (host) { - auto service (GetComparedName(op2, "service")); + auto service (GetComparedName(op2, "service", constants)); if (service) { return {host, service}; @@ -189,7 +189,7 @@ std::pair ApplyRule::GetTargetService(Expression * * @returns The object name on success and nullptr on failure. */ -const String * ApplyRule::GetComparedName(Expression* assignFilter, const char * lcType) +const String * ApplyRule::GetComparedName(Expression* assignFilter, const char * lcType, const Dictionary::Ptr& constants) { auto eq (dynamic_cast(assignFilter)); @@ -200,12 +200,12 @@ const String * ApplyRule::GetComparedName(Expression* assignFilter, const char * auto op1 (eq->GetOperand1().get()); auto op2 (eq->GetOperand2().get()); - if (IsNameIndexer(op1, lcType)) { - return GetLiteralStringValue(op2); + if (IsNameIndexer(op1, lcType, constants)) { + return GetConstString(op2, constants); } - if (IsNameIndexer(op2, lcType)) { - return GetLiteralStringValue(op1); + if (IsNameIndexer(op2, lcType, constants)) { + return GetConstString(op1, constants); } return nullptr; @@ -214,7 +214,7 @@ const String * ApplyRule::GetComparedName(Expression* assignFilter, const char * /** * @returns Whether the given expression is like $lcType$.name. */ -bool ApplyRule::IsNameIndexer(Expression* exp, const char * lcType) +bool ApplyRule::IsNameIndexer(Expression* exp, const char * lcType, const Dictionary::Ptr& constants) { auto ixr (dynamic_cast(exp)); @@ -228,27 +228,39 @@ bool ApplyRule::IsNameIndexer(Expression* exp, const char * lcType) return false; } - auto val (GetLiteralStringValue(ixr->GetOperand2().get())); + auto val (GetConstString(ixr->GetOperand2().get(), constants)); return val && *val == "name"; } /** - * @returns If the given expression is a string literal, the string. nullptr on failure. + * @returns If the given expression is a constant string, its address. nullptr on failure. */ -const String * ApplyRule::GetLiteralStringValue(Expression* exp) +const String * ApplyRule::GetConstString(Expression* exp, const Dictionary::Ptr& constants) +{ + auto cnst (GetConst(exp, constants)); + + return cnst && cnst->IsString() ? &cnst->Get() : nullptr; +} + +/** + * @returns If the given expression is a constant, its address. nullptr on failure. + */ +const Value * ApplyRule::GetConst(Expression* exp, const Dictionary::Ptr& constants) { auto lit (dynamic_cast(exp)); - if (!lit) { - return nullptr; + if (lit) { + return &lit->GetValue(); } - auto& val (lit->GetValue()); + if (constants) { + auto var (dynamic_cast(exp)); - if (!val.IsString()) { - return nullptr; + if (var) { + return constants->GetRef(var->GetVariable()); + } } - return &val.Get(); + return nullptr; } diff --git a/lib/config/applyrule.hpp b/lib/config/applyrule.hpp index c5f1709dd44..40251a4a8ec 100644 --- a/lib/config/applyrule.hpp +++ b/lib/config/applyrule.hpp @@ -108,12 +108,13 @@ class ApplyRule : public SharedObject static RuleMap m_Rules; static bool AddTargetedRule(const ApplyRule::Ptr& rule, const String& targetType, PerSourceType& rules); - static bool GetTargetHosts(Expression* assignFilter, std::vector& hosts); - static bool GetTargetServices(Expression* assignFilter, std::vector>& services); - static std::pair GetTargetService(Expression* assignFilter); - static const String * GetComparedName(Expression* assignFilter, const char * lcType); - static bool IsNameIndexer(Expression* exp, const char * lcType); - static const String * GetLiteralStringValue(Expression* exp); + static bool GetTargetHosts(Expression* assignFilter, std::vector& hosts, const Dictionary::Ptr& constants = nullptr); + static bool GetTargetServices(Expression* assignFilter, std::vector>& services, const Dictionary::Ptr& constants = nullptr); + static std::pair GetTargetService(Expression* assignFilter, const Dictionary::Ptr& constants); + static const String * GetComparedName(Expression* assignFilter, const char * lcType, const Dictionary::Ptr& constants); + static bool IsNameIndexer(Expression* exp, const char * lcType, const Dictionary::Ptr& constants); + static const String * GetConstString(Expression* exp, const Dictionary::Ptr& constants); + static const Value * GetConst(Expression* exp, const Dictionary::Ptr& constants); ApplyRule(String name, Expression::Ptr expression, Expression::Ptr filter, String package, String fkvar, String fvvar, Expression::Ptr fterm, From ecfc9033b0eb25c2f6dc59dab3474865ca74f7c6 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 21 Nov 2023 14:49:35 +0100 Subject: [PATCH 4/6] FilterUtility::GetFilterTargets(): don't run filter for specific object(s) for all objects --- lib/config/applyrule.hpp | 4 +- lib/remote/filterutility.cpp | 72 ++++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/lib/config/applyrule.hpp b/lib/config/applyrule.hpp index 40251a4a8ec..cf9b6e5e67e 100644 --- a/lib/config/applyrule.hpp +++ b/lib/config/applyrule.hpp @@ -82,6 +82,8 @@ class ApplyRule : public SharedObject static const std::vector& GetRules(const Type::Ptr& sourceType, const Type::Ptr& targetType); static const std::set& GetTargetedHostRules(const Type::Ptr& sourceType, const String& host); static const std::set& GetTargetedServiceRules(const Type::Ptr& sourceType, const String& host, const String& service); + static bool GetTargetHosts(Expression* assignFilter, std::vector& hosts, const Dictionary::Ptr& constants = nullptr); + static bool GetTargetServices(Expression* assignFilter, std::vector>& services, const Dictionary::Ptr& constants = nullptr); static void RegisterType(const String& sourceType, const std::vector& targetTypes); static bool IsValidSourceType(const String& sourceType); @@ -108,8 +110,6 @@ class ApplyRule : public SharedObject static RuleMap m_Rules; static bool AddTargetedRule(const ApplyRule::Ptr& rule, const String& targetType, PerSourceType& rules); - static bool GetTargetHosts(Expression* assignFilter, std::vector& hosts, const Dictionary::Ptr& constants = nullptr); - static bool GetTargetServices(Expression* assignFilter, std::vector>& services, const Dictionary::Ptr& constants = nullptr); static std::pair GetTargetService(Expression* assignFilter, const Dictionary::Ptr& constants); static const String * GetComparedName(Expression* assignFilter, const char * lcType, const Dictionary::Ptr& constants); static bool IsNameIndexer(Expression* exp, const char * lcType, const Dictionary::Ptr& constants); diff --git a/lib/remote/filterutility.cpp b/lib/remote/filterutility.cpp index a38ad5b9b10..d5dc2b6ba14 100644 --- a/lib/remote/filterutility.cpp +++ b/lib/remote/filterutility.cpp @@ -2,6 +2,7 @@ #include "remote/filterutility.hpp" #include "remote/httputility.hpp" +#include "config/applyrule.hpp" #include "config/configcompiler.hpp" #include "config/expression.hpp" #include "base/namespace.hpp" @@ -271,18 +272,73 @@ std::vector FilterUtility::GetFilterTargets(const QueryDescription& qd, c if (query->Contains("filter")) { String filter = HttpUtility::GetLastParameter(query, "filter"); std::unique_ptr ufilter = ConfigCompiler::CompileText("", filter); - Dictionary::Ptr filter_vars = query->Get("filter_vars"); - if (filter_vars) { - ObjectLock olock(filter_vars); - for (const Dictionary::Pair& kv : filter_vars) { - frameNS->Set(kv.first, kv.second); + bool targeted = false; + std::vector targets; + + if (dynamic_cast(provider.get())) { + auto dict (dynamic_cast(ufilter.get())); + + if (dict) { + auto& subex (dict->GetExpressions()); + + if (subex.size() == 1u) { + if (type == "Host") { + std::vector targetNames; + + if (ApplyRule::GetTargetHosts(subex.at(0).get(), targetNames, filter_vars)) { + static const auto typeHost (Type::GetByName("Host")); + static const auto ctypeHost (dynamic_cast(typeHost.get())); + targeted = true; + + for (auto name : targetNames) { + auto target (ctypeHost->GetObject(*name)); + + if (target) { + targets.emplace_back(target); + } + } + } + } else if (type == "Service") { + std::vector> targetNames; + + if (ApplyRule::GetTargetServices(subex.at(0).get(), targetNames, filter_vars)) { + static const auto typeService (Type::GetByName("Service")); + static const auto ctypeService (dynamic_cast(typeService.get())); + targeted = true; + + for (auto name : targetNames) { + auto target (ctypeService->GetObject(*name.first + "!" + *name.second)); + + if (target) { + targets.emplace_back(target); + } + } + } + } + } } } - provider->FindTargets(type, [&permissionFrame, &permissionFilter, &frame, &ufilter, &result, variableName](const Object::Ptr& target) { - FilteredAddTarget(permissionFrame, permissionFilter.get(), frame, &*ufilter, result, variableName, target); - }); + if (targeted) { + for (auto& target : targets) { + if (FilterUtility::EvaluateFilter(permissionFrame, permissionFilter.get(), target, variableName)) { + result.emplace_back(std::move(target)); + } + } + } else { + if (filter_vars) { + ObjectLock olock (filter_vars); + + for (auto& kv : filter_vars) { + frameNS->Set(kv.first, kv.second); + } + } + + provider->FindTargets(type, [&permissionFrame, &permissionFilter, &frame, &ufilter, &result, variableName](const Object::Ptr& target) { + FilteredAddTarget(permissionFrame, permissionFilter.get(), frame, &*ufilter, result, variableName, target); + }); + } } else { /* Ensure to pass a nullptr as filter expression. * GCC 8.1.1 on F28 causes problems, see GH #6533. From 191bf93f2efc0adba7ba18302bf5d6a49532d3b2 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Wed, 13 Dec 2023 16:25:33 +0100 Subject: [PATCH 5/6] Test ApplyRule::GetTarget*s() --- test/CMakeLists.txt | 33 ++++++ test/config-apply.cpp | 242 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 test/config-apply.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8919de304dc..484272b3966 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -24,6 +24,7 @@ set(base_test_SOURCES base-type.cpp base-utility.cpp base-value.cpp + config-apply.cpp config-ops.cpp icinga-checkresult.cpp icinga-dependencies.cpp @@ -123,6 +124,38 @@ add_boost_test(base base_value/scalar base_value/convert base_value/format + config_apply/gettargethosts_literal + config_apply/gettargethosts_const + config_apply/gettargethosts_swapped + config_apply/gettargethosts_two + config_apply/gettargethosts_three + config_apply/gettargethosts_mixed + config_apply/gettargethosts_redundant + config_apply/gettargethosts_badconst + config_apply/gettargethosts_notliteral + config_apply/gettargethosts_wrongop + config_apply/gettargethosts_wrongattr + config_apply/gettargethosts_wrongvar + config_apply/gettargethosts_noindexer + config_apply/gettargetservices_literal + config_apply/gettargetservices_const + config_apply/gettargetservices_swapped_outer + config_apply/gettargetservices_swapped_inner + config_apply/gettargetservices_two + config_apply/gettargetservices_three + config_apply/gettargetservices_mixed + config_apply/gettargetservices_redundant + config_apply/gettargetservices_badconst + config_apply/gettargetservices_notliteral + config_apply/gettargetservices_wrongop_outer + config_apply/gettargetservices_wrongop_host + config_apply/gettargetservices_wrongop_service + config_apply/gettargetservices_wrongattr_host + config_apply/gettargetservices_wrongattr_service + config_apply/gettargetservices_wrongvar_host + config_apply/gettargetservices_wrongvar_service + config_apply/gettargetservices_noindexer_host + config_apply/gettargetservices_noindexer_service config_ops/simple config_ops/advanced icinga_checkresult/host_1attempt diff --git a/test/config-apply.cpp b/test/config-apply.cpp new file mode 100644 index 00000000000..30ec80a5769 --- /dev/null +++ b/test/config-apply.cpp @@ -0,0 +1,242 @@ +/* Icinga 2 | (c) 2023 Icinga GmbH | GPLv2+ */ + +#include "config/applyrule.hpp" +#include "config/configcompiler.hpp" +#include + +using namespace icinga; + +static Expression* RequireActualExpression(const std::unique_ptr& compiledExpression) +{ + BOOST_REQUIRE_NE(compiledExpression.get(), nullptr); + + auto dict (dynamic_cast(compiledExpression.get())); + BOOST_REQUIRE_NE(dict, nullptr); + + auto& subex (dict->GetExpressions()); + BOOST_REQUIRE_EQUAL(subex.size(), 1u); + + auto sub0 (subex.at(0).get()); + BOOST_REQUIRE_NE(sub0, nullptr); + + return sub0; +} + +static void GetTargetHostsHelper( + const String& filter, const Dictionary::Ptr& constants, bool targeted, const std::vector& hosts = {} +) +{ + auto compiled (ConfigCompiler::CompileText("", filter)); + auto expr (RequireActualExpression(compiled)); + std::vector actualHosts; + + BOOST_CHECK_EQUAL(ApplyRule::GetTargetHosts(expr, actualHosts, constants), targeted); + + if (targeted) { + std::vector actualHostNames; + + actualHostNames.reserve(actualHosts.size()); + + for (auto h : actualHosts) { + actualHostNames.emplace_back(*h); + } + + BOOST_CHECK_EQUAL_COLLECTIONS(actualHostNames.begin(), actualHostNames.end(), hosts.begin(), hosts.end()); + } +} + +static void GetTargetServicesHelper( + const String& filter, const Dictionary::Ptr& constants, bool targeted, const std::vector>& services = {} +) +{ + auto compiled (ConfigCompiler::CompileText("", filter)); + auto expr (RequireActualExpression(compiled)); + std::vector> actualServices; + + BOOST_CHECK_EQUAL(ApplyRule::GetTargetServices(expr, actualServices, constants), targeted); + + if (targeted) { + std::vector> actualServiceNames; + + actualServiceNames.reserve(actualServices.size()); + + for (auto s : actualServices) { + actualServiceNames.emplace_back(*s.first, *s.second); + } + + BOOST_CHECK(actualServiceNames == services); + } +} + +BOOST_AUTO_TEST_SUITE(config_apply) + +BOOST_AUTO_TEST_CASE(gettargethosts_literal) +{ + GetTargetHostsHelper("host.name == \"foo\"", nullptr, true, {"foo"}); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_const) +{ + GetTargetHostsHelper("host.name == x", new Dictionary({{"x", "foo"}}), true, {"foo"}); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_swapped) +{ + GetTargetHostsHelper("\"foo\" == host.name", nullptr, true, {"foo"}); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_two) +{ + GetTargetHostsHelper("host.name == \"foo\" || host.name == \"bar\"", nullptr, true, {"foo", "bar"}); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_three) +{ + GetTargetHostsHelper( + "host.name == \"foo\" || host.name == \"bar\" || host.name == \"foobar\"", + nullptr, true, {"foo", "bar", "foobar"} + ); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_mixed) +{ + GetTargetHostsHelper("host.name == x || \"bar\" == host.name", new Dictionary({{"x", "foo"}}), true, {"foo", "bar"}); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_redundant) +{ + GetTargetHostsHelper("host.name == \"foo\" && 1", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_badconst) +{ + GetTargetHostsHelper("host.name == NodeName", new Dictionary({{"x", "foo"}}), false); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_notliteral) +{ + GetTargetHostsHelper("host.name == \"foo\" + \"bar\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_wrongop) +{ + GetTargetHostsHelper("host.name != \"foo\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_wrongattr) +{ + GetTargetHostsHelper("host.__name == \"foo\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_wrongvar) +{ + GetTargetHostsHelper("service.name == \"foo\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargethosts_noindexer) +{ + GetTargetHostsHelper("name == \"foo\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_literal) +{ + GetTargetServicesHelper("host.name == \"foo\" && service.name == \"bar\"", nullptr, true, {{"foo", "bar"}}); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_const) +{ + GetTargetServicesHelper("host.name == x && service.name == y", new Dictionary({{"x", "foo"}, {"y", "bar"}}), true, {{"foo", "bar"}}); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_swapped_outer) +{ + GetTargetServicesHelper("service.name == \"bar\" && host.name == \"foo\"", nullptr, true, {{"foo", "bar"}}); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_swapped_inner) +{ + GetTargetServicesHelper("\"foo\" == host.name && \"bar\" == service.name", nullptr, true, {{"foo", "bar"}}); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_two) +{ + GetTargetServicesHelper( + "host.name == \"foo\" && service.name == \"bar\" || host.name == \"oof\" && service.name == \"rab\"", + nullptr, true, {{"foo", "bar"}, {"oof", "rab"}} + ); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_three) +{ + GetTargetServicesHelper( + "host.name == \"foo\" && service.name == \"bar\" || host.name == \"oof\" && service.name == \"rab\" || host.name == \"ofo\" && service.name == \"rba\"", + nullptr, true, {{"foo", "bar"}, {"oof", "rab"}, {"ofo", "rba"}} + ); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_mixed) +{ + GetTargetServicesHelper("\"bar\" == service.name && x == host.name", new Dictionary({{"x", "foo"}}), true, {{"foo", "bar"}}); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_redundant) +{ + GetTargetServicesHelper("host.name == \"foo\" && service.name == \"bar\" && 1", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_badconst) +{ + GetTargetServicesHelper("host.name == NodeName && service.name == \"bar\"", new Dictionary({{"x", "foo"}}), false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_notliteral) +{ + GetTargetServicesHelper("host.name == \"foo\" && service.name == \"b\" + \"ar\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_wrongop_outer) +{ + GetTargetServicesHelper("host.name == \"foo\" & service.name == \"bar\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_wrongop_host) +{ + GetTargetServicesHelper("host.name != \"foo\" && service.name == \"bar\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_wrongop_service) +{ + GetTargetServicesHelper("host.name == \"foo\" && service.name != \"bar\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_wrongattr_host) +{ + GetTargetServicesHelper("host.__name == \"foo\" && service.name == \"bar\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_wrongattr_service) +{ + GetTargetServicesHelper("host.name == \"foo\" && service.__name == \"bar\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_wrongvar_host) +{ + GetTargetServicesHelper("horst.name == \"foo\" && service.name == \"bar\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_wrongvar_service) +{ + GetTargetServicesHelper("host.name == \"foo\" && sehrvice.name == \"bar\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_noindexer_host) +{ + GetTargetServicesHelper("name == \"foo\" && service.name == \"bar\"", nullptr, false); +} + +BOOST_AUTO_TEST_CASE(gettargetservices_noindexer_service) +{ + GetTargetServicesHelper("host.name == \"foo\" && name == \"bar\"", nullptr, false); +} + +BOOST_AUTO_TEST_SUITE_END() From 4424d57e7a00b6bc89854a1ad905479336a25361 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 18 Dec 2023 16:01:31 +0100 Subject: [PATCH 6/6] Tests: config_apply/gettargetservices_*: use BOOST_CHECK_EQUAL_COLLECTIONS() to show the value diff in case of mismatch. Co-authored-by: Yonas Habteab --- test/config-apply.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/config-apply.cpp b/test/config-apply.cpp index 30ec80a5769..c207ddd3baa 100644 --- a/test/config-apply.cpp +++ b/test/config-apply.cpp @@ -22,6 +22,15 @@ static Expression* RequireActualExpression(const std::unique_ptr& co return sub0; } +template<> +struct boost::test_tools::tt_detail::print_log_value> +{ + inline void operator()(std::ostream& os, const std::pair& hs) + { + os << hs.first << "!" << hs.second; + } +}; + static void GetTargetHostsHelper( const String& filter, const Dictionary::Ptr& constants, bool targeted, const std::vector& hosts = {} ) @@ -64,7 +73,7 @@ static void GetTargetServicesHelper( actualServiceNames.emplace_back(*s.first, *s.second); } - BOOST_CHECK(actualServiceNames == services); + BOOST_CHECK_EQUAL_COLLECTIONS(actualServiceNames.begin(), actualServiceNames.end(), services.begin(), services.end()); } }