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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ And optionally these properties depending on whether you are evaluating a featur
- `VariableKey`: the variable key
- `VariableValue`: the variable value
- `VariableSchema`: the variable schema
- `VariableOverrideIndex`: index of matched variable override when applicable

## Hooks

Expand Down
5 changes: 5 additions & 0 deletions cmd/commands/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,11 @@ func getEvaluationValue(evaluation featurevisor.Evaluation, key string) interfac
return evaluation.VariableValue
case "variableSchema":
return evaluation.VariableSchema
case "variableOverrideIndex":
if evaluation.VariableOverrideIndex != nil {
return *evaluation.VariableOverrideIndex
}
return nil
default:
return nil
}
Expand Down
22 changes: 22 additions & 0 deletions cmd/commands/test_evaluation_value_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package commands

import (
"testing"

"github.com/featurevisor/featurevisor-go"
)

func TestGetEvaluationValueVariableOverrideIndex(t *testing.T) {
index := 2
evaluation := featurevisor.Evaluation{
Type: featurevisor.EvaluationTypeVariable,
FeatureKey: "test",
Reason: featurevisor.EvaluationReasonVariableOverrideRule,
VariableOverrideIndex: &index,
}

value := getEvaluationValue(evaluation, "variableOverrideIndex")
if value != 2 {
t.Fatalf("expected variableOverrideIndex to be 2, got %#v", value)
}
}
94 changes: 69 additions & 25 deletions evaluate.go
Original file line number Diff line number Diff line change
Expand Up @@ -778,26 +778,67 @@ func Evaluate(options EvaluateOptions) Evaluation {
}

// override from rule
if matchedTraffic != nil && matchedTraffic.Variables != nil {
if variableValue, exists := matchedTraffic.Variables[string(*options.VariableKey)]; exists {
evaluation = Evaluation{
Type: options.Type,
FeatureKey: options.FeatureKey,
Reason: EvaluationReasonRule,
BucketKey: &bucketKey,
BucketValue: &bucketValue,
RuleKey: &matchedTraffic.Key,
Traffic: matchedTraffic,
VariableKey: options.VariableKey,
VariableSchema: variableSchema,
VariableValue: variableValue,
if matchedTraffic != nil {
if matchedTraffic.VariableOverrides != nil {
if overrides, exists := matchedTraffic.VariableOverrides[*options.VariableKey]; exists {
for index, override := range overrides {
matched := false

if override.Conditions != nil {
parsedConditions := options.DatafileReader.parseConditionsIfStringified(override.Conditions)
matched = options.DatafileReader.AllConditionsAreMatched(parsedConditions, options.Context)
} else if override.Segments != nil {
parsedSegments := options.DatafileReader.parseSegmentsIfStringified(override.Segments)
matched = options.DatafileReader.AllSegmentsAreMatched(parsedSegments, options.Context)
}

if matched {
overrideIndex := index
evaluation = Evaluation{
Type: options.Type,
FeatureKey: options.FeatureKey,
Reason: EvaluationReasonVariableOverrideRule,
BucketKey: &bucketKey,
BucketValue: &bucketValue,
RuleKey: &matchedTraffic.Key,
Traffic: matchedTraffic,
VariableKey: options.VariableKey,
VariableSchema: variableSchema,
VariableValue: override.Value,
VariableOverrideIndex: &overrideIndex,
}

options.Logger.Debug("variable override from rule", LogDetails{
"evaluation": evaluation,
})

return evaluation
}
}
}
}

options.Logger.Debug("override from rule", LogDetails{
"evaluation": evaluation,
})
if matchedTraffic.Variables != nil {
if variableValue, exists := matchedTraffic.Variables[string(*options.VariableKey)]; exists {
evaluation = Evaluation{
Type: options.Type,
FeatureKey: options.FeatureKey,
Reason: EvaluationReasonRule,
BucketKey: &bucketKey,
BucketValue: &bucketValue,
RuleKey: &matchedTraffic.Key,
Traffic: matchedTraffic,
VariableKey: options.VariableKey,
VariableSchema: variableSchema,
VariableValue: variableValue,
}

return evaluation
options.Logger.Debug("override from rule", LogDetails{
"evaluation": evaluation,
})

return evaluation
}
}
}

Expand All @@ -817,22 +858,24 @@ func Evaluate(options EvaluateOptions) Evaluation {
if variation.Value == *variationValue {
if variation.VariableOverrides != nil {
if overrides, exists := variation.VariableOverrides[*options.VariableKey]; exists {
for _, override := range overrides {
for index, override := range overrides {
matched := false

if override.Conditions != nil {
matched = options.DatafileReader.AllConditionsAreMatched(override.Conditions, options.Context)
parsedConditions := options.DatafileReader.parseConditionsIfStringified(override.Conditions)
matched = options.DatafileReader.AllConditionsAreMatched(parsedConditions, options.Context)
} else if override.Segments != nil {
// Parse segments if they come from JSON unmarshaling
parsedSegments := options.DatafileReader.parseSegmentsIfStringified(override.Segments)
matched = options.DatafileReader.AllSegmentsAreMatched(parsedSegments, options.Context)
}

if matched {
overrideIndex := index
evaluation = Evaluation{
Type: options.Type,
FeatureKey: options.FeatureKey,
Reason: EvaluationReasonVariableOverride,
Reason: EvaluationReasonVariableOverrideVariation,
BucketKey: &bucketKey,
BucketValue: &bucketValue,
RuleKey: func() *RuleKey {
Expand All @@ -841,13 +884,14 @@ func Evaluate(options EvaluateOptions) Evaluation {
}
return nil
}(),
Traffic: matchedTraffic,
VariableKey: options.VariableKey,
VariableSchema: variableSchema,
VariableValue: override.Value,
Traffic: matchedTraffic,
VariableKey: options.VariableKey,
VariableSchema: variableSchema,
VariableValue: override.Value,
VariableOverrideIndex: &overrideIndex,
}

options.Logger.Debug("variable override", LogDetails{
options.Logger.Debug("variable override from variation", LogDetails{
"evaluation": evaluation,
})

Expand Down
16 changes: 9 additions & 7 deletions evaluation.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ const (
EvaluationReasonVariationDisabled EvaluationReason = "variation_disabled" // feature is disabled, and variation's disabledVariationValue is used

// Variable specific
EvaluationReasonVariableNotFound EvaluationReason = "variable_not_found" // variable's schema is not defined in the feature
EvaluationReasonVariableDefault EvaluationReason = "variable_default" // default variable value used
EvaluationReasonVariableDisabled EvaluationReason = "variable_disabled" // feature is disabled, and variable's disabledValue is used
EvaluationReasonVariableOverride EvaluationReason = "variable_override" // variable overridden from inside a variation
EvaluationReasonVariableNotFound EvaluationReason = "variable_not_found" // variable's schema is not defined in the feature
EvaluationReasonVariableDefault EvaluationReason = "variable_default" // default variable value used
EvaluationReasonVariableDisabled EvaluationReason = "variable_disabled" // feature is disabled, and variable's disabledValue is used
EvaluationReasonVariableOverrideVariation EvaluationReason = "variable_override_variation" // variable overridden from inside a variation
EvaluationReasonVariableOverrideRule EvaluationReason = "variable_override_rule" // variable overridden from inside a rule

// Common
EvaluationReasonNoMatch EvaluationReason = "no_match" // no rules matched
Expand Down Expand Up @@ -63,7 +64,8 @@ type Evaluation struct {
VariationValue *VariationValue `json:"variationValue,omitempty"`

// Variable
VariableKey *VariableKey `json:"variableKey,omitempty"`
VariableValue VariableValue `json:"variableValue,omitempty"`
VariableSchema *VariableSchema `json:"variableSchema,omitempty"`
VariableKey *VariableKey `json:"variableKey,omitempty"`
VariableValue VariableValue `json:"variableValue,omitempty"`
VariableSchema *VariableSchema `json:"variableSchema,omitempty"`
VariableOverrideIndex *int `json:"variableOverrideIndex,omitempty"`
}
Loading
Loading