Skip to content

Commit 0ec0c20

Browse files
committed
Added fallback treatment in the evaluator
1 parent c57cb46 commit 0ec0c20

File tree

5 files changed

+66
-25
lines changed

5 files changed

+66
-25
lines changed

dtos/fallbacktreatment.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,26 @@ type FallbackTreatment struct {
1212

1313
type FallbackTreatmentConfig struct {
1414
GlobalFallbackTreatment *FallbackTreatment
15-
byFlagFallbackTreatment map[string]FallbackTreatment
15+
ByFlagFallbackTreatment map[string]FallbackTreatment
1616
}
1717

1818
type FallbackTreatmentCalculator interface {
19-
Resolve(flagName string, label string) FallbackTreatment
19+
Resolve(flagName string, label *string) FallbackTreatment
2020
}
2121

2222
type FallbackTreatmentCalculatorImp struct {
2323
fallbackTreatmentConfig *FallbackTreatmentConfig
2424
}
2525

26-
func NewFallbackTreatmentCalculatorImp(fallbackTreatmentConfig *FallbackTreatmentConfig) FallbackTreatmentCalculatorImp {
27-
return FallbackTreatmentCalculatorImp{
26+
func NewFallbackTreatmentCalculatorImp(fallbackTreatmentConfig *FallbackTreatmentConfig) FallbackTreatmentCalculator {
27+
return &FallbackTreatmentCalculatorImp{
2828
fallbackTreatmentConfig: fallbackTreatmentConfig,
2929
}
3030
}
3131

3232
func (f *FallbackTreatmentCalculatorImp) Resolve(flagName string, label *string) FallbackTreatment {
3333
if f.fallbackTreatmentConfig != nil {
34-
if byFlag := f.fallbackTreatmentConfig.byFlagFallbackTreatment; byFlag != nil {
34+
if byFlag := f.fallbackTreatmentConfig.ByFlagFallbackTreatment; byFlag != nil {
3535
if val, ok := byFlag[flagName]; ok {
3636
return FallbackTreatment{
3737
Treatment: val.Treatment,

dtos/fallbacktreatment_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ func TestFallbackTreatmentCalculatorResolve(t *testing.T) {
1313
GlobalFallbackTreatment: &FallbackTreatment{
1414
Treatment: "global_treatment",
1515
},
16-
byFlagFallbackTreatment: map[string]FallbackTreatment{
16+
ByFlagFallbackTreatment: map[string]FallbackTreatment{
1717
"flag1": {
1818
Treatment: "flag1_treatment",
1919
Config: &stringConfig,

engine/evaluator/evaluator.go

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ type Results struct {
3737

3838
// Evaluator struct is the main evaluator
3939
type Evaluator struct {
40-
splitStorage storage.SplitStorageConsumer
41-
eng *engine.Engine
42-
logger logging.LoggerInterface
43-
ruleBuilder grammar.RuleBuilder
40+
splitStorage storage.SplitStorageConsumer
41+
eng *engine.Engine
42+
logger logging.LoggerInterface
43+
ruleBuilder grammar.RuleBuilder
44+
fallbackTratmentCalculator dtos.FallbackTreatmentCalculator
4445
}
4546

4647
// NewEvaluator instantiates an Evaluator struct and returns a reference to it
@@ -53,21 +54,25 @@ func NewEvaluator(
5354
logger logging.LoggerInterface,
5455
featureFlagRules []string,
5556
ruleBasedSegmentRules []string,
57+
fallbackTreatmentCalculator dtos.FallbackTreatmentCalculator,
5658
) *Evaluator {
5759
e := &Evaluator{
58-
splitStorage: splitStorage,
59-
eng: eng,
60-
logger: logger,
60+
splitStorage: splitStorage,
61+
eng: eng,
62+
logger: logger,
63+
fallbackTratmentCalculator: fallbackTreatmentCalculator,
6164
}
6265
e.ruleBuilder = grammar.NewRuleBuilder(segmentStorage, ruleBasedSegmentStorage, largeSegmentStorage, featureFlagRules, ruleBasedSegmentRules, logger, e)
6366
return e
6467
}
6568

6669
func (e *Evaluator) evaluateTreatment(key string, bucketingKey string, featureFlag string, splitDto *dtos.SplitDTO, attributes map[string]interface{}) *Result {
6770
var config *string
71+
label := impressionlabels.SplitNotFound
6872
if splitDto == nil {
69-
e.logger.Warning(fmt.Sprintf("Feature flag %s not found, returning control.", featureFlag))
70-
return &Result{Treatment: Control, Label: impressionlabels.SplitNotFound, Config: config}
73+
fallbackTratment := e.fallbackTratmentCalculator.Resolve(featureFlag, &label)
74+
e.logger.Warning(fmt.Sprintf("Feature flag %s not found, returning fallback treatment.", featureFlag))
75+
return &Result{Treatment: fallbackTratment.Treatment, Label: *fallbackTratment.Label, Config: fallbackTratment.Config}
7176
}
7277

7378
split := grammar.NewSplit(splitDto, e.logger, e.ruleBuilder)
@@ -113,6 +118,15 @@ func (e *Evaluator) evaluateTreatment(key string, bucketingKey string, featureFl
113118
label = impressionlabels.NoConditionMatched
114119
}
115120

121+
if *treatment == Control {
122+
fallbackTreatment := e.fallbackTratmentCalculator.Resolve(featureFlag, &label)
123+
return &Result{
124+
Treatment: fallbackTreatment.Treatment,
125+
Label: *fallbackTreatment.Label,
126+
Config: fallbackTreatment.Config,
127+
}
128+
}
129+
116130
if _, ok := split.Configurations()[*treatment]; ok {
117131
treatmentConfig := split.Configurations()[*treatment]
118132
config = &treatmentConfig

engine/evaluator/evaluator_test.go

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,8 @@ func TestSplitWithoutConfigurations(t *testing.T) {
308308
nil,
309309
logger,
310310
syncProxyFeatureFlagsRules,
311-
syncProxyRuleBasedSegmentRules)
311+
syncProxyRuleBasedSegmentRules,
312+
nil)
312313

313314
key := "test"
314315
result := evaluator.EvaluateFeature(key, &key, "mysplittest", nil)
@@ -333,7 +334,8 @@ func TestSplitWithtConfigurations(t *testing.T) {
333334
nil,
334335
logger,
335336
syncProxyFeatureFlagsRules,
336-
syncProxyRuleBasedSegmentRules)
337+
syncProxyRuleBasedSegmentRules,
338+
nil)
337339

338340
key := "test"
339341
result := evaluator.EvaluateFeature(key, &key, "mysplittest2", nil)
@@ -358,7 +360,8 @@ func TestSplitWithtConfigurationsButKilled(t *testing.T) {
358360
nil,
359361
logger,
360362
syncProxyFeatureFlagsRules,
361-
syncProxyRuleBasedSegmentRules)
363+
syncProxyRuleBasedSegmentRules,
364+
nil)
362365

363366
key := "test"
364367
result := evaluator.EvaluateFeature(key, &key, "mysplittest3", nil)
@@ -383,7 +386,8 @@ func TestSplitWithConfigurationsButKilledWithConfigsOnDefault(t *testing.T) {
383386
nil,
384387
logger,
385388
syncProxyFeatureFlagsRules,
386-
syncProxyRuleBasedSegmentRules)
389+
syncProxyRuleBasedSegmentRules,
390+
nil)
387391

388392
key := "test"
389393
result := evaluator.EvaluateFeature(key, &key, "mysplittest4", nil)
@@ -399,6 +403,14 @@ func TestSplitWithConfigurationsButKilledWithConfigsOnDefault(t *testing.T) {
399403

400404
func TestMultipleEvaluations(t *testing.T) {
401405
logger := logging.NewLogger(nil)
406+
fallbackTreatmentConfig := dtos.FallbackTreatmentConfig{GlobalFallbackTreatment: &dtos.FallbackTreatment{
407+
Treatment: "fallback",
408+
},
409+
ByFlagFallbackTreatment: map[string]dtos.FallbackTreatment{
410+
"flag1": {
411+
Treatment: "on",
412+
},
413+
}}
402414

403415
evaluator := NewEvaluator(
404416
&mockStorage{},
@@ -408,7 +420,8 @@ func TestMultipleEvaluations(t *testing.T) {
408420
nil,
409421
logger,
410422
syncProxyFeatureFlagsRules,
411-
syncProxyRuleBasedSegmentRules)
423+
syncProxyRuleBasedSegmentRules,
424+
dtos.NewFallbackTreatmentCalculatorImp(&fallbackTreatmentConfig))
412425

413426
key := "test"
414427
splits := []string{"mysplittest", "mysplittest2", "mysplittest3", "mysplittest4", "mysplittest5"}
@@ -442,7 +455,7 @@ func TestMultipleEvaluations(t *testing.T) {
442455
t.Error("Unexpected configs")
443456
}
444457

445-
if result.Evaluations["mysplittest5"].Treatment != "control" {
458+
if result.Evaluations["mysplittest5"].Treatment != "fallback" {
446459
t.Error("Wrong treatment result")
447460
}
448461
if result.Evaluations["mysplittest5"].Config != nil {
@@ -467,7 +480,8 @@ func TestNoConditionMatched(t *testing.T) {
467480
nil,
468481
logger,
469482
syncProxyFeatureFlagsRules,
470-
syncProxyRuleBasedSegmentRules)
483+
syncProxyRuleBasedSegmentRules,
484+
nil)
471485

472486
key := "test"
473487
result := evaluator.EvaluateFeature(key, &key, "some", nil)
@@ -508,6 +522,15 @@ func TestEvaluationByFlagSets(t *testing.T) {
508522
},
509523
}
510524

525+
fallbackTreatmentConfig := dtos.FallbackTreatmentConfig{GlobalFallbackTreatment: &dtos.FallbackTreatment{
526+
Treatment: "fallback",
527+
},
528+
ByFlagFallbackTreatment: map[string]dtos.FallbackTreatment{
529+
"mysplittest5": {
530+
Treatment: "on",
531+
},
532+
}}
533+
511534
evaluator := NewEvaluator(
512535
mockedStorage,
513536
nil,
@@ -516,7 +539,8 @@ func TestEvaluationByFlagSets(t *testing.T) {
516539
nil,
517540
logger,
518541
syncProxyFeatureFlagsRules,
519-
syncProxyRuleBasedSegmentRules)
542+
syncProxyRuleBasedSegmentRules,
543+
dtos.NewFallbackTreatmentCalculatorImp(&fallbackTreatmentConfig))
520544
result := evaluator.EvaluateFeatureByFlagSets(key, &key, []string{"set1", "set2", "set3"}, nil)
521545

522546
if result.Evaluations["mysplittest"].Treatment != "off" {
@@ -547,7 +571,7 @@ func TestEvaluationByFlagSets(t *testing.T) {
547571
t.Error("Unexpected configs")
548572
}
549573

550-
if result.Evaluations["mysplittest5"].Treatment != "control" {
574+
if result.Evaluations["mysplittest5"].Treatment != "on" {
551575
t.Error("Wrong treatment result")
552576
}
553577
if result.Evaluations["mysplittest5"].Config != nil {
@@ -652,6 +676,7 @@ func TestPrerequisitesMatching(t *testing.T) {
652676
logging.NewLogger(nil),
653677
syncProxyFeatureFlagsRules,
654678
syncProxyRuleBasedSegmentRules,
679+
nil,
655680
)
656681

657682
// Create split DTO with prerequisites
@@ -747,7 +772,8 @@ func TestEvaluationByFlagSetsASetEmpty(t *testing.T) {
747772
nil,
748773
logger,
749774
syncProxyFeatureFlagsRules,
750-
syncProxyRuleBasedSegmentRules)
775+
syncProxyRuleBasedSegmentRules,
776+
nil)
751777
result := evaluator.EvaluateFeatureByFlagSets(key, &key, []string{"set2"}, nil)
752778

753779
if len(result.Evaluations) != 0 {

engine/grammar/dependency_test/dependency_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ func TestDependencyMatcher(t *testing.T) {
137137
logger,
138138
syncProxyFeatureFlagsRules,
139139
syncProxyRuleBasedSegmentRules,
140+
nil,
140141
)
141142

142143
ruleBuilder := grammar.NewRuleBuilder(nil, nil, nil, syncProxyFeatureFlagsRules, syncProxyRuleBasedSegmentRules, logger, evaluator)

0 commit comments

Comments
 (0)