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
70 changes: 53 additions & 17 deletions libs/common/include/launchdarkly/data/evaluation_reason.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#pragma once

#include <cstddef>
Expand Down Expand Up @@ -55,6 +55,27 @@

friend std::ostream& operator<<(std::ostream& out, ErrorKind const& kind);

/**
* Do not change these values. They must remain stable for the C API.
*/
enum class BigSegmentsStatus {
// The evaluation did not query any Big Segments.
kNone = 0,
// The query was successful and the segment state is up to date.
kHealthy = 1,
// The query was successful, but the segment state may not be up to
// date.
kStale = 2,
// Big Segments could not be queried because the SDK configuration did
// not include a Big Segment store.
kNotConfigured = 3,
// The query failed, for instance due to a database error.
kStoreError = 4,
};

friend std::ostream& operator<<(std::ostream& out,
BigSegmentsStatus const& status);

/**
* @return The general category of the reason.
*/
Expand All @@ -66,6 +87,21 @@
*/
[[nodiscard]] std::optional<ErrorKind> ErrorKind() const;

/**
* The validity of the Big Segment information used in this evaluation, or
* BigSegmentsStatus::kNone if the evaluation did not query any Big
* Segments.
*/
[[nodiscard]] enum BigSegmentsStatus BigSegmentsStatus() const;

/**
* Deprecated; use BigSegmentsStatus() instead. Returns the string passed
* to the deprecated string-typed constructor, or std::nullopt otherwise.
*/
[[deprecated("use BigSegmentsStatus()")]] [[nodiscard]] std::optional<
std::string>
BigSegmentStatus() const;

/**
* The index of the matched rule (0 for the first), if the kind was
* `"RULE_MATCH"`.
Expand Down Expand Up @@ -93,29 +129,25 @@
*/
[[nodiscard]] bool InExperiment() const;

/**
* Describes the validity of Big Segment information, if and only if the
* flag evaluation required querying at least one Big Segment.
*
* - `"HEALTHY"`: The Big Segment query involved in the flag evaluation was
* successful, and the segment state is considered up to date.
* - `"STALE"`: The Big Segment query involved in the flag evaluation was
* successful, but the segment state may not be up to date
* - `"NOT_CONFIGURED"`: Big Segments could not be queried for the flag
* evaluation because the SDK configuration did not include a Big Segment
* store.
* - `"STORE_ERROR"`: The Big Segment query involved in the flag evaluation
* failed, for instance due to a database error.
*/
[[nodiscard]] std::optional<std::string> BigSegmentStatus() const;

EvaluationReason(enum Kind kind,
std::optional<enum ErrorKind> error_kind,
std::optional<std::size_t> rule_index,
std::optional<std::string> rule_id,
std::optional<std::string> prerequisite_key,
bool in_experiment,
std::optional<std::string> big_segment_status);
enum BigSegmentsStatus big_segments_status);

/**
* Deprecated; use the overload taking @ref BigSegmentsStatus instead.
*/
[[deprecated("use the BigSegmentsStatus overload")]] EvaluationReason(
enum Kind kind,
std::optional<enum ErrorKind> error_kind,
std::optional<std::size_t> rule_index,
std::optional<std::string> rule_id,
std::optional<std::string> prerequisite_key,
bool in_experiment,
std::optional<std::string> big_segment_status);

explicit EvaluationReason(enum ErrorKind error_kind);

Expand Down Expand Up @@ -158,13 +190,17 @@
friend std::ostream& operator<<(std::ostream& out,
EvaluationReason const& reason);

friend bool operator==(EvaluationReason const& lhs,
EvaluationReason const& rhs);

private:
enum Kind kind_;
std::optional<enum ErrorKind> error_kind_;
std::optional<std::size_t> rule_index_;
std::optional<std::string> rule_id_;
std::optional<std::string> prerequisite_key_;
bool in_experiment_;
enum BigSegmentsStatus big_segments_status_;
std::optional<std::string> big_segment_status_;
};

Expand Down
110 changes: 91 additions & 19 deletions libs/common/src/data/evaluation_reason.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#include <launchdarkly/data/evaluation_reason.hpp>

namespace launchdarkly {
Expand Down Expand Up @@ -27,10 +27,32 @@
return in_experiment_;
}

enum EvaluationReason::BigSegmentsStatus
EvaluationReason::BigSegmentsStatus() const {
return big_segments_status_;
}

std::optional<std::string> EvaluationReason::BigSegmentStatus() const {
return big_segment_status_;
}

EvaluationReason::EvaluationReason(
enum Kind kind,
std::optional<enum ErrorKind> error_kind,
std::optional<std::size_t> rule_index,
std::optional<std::string> rule_id,
std::optional<std::string> prerequisite_key,
bool in_experiment,
enum BigSegmentsStatus big_segments_status)
: kind_(kind),
error_kind_(error_kind),
rule_index_(rule_index),
rule_id_(std::move(rule_id)),
prerequisite_key_(std::move(prerequisite_key)),
in_experiment_(in_experiment),
big_segments_status_(big_segments_status),
big_segment_status_(std::nullopt) {}

EvaluationReason::EvaluationReason(
enum Kind kind,
std::optional<enum ErrorKind> error_kind,
Expand All @@ -45,44 +67,69 @@
rule_id_(std::move(rule_id)),
prerequisite_key_(std::move(prerequisite_key)),
in_experiment_(in_experiment),
big_segments_status_(BigSegmentsStatus::kNone),
big_segment_status_(std::move(big_segment_status)) {}

EvaluationReason::EvaluationReason(enum ErrorKind error_kind)
: EvaluationReason(Kind::kError,
error_kind,
std::nullopt,
std::nullopt,
std::nullopt,
false,
std::nullopt) {}
/* rule_index= */ std::nullopt,
/* rule_id= */ std::nullopt,
/* prerequisite_key= */ std::nullopt,
/* in_experiment= */ false,
BigSegmentsStatus::kNone) {}

EvaluationReason EvaluationReason::Off() {
return {Kind::kOff, std::nullopt, std::nullopt, std::nullopt,
std::nullopt, false, std::nullopt};
return {Kind::kOff,
/* error_kind= */ std::nullopt,
/* rule_index= */ std::nullopt,
/* rule_id= */ std::nullopt,
/* prerequisite_key= */ std::nullopt,
/* in_experiment= */ false,
BigSegmentsStatus::kNone};
}

EvaluationReason EvaluationReason::PrerequisiteFailed(
std::string prerequisite_key) {
return {
Kind::kPrerequisiteFailed, std::nullopt, std::nullopt, std::nullopt,
std::move(prerequisite_key), false, std::nullopt};
return {Kind::kPrerequisiteFailed,
/* error_kind= */ std::nullopt,
/* rule_index= */ std::nullopt,
/* rule_id= */ std::nullopt,
std::move(prerequisite_key),
/* in_experiment= */ false,
BigSegmentsStatus::kNone};
}

EvaluationReason EvaluationReason::TargetMatch() {
return {Kind::kTargetMatch, std::nullopt, std::nullopt, std::nullopt,
std::nullopt, false, std::nullopt};
return {Kind::kTargetMatch,
/* error_kind= */ std::nullopt,
/* rule_index= */ std::nullopt,
/* rule_id= */ std::nullopt,
/* prerequisite_key= */ std::nullopt,
/* in_experiment= */ false,
BigSegmentsStatus::kNone};
}

EvaluationReason EvaluationReason::Fallthrough(bool in_experiment) {
return {Kind::kFallthrough, std::nullopt, std::nullopt, std::nullopt,
std::nullopt, in_experiment, std::nullopt};
return {Kind::kFallthrough,
/* error_kind= */ std::nullopt,
/* rule_index= */ std::nullopt,
/* rule_id= */ std::nullopt,
/* prerequisite_key= */ std::nullopt,
in_experiment,
BigSegmentsStatus::kNone};
}

EvaluationReason EvaluationReason::RuleMatch(std::size_t rule_index,
std::optional<std::string> rule_id,
bool in_experiment) {
return {Kind::kRuleMatch, std::nullopt, rule_index, std::move(rule_id),
std::nullopt, in_experiment, std::nullopt};
return {Kind::kRuleMatch,
/* error_kind= */ std::nullopt,
rule_index,
std::move(rule_id),
/* prerequisite_key= */ std::nullopt,
in_experiment,
BigSegmentsStatus::kNone};
}

EvaluationReason EvaluationReason::MalformedFlag() {
Expand All @@ -105,8 +152,9 @@
out << " prerequisiteKey: " << reason.prerequisite_key_.value();
}
out << " inExperiment: " << reason.in_experiment_;
if (reason.big_segment_status_.has_value()) {
out << " bigSegmentStatus: " << reason.big_segment_status_.value();
if (reason.big_segments_status_ !=
EvaluationReason::BigSegmentsStatus::kNone) {
out << " bigSegmentsStatus: " << reason.big_segments_status_;
}
out << "}";
return out;
Expand All @@ -115,7 +163,8 @@
bool operator==(EvaluationReason const& lhs, EvaluationReason const& rhs) {
return lhs.Kind() == rhs.Kind() && lhs.ErrorKind() == rhs.ErrorKind() &&
lhs.InExperiment() == rhs.InExperiment() &&
lhs.BigSegmentStatus() == rhs.BigSegmentStatus() &&
lhs.BigSegmentsStatus() == rhs.BigSegmentsStatus() &&
lhs.big_segment_status_ == rhs.big_segment_status_ &&
lhs.PrerequisiteKey() == rhs.PrerequisiteKey() &&
lhs.RuleId() == rhs.RuleId() && lhs.RuleIndex() == rhs.RuleIndex();
}
Expand Down Expand Up @@ -149,6 +198,29 @@
return out;
}

std::ostream& operator<<(
std::ostream& out,
enum EvaluationReason::BigSegmentsStatus const& status) {
switch (status) {
case EvaluationReason::BigSegmentsStatus::kNone:
out << "NONE";
break;
case EvaluationReason::BigSegmentsStatus::kHealthy:
out << "HEALTHY";
break;
case EvaluationReason::BigSegmentsStatus::kStale:
out << "STALE";
break;
case EvaluationReason::BigSegmentsStatus::kNotConfigured:
out << "NOT_CONFIGURED";
break;
case EvaluationReason::BigSegmentsStatus::kStoreError:
out << "STORE_ERROR";
break;
}
return out;
}

std::ostream& operator<<(std::ostream& out,
enum EvaluationReason::ErrorKind const& kind) {
switch (kind) {
Expand Down
18 changes: 13 additions & 5 deletions libs/common/tests/bindings/evaluation_detail_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ TEST(EvaluationDetailBindings, EvaluationReasonError) {

TEST(EvaluationDetailBindings, EvaluationReasonFallthrough) {
auto reason = EvaluationReason(EvaluationReason::Kind::kFallthrough,
std::nullopt, std::nullopt, std::nullopt,
std::nullopt, true, std::nullopt);
/* error_kind= */ std::nullopt,
/* rule_index= */ std::nullopt,
/* rule_id= */ std::nullopt,
/* prerequisite_key= */ std::nullopt,
/* in_experiment= */ true,
EvaluationReason::BigSegmentsStatus::kNone);
auto ld_reason = reinterpret_cast<LDEvalReason>(&reason);

ASSERT_EQ(LDEvalReason_Kind(ld_reason), LD_EVALREASON_FALLTHROUGH);
Expand Down Expand Up @@ -52,9 +56,13 @@ TEST(EvaluationDetailBindings, EvaluationDetailError) {
TEST(EvaluationDetailBindings, EvaluationDetailSuccess) {
auto detail = CEvaluationDetail(EvaluationDetail<bool>(
true, 42,
EvaluationReason(EvaluationReason::Kind::kFallthrough, std::nullopt,
std::nullopt, std::nullopt, std::nullopt, true,
std::nullopt)));
EvaluationReason(EvaluationReason::Kind::kFallthrough,
/* error_kind= */ std::nullopt,
/* rule_index= */ std::nullopt,
/* rule_id= */ std::nullopt,
/* prerequisite_key= */ std::nullopt,
/* in_experiment= */ true,
EvaluationReason::BigSegmentsStatus::kNone)));

auto ld_detail = reinterpret_cast<LDEvalDetail>(&detail);

Expand Down
Loading
Loading