Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions providers/flagd/src/provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@ FlagdProvider::FlagdProvider(FlagdProviderConfig config)
evaluator_ = std::make_unique<JsonLogicEvaluator>(sync_);
}

FlagdProvider::FlagdProvider(std::shared_ptr<FlagSync> sync,
FlagdProviderConfig config)
: configuration_(std::move(config)),
sync_(std::move(sync)),
evaluator_(std::make_unique<JsonLogicEvaluator>(sync_)),
is_ready_(false) {}

FlagdProvider::FlagdProvider(std::shared_ptr<FlagSync> sync,
std::unique_ptr<Evaluator> evaluator,
FlagdProviderConfig config)
: configuration_(std::move(config)),
sync_(std::move(sync)),
evaluator_(std::move(evaluator)),
is_ready_(false) {}

FlagdProvider::~FlagdProvider() {
if (is_ready_) {
absl::Status status = FlagdProvider::Shutdown();
Expand Down
5 changes: 5 additions & 0 deletions providers/flagd/src/provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ namespace flagd {
class FlagdProvider : public openfeature::FeatureProvider {
public:
explicit FlagdProvider(FlagdProviderConfig config = FlagdProviderConfig());
explicit FlagdProvider(std::shared_ptr<FlagSync> sync,
FlagdProviderConfig config = FlagdProviderConfig());
FlagdProvider(std::shared_ptr<FlagSync> sync,
std::unique_ptr<Evaluator> evaluator,
FlagdProviderConfig config = FlagdProviderConfig());

~FlagdProvider() override;

Expand Down
10 changes: 10 additions & 0 deletions providers/flagd/tests/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
load("@rules_cc//cc:defs.bzl", "cc_test")

cc_test(
name = "provider_test",
srcs = ["provider_test.cpp"],
deps = [
"//providers/flagd/src:flagd_provider",
"@googletest//:gtest_main",
],
)
2 changes: 1 addition & 1 deletion providers/flagd/tests/evaluator/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cc_test(
srcs = ["evaluator_test.cpp"],
deps = [
"//providers/flagd/src/evaluator",
"//providers/flagd/src/sync:sync",
"//providers/flagd/src/sync",
"@googletest//:gtest_main",
"@nlohmann_json//:json",
],
Expand Down
150 changes: 150 additions & 0 deletions providers/flagd/tests/provider_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#include "flagd/provider.h"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <memory>

#include "flagd/evaluator/evaluator.h"
#include "flagd/sync/sync.h"

namespace flagd {

class MockSync : public FlagSync {
public:
MOCK_METHOD(absl::Status, Init, (const openfeature::EvaluationContext& ctx),
(override));
MOCK_METHOD(absl::Status, Shutdown, (), (override));
};

class MockEvaluator : public Evaluator {
public:
MOCK_METHOD(std::unique_ptr<openfeature::BoolResolutionDetails>,
ResolveBoolean,
(std::string_view flag_key, bool default_value,
const openfeature::EvaluationContext& ctx),
(override));
MOCK_METHOD(std::unique_ptr<openfeature::StringResolutionDetails>,
ResolveString,
(std::string_view flag_key, std::string_view default_value,
const openfeature::EvaluationContext& ctx),
(override));
MOCK_METHOD(std::unique_ptr<openfeature::IntResolutionDetails>,
ResolveInteger,
(std::string_view flag_key, int64_t default_value,
const openfeature::EvaluationContext& ctx),
(override));
MOCK_METHOD(std::unique_ptr<openfeature::DoubleResolutionDetails>,
ResolveDouble,
(std::string_view flag_key, double default_value,
const openfeature::EvaluationContext& ctx),
(override));
MOCK_METHOD(std::unique_ptr<openfeature::ObjectResolutionDetails>,
ResolveObject,
(std::string_view flag_key, openfeature::Value default_value,
const openfeature::EvaluationContext& ctx),
(override));
};

TEST(ProviderTest, MetadataReturnsExpectedValues) {
FlagdProvider provider;
openfeature::Metadata metadata = provider.GetMetadata();
EXPECT_EQ(metadata.name, "flagd");
}

TEST(ProviderTest, ReturnsNotReadyBeforeInit) {
auto mock_sync = std::make_shared<MockSync>();
auto mock_evaluator = std::make_unique<MockEvaluator>();

// We don't expect any calls to the evaluator when not ready
EXPECT_CALL(*mock_evaluator, ResolveBoolean).Times(0);

FlagdProvider provider(mock_sync, std::move(mock_evaluator));

std::unique_ptr<openfeature::BoolResolutionDetails> result =
provider.GetBooleanEvaluation(
"some-flag", false,
openfeature::EvaluationContext::Builder().build());

EXPECT_EQ(result->GetErrorCode(), openfeature::ErrorCode::kProviderNotReady);
EXPECT_EQ(result->GetReason(), openfeature::Reason::kError);
}

TEST(ProviderTest, ReturnsReadyAfterInit) {
auto mock_sync = std::make_shared<MockSync>();
auto mock_evaluator = std::make_unique<MockEvaluator>();

EXPECT_CALL(*mock_sync, Init).WillOnce(testing::Return(absl::OkStatus()));

EXPECT_CALL(*mock_evaluator, ResolveBoolean)
.WillOnce([](std::string_view flag_key, bool default_value,
const openfeature::EvaluationContext& ctx) {
return std::make_unique<openfeature::BoolResolutionDetails>(
true, openfeature::Reason::kStatic, "on",
openfeature::FlagMetadata());
});

FlagdProvider provider(mock_sync, std::move(mock_evaluator));
(void)provider.Init(openfeature::EvaluationContext::Builder().build());

std::unique_ptr<openfeature::BoolResolutionDetails> result =
provider.GetBooleanEvaluation(
"some-flag", false,
openfeature::EvaluationContext::Builder().build());

EXPECT_EQ(result->GetValue(), true);
EXPECT_EQ(result->GetReason(), openfeature::Reason::kStatic);
}

TEST(ProviderTest, DelegationWorks) {
auto mock_sync = std::make_shared<MockSync>();
auto mock_evaluator = std::make_unique<MockEvaluator>();

EXPECT_CALL(*mock_sync, Init).WillOnce(testing::Return(absl::OkStatus()));

std::string expected_flag = "my-flag";
bool expected_default = true;

EXPECT_CALL(*mock_evaluator,
ResolveBoolean(testing::Eq(expected_flag),
testing::Eq(expected_default), testing::_))
.WillOnce([](std::string_view flag_key, bool default_value,
const openfeature::EvaluationContext& ctx) {
return std::make_unique<openfeature::BoolResolutionDetails>(
default_value, openfeature::Reason::kDefault, std::nullopt,
openfeature::FlagMetadata());
});

FlagdProvider provider(mock_sync, std::move(mock_evaluator));
(void)provider.Init(openfeature::EvaluationContext::Builder().build());

std::unique_ptr<openfeature::BoolResolutionDetails> result =
provider.GetBooleanEvaluation(
expected_flag, expected_default,
openfeature::EvaluationContext::Builder().build());

EXPECT_EQ(result->GetValue(), expected_default);
EXPECT_EQ(result->GetReason(), openfeature::Reason::kDefault);
}

TEST(ProviderTest, ShutdownMakesProviderNotReady) {
auto mock_sync = std::make_shared<MockSync>();
auto mock_evaluator = std::make_unique<MockEvaluator>();

EXPECT_CALL(*mock_sync, Init).WillOnce(testing::Return(absl::OkStatus()));
EXPECT_CALL(*mock_sync, Shutdown).WillOnce(testing::Return(absl::OkStatus()));

FlagdProvider provider(mock_sync, std::move(mock_evaluator));
(void)provider.Init(openfeature::EvaluationContext::Builder().build());
(void)provider.Shutdown();

std::unique_ptr<openfeature::BoolResolutionDetails> result =
provider.GetBooleanEvaluation(
"some-flag", false,
openfeature::EvaluationContext::Builder().build());

EXPECT_EQ(result->GetErrorCode(), openfeature::ErrorCode::kProviderNotReady);
EXPECT_EQ(result->GetReason(), openfeature::Reason::kError);
}

} // namespace flagd
Loading