From 7c2b82f087122b519a20de4d1a005fda5dcf2583 Mon Sep 17 00:00:00 2001 From: Marcin Olko Date: Thu, 12 Mar 2026 16:00:44 +0000 Subject: [PATCH 1/5] Improved openfeature smoke tests to use newest sdk api Signed-off-by: Marcin Olko --- providers/flagd/src/provider.cpp | 8 +- providers/flagd/src/provider.h | 3 + providers/flagd/tests/smoke/BUILD | 1 + providers/flagd/tests/smoke/openfeature.cpp | 208 +++++++++++++++++--- 4 files changed, 187 insertions(+), 33 deletions(-) diff --git a/providers/flagd/src/provider.cpp b/providers/flagd/src/provider.cpp index 96958c7..223f97b 100644 --- a/providers/flagd/src/provider.cpp +++ b/providers/flagd/src/provider.cpp @@ -2,7 +2,6 @@ #include -#include #include #include "absl/log/log.h" @@ -28,6 +27,13 @@ FlagdProvider::FlagdProvider(FlagdProviderConfig config) evaluator_ = std::make_unique(sync_); } +FlagdProvider::FlagdProvider(std::shared_ptr sync, + FlagdProviderConfig config) + : configuration_(std::move(config)), + sync_(std::move(sync)), + evaluator_(std::make_unique(sync_)), + is_ready_(false) {} + FlagdProvider::~FlagdProvider() { if (is_ready_) { absl::Status status = FlagdProvider::Shutdown(); diff --git a/providers/flagd/src/provider.h b/providers/flagd/src/provider.h index 983777c..1af8dfc 100644 --- a/providers/flagd/src/provider.h +++ b/providers/flagd/src/provider.h @@ -17,6 +17,9 @@ class FlagdProvider : public openfeature::FeatureProvider { public: explicit FlagdProvider(FlagdProviderConfig config = FlagdProviderConfig()); + explicit FlagdProvider(std::shared_ptr sync, + FlagdProviderConfig config = FlagdProviderConfig()); + ~FlagdProvider() override; openfeature::Metadata GetMetadata() const override; diff --git a/providers/flagd/tests/smoke/BUILD b/providers/flagd/tests/smoke/BUILD index 3bda82b..302612c 100644 --- a/providers/flagd/tests/smoke/BUILD +++ b/providers/flagd/tests/smoke/BUILD @@ -8,6 +8,7 @@ cc_test( "//providers/flagd/src:flagd_provider", "@googletest//:gtest_main", "@openfeature_cpp_sdk//openfeature", + "@openfeature_cpp_sdk//openfeature:openfeature_api", ], ) diff --git a/providers/flagd/tests/smoke/openfeature.cpp b/providers/flagd/tests/smoke/openfeature.cpp index 8abf8fc..b84fa4b 100644 --- a/providers/flagd/tests/smoke/openfeature.cpp +++ b/providers/flagd/tests/smoke/openfeature.cpp @@ -1,36 +1,180 @@ +#include + #include -#include +#include -#include "flagd/configuration.h" #include "flagd/provider.h" -#include "gtest/gtest.h" -#include "openfeature/provider.h" - -TEST(FlagdProviderTest, ProviderCreation) { - flagd::FlagdProviderConfig config = - flagd::FlagdProviderConfig().SetHost("localhost"); - - std::shared_ptr provider = - std::make_shared(config); - - openfeature::EvaluationContext ctx = - openfeature::EvaluationContext::Builder().build(); - - std::unique_ptr details = - provider->GetBooleanEvaluation("test_flag", false, ctx); - - // We didn't call Init, so the provider is not ready. - auto expected_details = openfeature::BoolResolutionDetails{ - false, - openfeature::Reason::kError, - "", - {}, - openfeature::ErrorCode::kProviderNotReady, - "Provider not ready"}; - - EXPECT_EQ(details->GetValue(), expected_details.GetValue()); - EXPECT_EQ(details->GetReason(), expected_details.GetReason()); - EXPECT_EQ(details->GetVariant(), expected_details.GetVariant()); - EXPECT_EQ(details->GetErrorCode(), expected_details.GetErrorCode()); - EXPECT_EQ(details->GetErrorMessage(), expected_details.GetErrorMessage()); +#include "flagd/sync.h" +#include "openfeature/openfeature_api.h" + +namespace { + +class MockSync : public flagd::FlagSync { + public: + absl::Status Init(const openfeature::EvaluationContext& /*ctx*/) override { + return absl::OkStatus(); + } + absl::Status Shutdown() override { return absl::OkStatus(); } + + void SetFlags(const nlohmann::json& flags) { this->UpdateFlags(flags); } +}; + +class FlagdOpenFeatureTest : public ::testing::Test { + protected: + void SetUp() override { + sync_ = std::make_shared(); + provider_ = std::make_shared(sync_); + auto& api = openfeature::OpenFeatureAPI::GetInstance(); + api.SetProviderAndWait(provider_); + client_ = api.GetClient(); + } + + void TearDown() override { + auto& api = openfeature::OpenFeatureAPI::GetInstance(); + api.Shutdown(); + } + + std::shared_ptr sync_; + std::shared_ptr provider_; + std::shared_ptr client_; +}; + +TEST_F(FlagdOpenFeatureTest, BooleanEvaluation) { + auto flags = nlohmann::json::parse(R"({ + "flags": { + "bool-flag": { + "state": "ENABLED", + "variants": { + "on": true, + "off": false + }, + "defaultVariant": "on" + } + } + })"); + sync_->SetFlags(flags); + + EXPECT_TRUE(client_->GetBooleanValue("bool-flag", false)); + EXPECT_FALSE(client_->GetBooleanValue("non-existent", false)); } + +TEST_F(FlagdOpenFeatureTest, StringEvaluation) { + auto flags = nlohmann::json::parse(R"({ + "flags": { + "string-flag": { + "state": "ENABLED", + "variants": { + "v1": "value1", + "v2": "value2" + }, + "defaultVariant": "v2" + } + } + })"); + sync_->SetFlags(flags); + + EXPECT_EQ(client_->GetStringValue("string-flag", "default"), "value2"); +} + +TEST_F(FlagdOpenFeatureTest, IntegerEvaluation) { + auto flags = nlohmann::json::parse(R"({ + "flags": { + "int-flag": { + "state": "ENABLED", + "variants": { + "one": 1, + "two": 2 + }, + "defaultVariant": "one" + } + } + })"); + sync_->SetFlags(flags); + + EXPECT_EQ(client_->GetIntegerValue("int-flag", 0), 1); +} + +TEST_F(FlagdOpenFeatureTest, DoubleEvaluation) { + auto flags = nlohmann::json::parse(R"({ + "flags": { + "double-flag": { + "state": "ENABLED", + "variants": { + "d1": 1.1, + "d2": 2.2 + }, + "defaultVariant": "d2" + } + } + })"); + sync_->SetFlags(flags); + + EXPECT_DOUBLE_EQ(client_->GetDoubleValue("double-flag", 0.0), 2.2); +} + +TEST_F(FlagdOpenFeatureTest, ObjectEvaluation) { + auto flags = nlohmann::json::parse(R"({ + "flags": { + "obj-flag": { + "state": "ENABLED", + "variants": { + "v1": { + "key": "value" + } + }, + "defaultVariant": "v1" + } + } + })"); + sync_->SetFlags(flags); + + openfeature::Value val = + client_->GetObjectValue("obj-flag", openfeature::Value()); + EXPECT_TRUE(val.IsStructure()); + const auto* structure = val.AsStructure(); + EXPECT_EQ(structure->at("key").AsString().value(), "value"); +} + +TEST_F(FlagdOpenFeatureTest, EvaluationContextTargeting) { + // Example of targeting using EvaluationContext + auto flags = nlohmann::json::parse(R"({ + "flags": { + "targeting-flag": { + "state": "ENABLED", + "variants": { + "red": "red-value", + "blue": "blue-value" + }, + "defaultVariant": "red", + "targeting": { + "if": [ + { "==": [{ "var": "color" }, "blue"] }, + "blue", + "red" + ] + } + } + } + })"); + sync_->SetFlags(flags); + + // Without context, should return defaultVariant "red" + EXPECT_EQ(client_->GetStringValue("targeting-flag", "default"), "red-value"); + + // With context color=blue, should return "blue" + openfeature::EvaluationContext ctx = openfeature::EvaluationContext::Builder() + .WithAttribute("color", "blue") + .build(); + EXPECT_EQ(client_->GetStringValue("targeting-flag", "default", ctx), + "blue-value"); + + // With context color=green, should return "red" + openfeature::EvaluationContext ctx2 = + openfeature::EvaluationContext::Builder() + .WithAttribute("color", "green") + .build(); + EXPECT_EQ(client_->GetStringValue("targeting-flag", "default", ctx2), + "red-value"); +} + +} // namespace From 88f19c6eb2c53ca9c261e0c44526bcebc68b3b04 Mon Sep 17 00:00:00 2001 From: Marcin Olko Date: Fri, 13 Mar 2026 14:41:55 +0100 Subject: [PATCH 2/5] Update providers/flagd/tests/smoke/openfeature.cpp Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Marcin Olko --- providers/flagd/tests/smoke/openfeature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/flagd/tests/smoke/openfeature.cpp b/providers/flagd/tests/smoke/openfeature.cpp index b84fa4b..42dc278 100644 --- a/providers/flagd/tests/smoke/openfeature.cpp +++ b/providers/flagd/tests/smoke/openfeature.cpp @@ -130,7 +130,7 @@ TEST_F(FlagdOpenFeatureTest, ObjectEvaluation) { openfeature::Value val = client_->GetObjectValue("obj-flag", openfeature::Value()); - EXPECT_TRUE(val.IsStructure()); + ASSERT_TRUE(val.IsStructure()); const auto* structure = val.AsStructure(); EXPECT_EQ(structure->at("key").AsString().value(), "value"); } From d51d59f5627191df8f2d92dea8d7bf9b3a8e5992 Mon Sep 17 00:00:00 2001 From: Marcin Olko Date: Fri, 13 Mar 2026 13:48:33 +0000 Subject: [PATCH 3/5] Removed auto Signed-off-by: Marcin Olko --- providers/flagd/tests/smoke/openfeature.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/providers/flagd/tests/smoke/openfeature.cpp b/providers/flagd/tests/smoke/openfeature.cpp index 42dc278..4361b3c 100644 --- a/providers/flagd/tests/smoke/openfeature.cpp +++ b/providers/flagd/tests/smoke/openfeature.cpp @@ -40,7 +40,7 @@ class FlagdOpenFeatureTest : public ::testing::Test { }; TEST_F(FlagdOpenFeatureTest, BooleanEvaluation) { - auto flags = nlohmann::json::parse(R"({ + nlohmann::json flags = nlohmann::json::parse(R"({ "flags": { "bool-flag": { "state": "ENABLED", @@ -59,7 +59,7 @@ TEST_F(FlagdOpenFeatureTest, BooleanEvaluation) { } TEST_F(FlagdOpenFeatureTest, StringEvaluation) { - auto flags = nlohmann::json::parse(R"({ + nlohmann::json flags = nlohmann::json::parse(R"({ "flags": { "string-flag": { "state": "ENABLED", @@ -77,7 +77,7 @@ TEST_F(FlagdOpenFeatureTest, StringEvaluation) { } TEST_F(FlagdOpenFeatureTest, IntegerEvaluation) { - auto flags = nlohmann::json::parse(R"({ + nlohmann::json flags = nlohmann::json::parse(R"({ "flags": { "int-flag": { "state": "ENABLED", @@ -95,7 +95,7 @@ TEST_F(FlagdOpenFeatureTest, IntegerEvaluation) { } TEST_F(FlagdOpenFeatureTest, DoubleEvaluation) { - auto flags = nlohmann::json::parse(R"({ + nlohmann::json flags = nlohmann::json::parse(R"({ "flags": { "double-flag": { "state": "ENABLED", @@ -113,7 +113,7 @@ TEST_F(FlagdOpenFeatureTest, DoubleEvaluation) { } TEST_F(FlagdOpenFeatureTest, ObjectEvaluation) { - auto flags = nlohmann::json::parse(R"({ + nlohmann::json flags = nlohmann::json::parse(R"({ "flags": { "obj-flag": { "state": "ENABLED", @@ -131,13 +131,14 @@ TEST_F(FlagdOpenFeatureTest, ObjectEvaluation) { openfeature::Value val = client_->GetObjectValue("obj-flag", openfeature::Value()); ASSERT_TRUE(val.IsStructure()); - const auto* structure = val.AsStructure(); + const std::map* structure = + val.AsStructure(); EXPECT_EQ(structure->at("key").AsString().value(), "value"); } TEST_F(FlagdOpenFeatureTest, EvaluationContextTargeting) { // Example of targeting using EvaluationContext - auto flags = nlohmann::json::parse(R"({ + nlohmann::json flags = nlohmann::json::parse(R"({ "flags": { "targeting-flag": { "state": "ENABLED", From ecacfd5b187f5e1ec274cd0f22b1aa9e7b46b690 Mon Sep 17 00:00:00 2001 From: Marcin Olko Date: Fri, 13 Mar 2026 13:52:34 +0000 Subject: [PATCH 4/5] Fixed incorrect include Signed-off-by: Marcin Olko --- providers/flagd/tests/smoke/openfeature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/flagd/tests/smoke/openfeature.cpp b/providers/flagd/tests/smoke/openfeature.cpp index 58b636a..49ff0a1 100644 --- a/providers/flagd/tests/smoke/openfeature.cpp +++ b/providers/flagd/tests/smoke/openfeature.cpp @@ -3,7 +3,7 @@ #include #include -#include "flagd/provider/provider.h" +#include "flagd/provider.h" #include "flagd/sync/sync.h" #include "openfeature/openfeature_api.h" From d1aecb60b79a139c9f82db335efadb295bd9325b Mon Sep 17 00:00:00 2001 From: Marcin Olko Date: Wed, 18 Mar 2026 09:20:12 +0000 Subject: [PATCH 5/5] Addressed comments Signed-off-by: Marcin Olko --- providers/flagd/tests/smoke/openfeature.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/providers/flagd/tests/smoke/openfeature.cpp b/providers/flagd/tests/smoke/openfeature.cpp index 49ff0a1..174aeaf 100644 --- a/providers/flagd/tests/smoke/openfeature.cpp +++ b/providers/flagd/tests/smoke/openfeature.cpp @@ -24,13 +24,15 @@ class FlagdOpenFeatureTest : public ::testing::Test { void SetUp() override { sync_ = std::make_shared(); provider_ = std::make_shared(sync_); - auto& api = openfeature::OpenFeatureAPI::GetInstance(); + openfeature::OpenFeatureAPI& api = + openfeature::OpenFeatureAPI::GetInstance(); api.SetProviderAndWait(provider_); client_ = api.GetClient(); } void TearDown() override { - auto& api = openfeature::OpenFeatureAPI::GetInstance(); + openfeature::OpenFeatureAPI& api = + openfeature::OpenFeatureAPI::GetInstance(); api.Shutdown(); }