11/****************************************************************************
2- * Copyright 2020, Optimizely, Inc. and contributors *
2+ * Copyright 2020-2021 , Optimizely, Inc. and contributors *
33 * *
44 * Licensed under the Apache License, Version 2.0 (the "License"); *
55 * you may not use this file except in compliance with the License. *
@@ -174,15 +174,17 @@ func (s *OptimizelyUserContextTestSuite) TestDecideFeatureTest() {
174174 s .Nil (err )
175175
176176 user := s .OptimizelyClient .CreateUserContext (s .userID , nil )
177- decision := user .Decide (flagKey , nil )
177+ decision := user .Decide (flagKey , []decide. OptimizelyDecideOptions { decide . IncludeReasons } )
178178
179179 s .Equal (variationKey , decision .VariationKey )
180180 s .Equal (true , decision .Enabled )
181181 s .Equal (variablesExpected .ToMap (), decision .Variables .ToMap ())
182182 s .Equal (ruleKey , decision .RuleKey )
183183 s .Equal (flagKey , decision .FlagKey )
184184 s .Equal (user , decision .UserContext )
185- s .Len (decision .Reasons , 0 )
185+ reasons := decision .Reasons
186+ s .Len (reasons , 1 )
187+ s .Equal (`Audiences for experiment exp_no_audience collectively evaluated to true.` , reasons [0 ])
186188
187189 s .True (len (s .eventProcessor .Events ) == 1 )
188190 s .Equal (s .userID , s .eventProcessor .Events [0 ].VisitorID )
@@ -205,15 +207,32 @@ func (s *OptimizelyUserContextTestSuite) TestDecideRollout() {
205207 s .Nil (err )
206208
207209 user := s .OptimizelyClient .CreateUserContext (s .userID , nil )
208- decision := user .Decide (flagKey , nil )
210+ decision := user .Decide (flagKey , []decide. OptimizelyDecideOptions { decide . IncludeReasons } )
209211
210212 s .Equal (variationKey , decision .VariationKey )
211213 s .Equal (true , decision .Enabled )
212214 s .Equal (variablesExpected .ToMap (), decision .Variables .ToMap ())
213215 s .Equal (ruleKey , decision .RuleKey )
214216 s .Equal (flagKey , decision .FlagKey )
215217 s .Equal (user , decision .UserContext )
216- s .Len (decision .Reasons , 3 )
218+ reasons := decision .Reasons
219+ s .Len (reasons , 9 )
220+
221+ expectedLogs := []string {
222+ `an error occurred while evaluating nested tree for audience ID "13389141123"` ,
223+ `Audiences for experiment exp_with_audience collectively evaluated to false.` ,
224+ `User "tester" does not meet conditions to be in experiment "exp_with_audience".` ,
225+ `an error occurred while evaluating nested tree for audience ID "13389130056"` ,
226+ `User "tester" does not meet conditions for targeting rule 1.` ,
227+ `an error occurred while evaluating nested tree for audience ID "12208130097"` ,
228+ `User "tester" does not meet conditions for targeting rule 2.` ,
229+ `Audiences for experiment 18322080788 collectively evaluated to true.` ,
230+ `User "tester" meets conditions for targeting rule "Everyone Else".` ,
231+ }
232+
233+ for index , log := range expectedLogs {
234+ s .Equal (log , reasons [index ])
235+ }
217236
218237 s .True (len (s .eventProcessor .Events ) == 1 )
219238 s .Equal (s .userID , s .eventProcessor .Events [0 ].VisitorID )
@@ -233,15 +252,17 @@ func (s *OptimizelyUserContextTestSuite) TestDecideNullVariation() {
233252 variablesExpected := optimizelyjson .NewOptimizelyJSONfromMap (map [string ]interface {}{})
234253
235254 user := s .OptimizelyClient .CreateUserContext (s .userID , nil )
236- decision := user .Decide (flagKey , nil )
255+ decision := user .Decide (flagKey , []decide. OptimizelyDecideOptions { decide . IncludeReasons } )
237256
238257 s .Equal ("" , decision .VariationKey )
239258 s .Equal (false , decision .Enabled )
240259 s .Equal (variablesExpected .ToMap (), decision .Variables .ToMap ())
241260 s .Equal ("" , decision .RuleKey )
242261 s .Equal ("feature_3" , decision .FlagKey )
243262 s .Equal (user , decision .UserContext )
244- s .Len (decision .Reasons , 0 )
263+ reasons := decision .Reasons
264+ s .Len (reasons , 1 )
265+ s .Equal (`Rollout with ID "" is not in the datafile.` , reasons [0 ])
245266
246267 s .True (len (s .eventProcessor .Events ) == 1 )
247268 s .Equal (s .userID , s .eventProcessor .Events [0 ].VisitorID )
@@ -265,17 +286,21 @@ func (s *OptimizelyUserContextTestSuite) TestDecideForKeysOneFlag() {
265286 s .Nil (err )
266287
267288 user := s .OptimizelyClient .CreateUserContext (s .userID , nil )
268- decisions := user .DecideForKeys (flagKeys , nil )
289+ decisions := user .DecideForKeys (flagKeys , []decide. OptimizelyDecideOptions { decide . IncludeReasons } )
269290 s .Len (decisions , 1 )
270291
271292 decision1 := decisions [flagKey ]
293+
272294 s .Equal (variationKey , decision1 .VariationKey )
273295 s .Equal (true , decision1 .Enabled )
274296 s .Equal (variablesExpected .ToMap (), decision1 .Variables .ToMap ())
275297 s .Equal (ruleKey , decision1 .RuleKey )
276298 s .Equal (flagKey , decision1 .FlagKey )
277299 s .Equal (user , decision1 .UserContext )
278- s .Len (decision1 .Reasons , 0 )
300+
301+ reasons := decision1 .Reasons
302+ s .Len (reasons , 1 )
303+ s .Equal (`Audiences for experiment exp_no_audience collectively evaluated to true.` , reasons [0 ])
279304
280305 s .True (len (s .eventProcessor .Events ) == 1 )
281306 s .Equal (s .userID , s .eventProcessor .Events [0 ].VisitorID )
@@ -304,7 +329,7 @@ func (s *OptimizelyUserContextTestSuite) TestDecideForKeysWithMultipleFlags() {
304329 s .Nil (err )
305330
306331 user := s .OptimizelyClient .CreateUserContext (s .userID , map [string ]interface {}{"gender" : "f" })
307- decisions := user .DecideForKeys (flagKeys , nil )
332+ decisions := user .DecideForKeys (flagKeys , []decide. OptimizelyDecideOptions { decide . IncludeReasons } )
308333 s .Len (decisions , 2 )
309334
310335 decision1 := decisions [flagKey1 ]
@@ -314,7 +339,9 @@ func (s *OptimizelyUserContextTestSuite) TestDecideForKeysWithMultipleFlags() {
314339 s .Equal (ruleKey1 , decision1 .RuleKey )
315340 s .Equal (flagKey1 , decision1 .FlagKey )
316341 s .Equal (user , decision1 .UserContext )
317- s .Len (decision1 .Reasons , 0 )
342+ reasons := decision1 .Reasons
343+ s .Len (reasons , 1 )
344+ s .Equal (`Audiences for experiment exp_with_audience collectively evaluated to true.` , reasons [0 ])
318345
319346 decision2 := decisions [flagKey2 ]
320347 s .Equal (variationKey2 , decision2 .VariationKey )
@@ -323,7 +350,9 @@ func (s *OptimizelyUserContextTestSuite) TestDecideForKeysWithMultipleFlags() {
323350 s .Equal (ruleKey2 , decision2 .RuleKey )
324351 s .Equal (flagKey2 , decision2 .FlagKey )
325352 s .Equal (user , decision2 .UserContext )
326- s .Len (decision2 .Reasons , 0 )
353+ reasons = decision2 .Reasons
354+ s .Len (reasons , 1 )
355+ s .Equal (`Audiences for experiment exp_no_audience collectively evaluated to true.` , reasons [0 ])
327356
328357 s .True (len (s .eventProcessor .Events ) == 2 )
329358 s .Equal (s .userID , s .eventProcessor .Events [0 ].VisitorID )
@@ -454,7 +483,7 @@ func (s *OptimizelyUserContextTestSuite) TestDecideAllEnabledFlagsOnly() {
454483 s .Nil (err )
455484
456485 user := s .OptimizelyClient .CreateUserContext (s .userID , map [string ]interface {}{"gender" : "f" })
457- decisions := user .DecideAll ([]decide.OptimizelyDecideOptions {decide .EnabledFlagsOnly })
486+ decisions := user .DecideAll ([]decide.OptimizelyDecideOptions {decide .EnabledFlagsOnly , decide . IncludeReasons })
458487 s .Len (decisions , 2 )
459488
460489 decision1 := decisions [flagKey1 ]
@@ -464,7 +493,9 @@ func (s *OptimizelyUserContextTestSuite) TestDecideAllEnabledFlagsOnly() {
464493 s .Equal ("exp_with_audience" , decision1 .RuleKey )
465494 s .Equal (flagKey1 , decision1 .FlagKey )
466495 s .Equal (user , decision1 .UserContext )
467- s .Len (decision1 .Reasons , 0 )
496+ reasons := decision1 .Reasons
497+ s .Len (reasons , 1 )
498+ s .Equal (`Audiences for experiment exp_with_audience collectively evaluated to true.` , reasons [0 ])
468499}
469500
470501func (s * OptimizelyUserContextTestSuite ) TestTrackEvent () {
@@ -580,6 +611,7 @@ func (s *OptimizelyUserContextTestSuite) TestDecideOptionsBypassUps() {
580611 variationID2 := "10418510624"
581612 variationKey1 := "variation_with_traffic"
582613 variationKey2 := "variation_no_traffic"
614+ options := []decide.OptimizelyDecideOptions {decide .IncludeReasons }
583615
584616 userProfileService := new (MockUserProfileService )
585617 s .OptimizelyClient , _ = s .factory .Client (
@@ -596,13 +628,20 @@ func (s *OptimizelyUserContextTestSuite) TestDecideOptionsBypassUps() {
596628 userProfileService .On ("Save" , mock .Anything )
597629
598630 userContext := s .OptimizelyClient .CreateUserContext (s .userID , map [string ]interface {}{})
599- decision := userContext .Decide (flagKey , nil )
631+ decision := userContext .Decide (flagKey , options )
632+ reasons := decision .Reasons
633+ s .Len (reasons , 1 )
634+ s .Equal (`User "tester" was previously bucketed into variation "variation_no_traffic" of experiment "exp_no_audience".` , reasons [0 ])
600635 // should return variationId2 set by UPS
601636 s .Equal (variationKey2 , decision .VariationKey )
602637 userProfileService .AssertCalled (s .T (), "Lookup" , s .userID )
603638 userProfileService .AssertNotCalled (s .T (), "Save" , mock .Anything )
604639
605- decision = userContext .Decide (flagKey , []decide.OptimizelyDecideOptions {decide .IgnoreUserProfileService })
640+ options = append (options , decide .IgnoreUserProfileService )
641+ decision = userContext .Decide (flagKey , options )
642+ reasons = decision .Reasons
643+ s .Len (reasons , 1 )
644+ s .Equal (`Audiences for experiment exp_no_audience collectively evaluated to true.` , reasons [0 ])
606645 // should not lookup, ignore variationId2 set by UPS and return variationId1
607646 s .Equal (variationKey1 , decision .VariationKey )
608647 userProfileService .AssertNumberOfCalls (s .T (), "Lookup" , 1 )
@@ -641,8 +680,25 @@ func (s *OptimizelyUserContextTestSuite) TestDecideOptionsIncludeReasons() {
641680
642681 // valid flag key
643682 flagKey = "feature_1"
644- decision = user .Decide (flagKey , nil )
645- s .Len (decision .Reasons , 3 )
683+ decision = user .Decide (flagKey , options )
684+ reasons := decision .Reasons
685+ s .Len (reasons , 9 )
686+
687+ expectedLogs := []string {
688+ `an error occurred while evaluating nested tree for audience ID "13389141123"` ,
689+ `Audiences for experiment exp_with_audience collectively evaluated to false.` ,
690+ `User "tester" does not meet conditions to be in experiment "exp_with_audience".` ,
691+ `an error occurred while evaluating nested tree for audience ID "13389130056"` ,
692+ `User "tester" does not meet conditions for targeting rule 1.` ,
693+ `an error occurred while evaluating nested tree for audience ID "12208130097"` ,
694+ `User "tester" does not meet conditions for targeting rule 2.` ,
695+ `Audiences for experiment 18322080788 collectively evaluated to true.` ,
696+ `User "tester" meets conditions for targeting rule "Everyone Else".` ,
697+ }
698+
699+ for index , log := range expectedLogs {
700+ s .Equal (log , reasons [index ])
701+ }
646702}
647703
648704func (s * OptimizelyUserContextTestSuite ) TestDefaultDecideOptionsExcludeVariables () {
@@ -654,14 +710,38 @@ func (s *OptimizelyUserContextTestSuite) TestDefaultDecideOptionsExcludeVariable
654710 // should be excluded by DefaultDecideOption
655711 decision := userContext .Decide (flagKey , nil )
656712 s .Len (decision .Variables .ToMap (), 0 )
713+ reasons := decision .Reasons
714+ s .Len (reasons , 0 )
715+
716+ options = append (options , decide .IncludeReasons )
717+ client , _ = s .factory .Client (WithEventProcessor (s .eventProcessor ), WithDefaultDecideOptions (options ))
718+ userContext = client .CreateUserContext (s .userID , nil )
719+
720+ decision = userContext .Decide (flagKey , nil )
721+ reasons = decision .Reasons
722+ s .Len (reasons , 9 )
723+
724+ expectedLogs := []string {
725+ `an error occurred while evaluating nested tree for audience ID "13389141123"` ,
726+ `Audiences for experiment exp_with_audience collectively evaluated to false.` ,
727+ `User "tester" does not meet conditions to be in experiment "exp_with_audience".` ,
728+ `an error occurred while evaluating nested tree for audience ID "13389130056"` ,
729+ `User "tester" does not meet conditions for targeting rule 1.` ,
730+ `an error occurred while evaluating nested tree for audience ID "12208130097"` ,
731+ `User "tester" does not meet conditions for targeting rule 2.` ,
732+ `Audiences for experiment 18322080788 collectively evaluated to true.` ,
733+ `User "tester" meets conditions for targeting rule "Everyone Else".` ,
734+ }
657735
658- // @TODO: Need one more case: IncludeReasons = true and flagKey = "feature_1". Then reasons.count > 0
736+ for index , log := range expectedLogs {
737+ s .Equal (log , reasons [index ])
738+ }
659739}
660740
661741func (s * OptimizelyUserContextTestSuite ) TestDefaultDecideOptionsEnabledFlagsOnly () {
662742 flagKey := "feature_1"
663743 variablesExpected , _ := s .OptimizelyClient .GetAllFeatureVariables (flagKey , entities.UserContext {ID : s .userID })
664- options := []decide.OptimizelyDecideOptions {decide .EnabledFlagsOnly }
744+ options := []decide.OptimizelyDecideOptions {decide .EnabledFlagsOnly , decide . IncludeReasons }
665745 client , _ := s .factory .Client (WithEventProcessor (s .eventProcessor ), WithDefaultDecideOptions (options ))
666746 user := client .CreateUserContext (s .userID , map [string ]interface {}{"gender" : "f" })
667747
@@ -676,7 +756,9 @@ func (s *OptimizelyUserContextTestSuite) TestDefaultDecideOptionsEnabledFlagsOnl
676756 s .Equal ("exp_with_audience" , decision1 .RuleKey )
677757 s .Equal (flagKey , decision1 .FlagKey )
678758 s .Equal (user , decision1 .UserContext )
679- s .Len (decision1 .Reasons , 0 )
759+ reasons := decision1 .Reasons
760+ s .Len (reasons , 1 )
761+ s .Equal ("Audiences for experiment exp_with_audience collectively evaluated to true." , reasons [0 ])
680762}
681763
682764func (s * OptimizelyUserContextTestSuite ) TestDefaultDecideOptionsIncludeReasons () {
@@ -714,7 +796,8 @@ func (s *OptimizelyUserContextTestSuite) TestDefaultDecideOptionsBypassUps() {
714796 options := []decide.OptimizelyDecideOptions {decide .IgnoreUserProfileService }
715797 client , _ := s .factory .Client (WithEventProcessor (s .eventProcessor ), WithDefaultDecideOptions (options ))
716798 user := client .CreateUserContext (s .userID , nil )
717- decision := user .Decide (flagKey , nil )
799+ decision := user .Decide (flagKey , []decide.OptimizelyDecideOptions {decide .IncludeReasons })
800+ s .Len (decision .Reasons , 1 )
718801
719802 // should get IgnoreUserProfileService by DefaultDecideOption
720803 // should not lookup, ignore variationId2 set by UPS and return variationId1
@@ -763,7 +846,7 @@ func (s *OptimizelyUserContextTestSuite) TestDecideSDKNotReady() {
763846func (s * OptimizelyUserContextTestSuite ) TestDecideInvalidFeatureKey () {
764847 flagKey := "invalid_key"
765848 userContext := s .OptimizelyClient .CreateUserContext (s .userID , nil )
766- decision := userContext .Decide (flagKey , nil )
849+ decision := userContext .Decide (flagKey , []decide. OptimizelyDecideOptions { decide . IncludeReasons } )
767850
768851 s .Equal ("" , decision .VariationKey )
769852 s .False (decision .Enabled )
@@ -779,7 +862,7 @@ func (s *OptimizelyUserContextTestSuite) TestDecideForKeySDKNotReady() {
779862 factory := OptimizelyFactory {SDKKey : "121" }
780863 client , _ := factory .Client ()
781864 userContext := client .CreateUserContext (s .userID , nil )
782- decisions := userContext .DecideForKeys (flagKeys , nil )
865+ decisions := userContext .DecideForKeys (flagKeys , []decide. OptimizelyDecideOptions { decide . IncludeReasons } )
783866
784867 s .Len (decisions , 0 )
785868}
@@ -801,7 +884,7 @@ func (s *OptimizelyUserContextTestSuite) TestDecideForKeysErrorDecisionIncluded(
801884 s .Nil (err )
802885
803886 user := s .OptimizelyClient .CreateUserContext (s .userID , nil )
804- decisions := user .DecideForKeys (flagKeys , nil )
887+ decisions := user .DecideForKeys (flagKeys , []decide. OptimizelyDecideOptions { decide . IncludeReasons } )
805888 s .Len (decisions , 2 )
806889
807890 decision := decisions [flagKey1 ]
@@ -811,13 +894,16 @@ func (s *OptimizelyUserContextTestSuite) TestDecideForKeysErrorDecisionIncluded(
811894 s .Equal ("exp_no_audience" , decision .RuleKey )
812895 s .Equal (flagKey1 , decision .FlagKey )
813896 s .Equal (user , decision .UserContext )
814- s .Len (decision .Reasons , 0 )
897+ reasons := decision .Reasons
898+ s .Len (reasons , 1 )
899+ s .Equal (`Audiences for experiment exp_no_audience collectively evaluated to true.` , reasons [0 ])
815900
816901 decision = decisions [flagKey2 ]
817902 s .Equal (flagKey2 , decision .FlagKey )
818903 s .Equal (user , decision .UserContext )
819- s .Len (decision .Reasons , 1 )
820- s .Equal (decide .GetDecideMessage (decide .FlagKeyInvalid , flagKey2 ), decision .Reasons [0 ])
904+ reasons = decision .Reasons
905+ s .Len (reasons , 1 )
906+ s .Equal (decide .GetDecideMessage (decide .FlagKeyInvalid , flagKey2 ), reasons [0 ])
821907}
822908
823909func TestOptimizelyUserContextTestSuite (t * testing.T ) {
0 commit comments