Skip to content
Open
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
2 changes: 2 additions & 0 deletions openfeature/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ cc_library(
":provider",
":resolution_details",
":value",
"@abseil-cpp//absl/status:statusor",
],
)

Expand Down Expand Up @@ -165,6 +166,7 @@ cc_library(
include_prefix = "openfeature",
deps = [
"@abseil-cpp//absl/status",
"@abseil-cpp//absl/status:statusor",
":evaluation_context",
":metadata",
":resolution_details",
Expand Down
22 changes: 20 additions & 2 deletions openfeature/client_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,27 @@ std::unique_ptr<ResolutionDetailsType> ClientAPI::EvaluateFlag(
}

EvaluationContext merged_context = MergeContexts(ctx);
return provider_call(provider, merged_context);
}

try {
auto result = provider_call(provider, merged_context);

if (!result.ok() || *result == nullptr) {
return std::make_unique<ResolutionDetailsType>(
default_value, Reason::kError, std::nullopt, FlagMetadata(),
ErrorCode::kGeneral, std::string(result.status().message()));
}
return std::move(*result);
} catch (const std::exception& e) {
return std::make_unique<ResolutionDetailsType>(
default_value, Reason::kError, std::nullopt, FlagMetadata(),
ErrorCode::kGeneral,
std::string("Exception during evaluation: ") + e.what());
} catch (...) {
return std::make_unique<ResolutionDetailsType>(
default_value, Reason::kError, std::nullopt, FlagMetadata(),
ErrorCode::kGeneral, "Unknown exception during evaluation");
}
}
} // namespace openfeature

#endif // CPP_SDK_INCLUDE_OPENFEATURE_CLIENT_API_H_
40 changes: 24 additions & 16 deletions openfeature/memory_provider/in_memory_provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ static constexpr std::string_view kName = "InMemoryProvider";

InMemoryProvider::InMemoryProvider(
std::unordered_map<std::string, std::any> flags)
: flags_(std::move(flags)), status_(ProviderStatus::kNotReady) {}
: flags_(std::move(flags)) {}

Metadata InMemoryProvider::GetMetadata() const {
return Metadata{std::string(kName)};
Expand Down Expand Up @@ -50,35 +50,43 @@ void InMemoryProvider::UpdateFlag(std::string key, std::any new_flag) {
flags_.insert_or_assign(std::move(key), std::move(new_flag));
}

std::unique_ptr<BoolResolutionDetails> InMemoryProvider::GetBooleanEvaluation(
std::string_view key, bool default_value, const EvaluationContext& ctx) {
absl::StatusOr<std::unique_ptr<BoolResolutionDetails>>
InMemoryProvider::GetBooleanEvaluation(std::string_view key, bool default_value,
const EvaluationContext& ctx) {
return Evaluate<bool>(key, default_value, ctx);
}

std::unique_ptr<StringResolutionDetails> InMemoryProvider::GetStringEvaluation(
std::string_view key, std::string_view default_value,
const EvaluationContext& ctx) {
absl::StatusOr<std::unique_ptr<StringResolutionDetails>>
InMemoryProvider::GetStringEvaluation(std::string_view key,
std::string_view default_value,
const EvaluationContext& ctx) {
return Evaluate<std::string>(key, std::string(default_value), ctx);
}

std::unique_ptr<IntResolutionDetails> InMemoryProvider::GetIntegerEvaluation(
std::string_view key, int64_t default_value, const EvaluationContext& ctx) {
absl::StatusOr<std::unique_ptr<IntResolutionDetails>>
InMemoryProvider::GetIntegerEvaluation(std::string_view key,
int64_t default_value,
const EvaluationContext& ctx) {
return Evaluate<int64_t>(key, default_value, ctx);
}

std::unique_ptr<DoubleResolutionDetails> InMemoryProvider::GetDoubleEvaluation(
std::string_view key, double default_value, const EvaluationContext& ctx) {
absl::StatusOr<std::unique_ptr<DoubleResolutionDetails>>
InMemoryProvider::GetDoubleEvaluation(std::string_view key,
double default_value,
const EvaluationContext& ctx) {
return Evaluate<double>(key, default_value, ctx);
}

std::unique_ptr<ObjectResolutionDetails> InMemoryProvider::GetObjectEvaluation(
std::string_view key, Value default_value, const EvaluationContext& ctx) {
absl::StatusOr<std::unique_ptr<ObjectResolutionDetails>>
InMemoryProvider::GetObjectEvaluation(std::string_view key, Value default_value,
const EvaluationContext& ctx) {
return Evaluate<Value>(key, default_value, ctx);
}

template <typename T>
std::unique_ptr<ResolutionDetails<T>> InMemoryProvider::Evaluate(
std::string_view key, T default_value, const EvaluationContext& ctx) {
std::string_view key, const T& default_value,
const EvaluationContext& ctx) {
std::shared_lock lock(mutex_);

if (status_ != ProviderStatus::kReady) {
Expand All @@ -98,14 +106,14 @@ std::unique_ptr<ResolutionDetails<T>> InMemoryProvider::Evaluate(
}

std::string key_str{key};
auto it = flags_.find(key_str);
if (it == flags_.end()) {
auto flag_it = flags_.find(key_str);
if (flag_it == flags_.end()) {
return std::make_unique<ResolutionDetails<T>>(
default_value, Reason::kError, std::nullopt, FlagMetadata{},
ErrorCode::kFlagNotFound, "Flag " + key_str + " not found");
}

const Flag<T>* flag = std::any_cast<Flag<T>>(&it->second);
const Flag<T>* flag = std::any_cast<Flag<T>>(&flag_it->second);

if (!flag) {
return std::make_unique<ResolutionDetails<T>>(
Expand Down
19 changes: 10 additions & 9 deletions openfeature/memory_provider/in_memory_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <unordered_map>

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "openfeature/evaluation_context.h"
#include "openfeature/metadata.h"
#include "openfeature/provider.h"
Expand All @@ -23,9 +24,9 @@ namespace openfeature {
// evaluation based on the provided EvaluationContext.
class InMemoryProvider : public FeatureProvider {
public:
InMemoryProvider(std::unordered_map<std::string, std::any> flags);
explicit InMemoryProvider(std::unordered_map<std::string, std::any> flags);

~InMemoryProvider() = default;
~InMemoryProvider() override = default;

Metadata GetMetadata() const override;

Expand All @@ -42,34 +43,34 @@ class InMemoryProvider : public FeatureProvider {
// will be added to the configuration.
void UpdateFlag(std::string key, std::any new_flag);

std::unique_ptr<BoolResolutionDetails> GetBooleanEvaluation(
absl::StatusOr<std::unique_ptr<BoolResolutionDetails>> GetBooleanEvaluation(
std::string_view key, bool default_value,
const EvaluationContext& ctx) override;

std::unique_ptr<StringResolutionDetails> GetStringEvaluation(
absl::StatusOr<std::unique_ptr<StringResolutionDetails>> GetStringEvaluation(
std::string_view key, std::string_view default_value,
const EvaluationContext& ctx) override;

std::unique_ptr<IntResolutionDetails> GetIntegerEvaluation(
absl::StatusOr<std::unique_ptr<IntResolutionDetails>> GetIntegerEvaluation(
std::string_view key, int64_t default_value,
const EvaluationContext& ctx) override;

std::unique_ptr<DoubleResolutionDetails> GetDoubleEvaluation(
absl::StatusOr<std::unique_ptr<DoubleResolutionDetails>> GetDoubleEvaluation(
std::string_view key, double default_value,
const EvaluationContext& ctx) override;

std::unique_ptr<ObjectResolutionDetails> GetObjectEvaluation(
absl::StatusOr<std::unique_ptr<ObjectResolutionDetails>> GetObjectEvaluation(
std::string_view key, Value default_value,
const EvaluationContext& ctx) override;

private:
template <typename T>
std::unique_ptr<ResolutionDetails<T>> Evaluate(std::string_view key,
T default_value,
const T& default_value,
const EvaluationContext& ctx);

std::unordered_map<std::string, std::any> flags_;
ProviderStatus status_;
ProviderStatus status_ = ProviderStatus::kNotReady;
mutable std::shared_mutex mutex_;
};

Expand Down
28 changes: 16 additions & 12 deletions openfeature/noop_provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,42 @@ namespace openfeature {

Metadata NoopProvider::GetMetadata() const { return Metadata{name_}; }

std::unique_ptr<BoolResolutionDetails> NoopProvider::GetBooleanEvaluation(
std::string_view flag, bool default_value, const EvaluationContext& ctx) {
absl::StatusOr<std::unique_ptr<BoolResolutionDetails>>
NoopProvider::GetBooleanEvaluation(std::string_view flag, bool default_value,
const EvaluationContext& ctx) {
return std::make_unique<BoolResolutionDetails>(
default_value, Reason::kDefault, "default-variant", FlagMetadata(),
std::nullopt, "");
}

std::unique_ptr<StringResolutionDetails> NoopProvider::GetStringEvaluation(
std::string_view flag, std::string_view default_value,
const EvaluationContext& ctx) {
absl::StatusOr<std::unique_ptr<StringResolutionDetails>>
NoopProvider::GetStringEvaluation(std::string_view flag,
std::string_view default_value,
const EvaluationContext& ctx) {
return std::make_unique<StringResolutionDetails>(
std::string(default_value), Reason::kDefault, "default-variant",
FlagMetadata(), std::nullopt, "");
}

std::unique_ptr<IntResolutionDetails> NoopProvider::GetIntegerEvaluation(
std::string_view flag, int64_t default_value,
const EvaluationContext& ctx) {
absl::StatusOr<std::unique_ptr<IntResolutionDetails>>
NoopProvider::GetIntegerEvaluation(std::string_view flag, int64_t default_value,
const EvaluationContext& ctx) {
return std::make_unique<IntResolutionDetails>(
default_value, Reason::kDefault, "default-variant", FlagMetadata(),
std::nullopt, "");
}

std::unique_ptr<DoubleResolutionDetails> NoopProvider::GetDoubleEvaluation(
std::string_view flag, double default_value, const EvaluationContext& ctx) {
absl::StatusOr<std::unique_ptr<DoubleResolutionDetails>>
NoopProvider::GetDoubleEvaluation(std::string_view flag, double default_value,
const EvaluationContext& ctx) {
return std::make_unique<DoubleResolutionDetails>(
default_value, Reason::kDefault, "default-variant", FlagMetadata(),
std::nullopt, "");
}

std::unique_ptr<ObjectResolutionDetails> NoopProvider::GetObjectEvaluation(
std::string_view flag, Value default_value, const EvaluationContext& ctx) {
absl::StatusOr<std::unique_ptr<ObjectResolutionDetails>>
NoopProvider::GetObjectEvaluation(std::string_view flag, Value default_value,
const EvaluationContext& ctx) {
return std::make_unique<ObjectResolutionDetails>(
default_value, Reason::kDefault, "default-variant", FlagMetadata(),
std::nullopt, "");
Expand Down
11 changes: 6 additions & 5 deletions openfeature/noop_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>
#include <string_view>

#include "absl/status/statusor.h"
#include "openfeature/evaluation_context.h"
#include "openfeature/metadata.h"
#include "openfeature/provider.h"
Expand All @@ -23,27 +24,27 @@ class NoopProvider : public FeatureProvider {
Metadata GetMetadata() const override;

// BooleanEvaluation returns a boolean flag.
std::unique_ptr<BoolResolutionDetails> GetBooleanEvaluation(
absl::StatusOr<std::unique_ptr<BoolResolutionDetails>> GetBooleanEvaluation(
std::string_view flag, bool default_value,
const EvaluationContext& ctx) override;

// StringResolutionDetails returns a string flag.
std::unique_ptr<StringResolutionDetails> GetStringEvaluation(
absl::StatusOr<std::unique_ptr<StringResolutionDetails>> GetStringEvaluation(
std::string_view flag, std::string_view default_value,
const EvaluationContext& ctx) override;

// IntResolutionDetails returns an integer flag.
std::unique_ptr<IntResolutionDetails> GetIntegerEvaluation(
absl::StatusOr<std::unique_ptr<IntResolutionDetails>> GetIntegerEvaluation(
std::string_view flag, int64_t default_value,
const EvaluationContext& ctx) override;

// DoubleResolutionDetails returns a double flag.
std::unique_ptr<DoubleResolutionDetails> GetDoubleEvaluation(
absl::StatusOr<std::unique_ptr<DoubleResolutionDetails>> GetDoubleEvaluation(
std::string_view flag, double default_value,
const EvaluationContext& ctx) override;

// ObjectResolutionDetails returns an object flag.
std::unique_ptr<ObjectResolutionDetails> GetObjectEvaluation(
absl::StatusOr<std::unique_ptr<ObjectResolutionDetails>> GetObjectEvaluation(
std::string_view flag, Value default_value,
const EvaluationContext& ctx) override;

Expand Down
34 changes: 19 additions & 15 deletions openfeature/provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string_view>

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "openfeature/evaluation_context.h"
#include "openfeature/metadata.h"
#include "openfeature/resolution_details.h"
Expand All @@ -15,26 +16,29 @@ namespace openfeature {
// FeatureProvider interface defines a set of functions that can be called
// in order to evaluate a flag. This should be implemented by flag management
// systems.
// Implementations must NOT throw C++ exceptions. All errors
// must be reported by returning an absl::Status inside the absl::StatusOr.
// Throwing an exception will cause abnormal termination of the application.
// https://openfeature.dev/specification/sections/providers#21-feature-provider-interface
class FeatureProvider {
public:
virtual ~FeatureProvider() = default;
virtual Metadata GetMetadata() const = 0;
virtual std::unique_ptr<BoolResolutionDetails> GetBooleanEvaluation(
std::string_view flag, bool default_value,
const EvaluationContext& ctx) = 0;
virtual std::unique_ptr<StringResolutionDetails> GetStringEvaluation(
std::string_view flag, std::string_view default_value,
const EvaluationContext& ctx) = 0;
virtual std::unique_ptr<IntResolutionDetails> GetIntegerEvaluation(
std::string_view flag, int64_t default_value,
const EvaluationContext& ctx) = 0;
virtual std::unique_ptr<DoubleResolutionDetails> GetDoubleEvaluation(
std::string_view flag, double default_value,
const EvaluationContext& ctx) = 0;
virtual std::unique_ptr<ObjectResolutionDetails> GetObjectEvaluation(
std::string_view flag, Value default_value,
const EvaluationContext& ctx) = 0;
virtual absl::StatusOr<std::unique_ptr<BoolResolutionDetails>>
GetBooleanEvaluation(std::string_view flag, bool default_value,
const EvaluationContext& ctx) = 0;
virtual absl::StatusOr<std::unique_ptr<StringResolutionDetails>>
GetStringEvaluation(std::string_view flag, std::string_view default_value,
const EvaluationContext& ctx) = 0;
virtual absl::StatusOr<std::unique_ptr<IntResolutionDetails>>
GetIntegerEvaluation(std::string_view flag, int64_t default_value,
const EvaluationContext& ctx) = 0;
virtual absl::StatusOr<std::unique_ptr<DoubleResolutionDetails>>
GetDoubleEvaluation(std::string_view flag, double default_value,
const EvaluationContext& ctx) = 0;
virtual absl::StatusOr<std::unique_ptr<ObjectResolutionDetails>>
GetObjectEvaluation(std::string_view flag, Value default_value,
const EvaluationContext& ctx) = 0;
virtual absl::Status Init(const EvaluationContext& ctx) {
return absl::OkStatus();
}
Expand Down
4 changes: 3 additions & 1 deletion test/e2e/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ cc_library(
"//openfeature:reason",
"//openfeature:value",
"//openfeature:resolution_details",
"@googletest//:gtest",
"@googletest//:gtest",
"@abseil-cpp//absl/status",
"@abseil-cpp//absl/status:statusor",
],
)

Expand Down
10 changes: 5 additions & 5 deletions test/e2e/context_storing_provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ openfeature::Metadata ContextStoringProvider::GetMetadata() const {
return openfeature::Metadata{"ContextStoringProvider"};
}

std::unique_ptr<openfeature::BoolResolutionDetails>
absl::StatusOr<std::unique_ptr<openfeature::BoolResolutionDetails>>
ContextStoringProvider::GetBooleanEvaluation(
std::string_view key, bool default_value,
const openfeature::EvaluationContext& ctx) {
Expand All @@ -25,7 +25,7 @@ ContextStoringProvider::GetBooleanEvaluation(
openfeature::FlagMetadata{}, std::nullopt, "");
}

std::unique_ptr<openfeature::StringResolutionDetails>
absl::StatusOr<std::unique_ptr<openfeature::StringResolutionDetails>>
ContextStoringProvider::GetStringEvaluation(
std::string_view key, std::string_view default_value,
const openfeature::EvaluationContext& ctx) {
Expand All @@ -36,7 +36,7 @@ ContextStoringProvider::GetStringEvaluation(
openfeature::FlagMetadata{}, std::nullopt, "");
}

std::unique_ptr<openfeature::IntResolutionDetails>
absl::StatusOr<std::unique_ptr<openfeature::IntResolutionDetails>>
ContextStoringProvider::GetIntegerEvaluation(
std::string_view key, int64_t default_value,
const openfeature::EvaluationContext& ctx) {
Expand All @@ -47,7 +47,7 @@ ContextStoringProvider::GetIntegerEvaluation(
openfeature::FlagMetadata{}, std::nullopt, "");
}

std::unique_ptr<openfeature::DoubleResolutionDetails>
absl::StatusOr<std::unique_ptr<openfeature::DoubleResolutionDetails>>
ContextStoringProvider::GetDoubleEvaluation(
std::string_view key, double default_value,
const openfeature::EvaluationContext& ctx) {
Expand All @@ -58,7 +58,7 @@ ContextStoringProvider::GetDoubleEvaluation(
openfeature::FlagMetadata{}, std::nullopt, "");
}

std::unique_ptr<openfeature::ObjectResolutionDetails>
absl::StatusOr<std::unique_ptr<openfeature::ObjectResolutionDetails>>
ContextStoringProvider::GetObjectEvaluation(
std::string_view key, const openfeature::Value default_value,
const openfeature::EvaluationContext& ctx) {
Expand Down
Loading