...

Source file src/github.com/launchdarkly/go-server-sdk/v6/testhelpers/ldtestdata/test_data_source_flag_test.go

Documentation: github.com/launchdarkly/go-server-sdk/v6/testhelpers/ldtestdata

     1  package ldtestdata
     2  
     3  import (
     4  	"encoding/json"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/launchdarkly/go-sdk-common/v3/ldcontext"
     9  	"github.com/launchdarkly/go-sdk-common/v3/ldvalue"
    10  	"github.com/launchdarkly/go-server-sdk-evaluation/v2/ldbuilders"
    11  	"github.com/launchdarkly/go-server-sdk-evaluation/v2/ldmodel"
    12  	"github.com/launchdarkly/go-server-sdk/v6/subsystems"
    13  	"github.com/launchdarkly/go-server-sdk/v6/subsystems/ldstoreimpl"
    14  
    15  	m "github.com/launchdarkly/go-test-helpers/v3/matchers"
    16  )
    17  
    18  const (
    19  	trueVar  = 0
    20  	falseVar = 1
    21  )
    22  
    23  func verifyFlag(t *testing.T, configureFlag func(*FlagBuilder), expectedFlag *ldbuilders.FlagBuilder) {
    24  	t.Helper()
    25  	expectedJSON, _ := json.Marshal(expectedFlag.Build())
    26  	testDataSourceTest(t, func(p testDataSourceTestParams) {
    27  		t.Helper()
    28  		p.withDataSource(t, func(subsystems.DataSource) {
    29  			t.Helper()
    30  			f := p.td.Flag("flagkey")
    31  			configureFlag(f)
    32  			p.td.Update(f)
    33  			up := p.updates.DataStore.WaitForUpsert(t, ldstoreimpl.Features(), "flagkey", 1, time.Millisecond)
    34  			upJSON := ldstoreimpl.Features().Serialize(up.Item)
    35  			m.In(t).Assert(string(upJSON), m.JSONStrEqual(string(expectedJSON)))
    36  		})
    37  	})
    38  }
    39  
    40  func basicBool() *ldbuilders.FlagBuilder {
    41  	return ldbuilders.NewFlagBuilder("flagkey").Version(1).Variations(ldvalue.Bool(true), ldvalue.Bool(false)).
    42  		OffVariation(1)
    43  }
    44  
    45  func TestFlagConfig(t *testing.T) {
    46  	basicString := func() *ldbuilders.FlagBuilder {
    47  		return ldbuilders.NewFlagBuilder("flagkey").Version(1).On(true).Variations(threeStringValues...)
    48  	}
    49  
    50  	t.Run("simple boolean flag", func(t *testing.T) {
    51  		verifyFlag(t, func(f *FlagBuilder) {}, basicBool().On(true).FallthroughVariation(trueVar))
    52  		verifyFlag(t, func(f *FlagBuilder) { f.BooleanFlag() }, basicBool().On(true).FallthroughVariation(trueVar))
    53  		verifyFlag(t, func(f *FlagBuilder) { f.On(true) }, basicBool().On(true).FallthroughVariation(trueVar))
    54  		verifyFlag(t, func(f *FlagBuilder) { f.On(false) }, basicBool().On(false).FallthroughVariation(trueVar))
    55  		verifyFlag(t, func(f *FlagBuilder) { f.VariationForAll(false) }, basicBool().On(true).FallthroughVariation(falseVar))
    56  		verifyFlag(t, func(f *FlagBuilder) { f.VariationForAll(true) }, basicBool().On(true).FallthroughVariation(trueVar))
    57  
    58  		verifyFlag(t, func(f *FlagBuilder) {
    59  			f.FallthroughVariation(true).OffVariation(false)
    60  		}, basicBool().On(true).FallthroughVariation(trueVar).OffVariation(falseVar))
    61  
    62  		verifyFlag(t, func(f *FlagBuilder) {
    63  			f.FallthroughVariation(false).OffVariation(true)
    64  		}, basicBool().On(true).FallthroughVariation(falseVar).OffVariation(trueVar))
    65  	})
    66  
    67  	t.Run("using boolean config methods forces flag to be boolean", func(t *testing.T) {
    68  		verifyFlag(t, func(f *FlagBuilder) {
    69  			f.Variations(ldvalue.Int(1), ldvalue.Int(2))
    70  			f.BooleanFlag()
    71  		}, basicBool().On(true).FallthroughVariation(trueVar))
    72  
    73  		verifyFlag(t, func(f *FlagBuilder) {
    74  			f.Variations(ldvalue.Bool(true), ldvalue.Int(2))
    75  			f.BooleanFlag()
    76  		}, basicBool().On(true).FallthroughVariation(trueVar))
    77  
    78  		verifyFlag(t, func(f *FlagBuilder) {
    79  			f.ValueForAll(ldvalue.String("x"))
    80  			f.BooleanFlag()
    81  		}, basicBool().On(true).FallthroughVariation(trueVar))
    82  	})
    83  
    84  	t.Run("flag with string variations", func(t *testing.T) {
    85  		verifyFlag(t, func(f *FlagBuilder) {
    86  			f.Variations(threeStringValues...).OffVariationIndex(0).FallthroughVariationIndex(2)
    87  		}, basicString().OffVariation(0).FallthroughVariation(2))
    88  
    89  		verifyFlag(t, func(f *FlagBuilder) {
    90  			f.Variations(threeStringValues...).VariationForAllIndex(1)
    91  		}, basicString().OffVariation(1).FallthroughVariation(1))
    92  	})
    93  }
    94  
    95  func TestFlagTargets(t *testing.T) {
    96  	basicString := func() *ldbuilders.FlagBuilder {
    97  		return ldbuilders.NewFlagBuilder("flagkey").Version(1).On(true).Variations(threeStringValues...)
    98  	}
    99  
   100  	t.Run("user targets", func(t *testing.T) {
   101  		verifyFlag(t,
   102  			func(f *FlagBuilder) {
   103  				f.VariationForUser("a", true).VariationForUser("b", true)
   104  			},
   105  			basicBool().On(true).FallthroughVariation(trueVar).
   106  				AddTarget(0, "a", "b").AddContextTarget(ldcontext.DefaultKind, 0))
   107  
   108  		verifyFlag(t,
   109  			func(f *FlagBuilder) {
   110  				f.VariationForUser("a", true).VariationForUser("a", true)
   111  			},
   112  			basicBool().On(true).FallthroughVariation(trueVar).
   113  				AddTarget(0, "a").AddContextTarget(ldcontext.DefaultKind, 0))
   114  
   115  		verifyFlag(t,
   116  			func(f *FlagBuilder) {
   117  				f.VariationForUser("a", false).VariationForUser("b", true).VariationForUser("c", false)
   118  			},
   119  			basicBool().On(true).FallthroughVariation(trueVar).
   120  				AddTarget(0, "b").AddContextTarget(ldcontext.DefaultKind, 0).
   121  				AddTarget(1, "a", "c").AddContextTarget(ldcontext.DefaultKind, 1))
   122  
   123  		verifyFlag(t,
   124  			func(f *FlagBuilder) {
   125  				f.VariationForUser("a", true).VariationForUser("b", true).VariationForUser("a", false)
   126  			},
   127  			basicBool().On(true).FallthroughVariation(trueVar).
   128  				AddTarget(0, "b").AddContextTarget(ldcontext.DefaultKind, 0).
   129  				AddTarget(1, "a").AddContextTarget(ldcontext.DefaultKind, 1))
   130  
   131  		verifyFlag(t,
   132  			func(f *FlagBuilder) {
   133  				f.Variations(threeStringValues...).OffVariationIndex(0).FallthroughVariationIndex(2).
   134  					VariationIndexForUser("a", 2).VariationIndexForUser("b", 2)
   135  			},
   136  			basicString().On(true).OffVariation(0).FallthroughVariation(2).
   137  				AddTarget(2, "a", "b").AddContextTarget(ldcontext.DefaultKind, 2))
   138  
   139  		verifyFlag(t,
   140  			func(f *FlagBuilder) {
   141  				f.Variations(threeStringValues...).OffVariationIndex(0).FallthroughVariationIndex(2).
   142  					VariationIndexForUser("a", 2).VariationIndexForUser("b", 1).VariationIndexForUser("c", 2)
   143  			},
   144  			basicString().On(true).OffVariation(0).FallthroughVariation(2).
   145  				AddTarget(1, "b").AddContextTarget(ldcontext.DefaultKind, 1).
   146  				AddTarget(2, "a", "c").AddContextTarget(ldcontext.DefaultKind, 2))
   147  	})
   148  
   149  	t.Run("context targets", func(t *testing.T) {
   150  		verifyFlag(t,
   151  			func(f *FlagBuilder) {
   152  				f.VariationForKey("org", "a", true).VariationForKey("org", "b", true)
   153  			},
   154  			basicBool().On(true).FallthroughVariation(trueVar).
   155  				AddContextTarget("org", 0, "a", "b"))
   156  
   157  		verifyFlag(t,
   158  			func(f *FlagBuilder) {
   159  				f.VariationForKey("org", "a", true).VariationForKey("other", "a", true)
   160  			},
   161  			basicBool().On(true).FallthroughVariation(trueVar).
   162  				AddContextTarget("org", 0, "a").
   163  				AddContextTarget("other", 0, "a"))
   164  
   165  		verifyFlag(t,
   166  			func(f *FlagBuilder) {
   167  				f.VariationForKey("org", "a", true).VariationForKey("org", "a", true)
   168  			},
   169  			basicBool().On(true).FallthroughVariation(trueVar).
   170  				AddContextTarget("org", 0, "a"))
   171  
   172  		verifyFlag(t,
   173  			func(f *FlagBuilder) {
   174  				f.Variations(threeStringValues...).OffVariationIndex(0).FallthroughVariationIndex(2).
   175  					VariationIndexForKey("org", "a", 2).VariationIndexForKey("org", "b", 2)
   176  			},
   177  			basicString().On(true).OffVariation(0).FallthroughVariation(2).
   178  				AddContextTarget("org", 2, "a", "b"))
   179  
   180  		verifyFlag(t,
   181  			func(f *FlagBuilder) {
   182  				f.VariationForKey("", "a", true).VariationForKey("", "b", true)
   183  			},
   184  			basicBool().On(true).FallthroughVariation(trueVar).
   185  				AddTarget(0, "a", "b").AddContextTarget("user", 0))
   186  	})
   187  }
   188  
   189  func TestRuleConfig(t *testing.T) {
   190  	t.Run("simple match returning variation 0/true", func(t *testing.T) {
   191  		matchReturnsVariation0 := basicBool().On(true).FallthroughVariation(0).AddRule(
   192  			ldbuilders.NewRuleBuilder().ID("rule0").Variation(trueVar).Clauses(
   193  				ldbuilders.ClauseWithKind("user", "name", ldmodel.OperatorIn, ldvalue.String("Lucy")),
   194  			),
   195  		)
   196  
   197  		verifyFlag(t, func(f *FlagBuilder) {
   198  			f.IfMatch("name", ldvalue.String("Lucy")).ThenReturn(true)
   199  		}, matchReturnsVariation0)
   200  
   201  		verifyFlag(t, func(f *FlagBuilder) {
   202  			f.IfMatch("name", ldvalue.String("Lucy")).ThenReturnIndex(0)
   203  		}, matchReturnsVariation0)
   204  	})
   205  
   206  	t.Run("simple match returning variation 1/false", func(t *testing.T) {
   207  		matchReturnsVariation1 := basicBool().On(true).FallthroughVariation(0).AddRule(
   208  			ldbuilders.NewRuleBuilder().ID("rule0").Variation(falseVar).Clauses(
   209  				ldbuilders.ClauseWithKind("user", "name", ldmodel.OperatorIn, ldvalue.String("Lucy")),
   210  			),
   211  		)
   212  
   213  		verifyFlag(t, func(f *FlagBuilder) {
   214  			f.IfMatch("name", ldvalue.String("Lucy")).ThenReturn(false)
   215  		}, matchReturnsVariation1)
   216  
   217  		verifyFlag(t, func(f *FlagBuilder) {
   218  			f.IfMatch("name", ldvalue.String("Lucy")).ThenReturnIndex(1)
   219  		}, matchReturnsVariation1)
   220  	})
   221  
   222  	t.Run("negated match", func(t *testing.T) {
   223  		verifyFlag(t, func(f *FlagBuilder) {
   224  			f.IfNotMatch("name", ldvalue.String("Lucy")).ThenReturn(true)
   225  		}, basicBool().On(true).FallthroughVariation(0).AddRule(
   226  			ldbuilders.NewRuleBuilder().ID("rule0").Variation(trueVar).Clauses(
   227  				ldbuilders.Negate(ldbuilders.ClauseWithKind("user", "name", ldmodel.OperatorIn, ldvalue.String("Lucy"))),
   228  			),
   229  		))
   230  	})
   231  
   232  	t.Run("multiple clauses", func(t *testing.T) {
   233  		verifyFlag(t, func(f *FlagBuilder) {
   234  			f.IfMatch("name", ldvalue.String("Lucy")).
   235  				AndMatch("country", ldvalue.String("gb")).
   236  				ThenReturn(true)
   237  		}, basicBool().On(true).FallthroughVariation(0).AddRule(
   238  			ldbuilders.NewRuleBuilder().ID("rule0").Variation(trueVar).Clauses(
   239  				ldbuilders.ClauseWithKind("user", "name", ldmodel.OperatorIn, ldvalue.String("Lucy")),
   240  				ldbuilders.ClauseWithKind("user", "country", ldmodel.OperatorIn, ldvalue.String("gb")),
   241  			),
   242  		))
   243  	})
   244  
   245  	t.Run("multiple rules", func(t *testing.T) {
   246  		verifyFlag(t, func(f *FlagBuilder) {
   247  			f.IfMatch("name", ldvalue.String("Lucy")).ThenReturn(true).
   248  				IfMatch("name", ldvalue.String("Mina")).ThenReturn(true)
   249  		}, basicBool().On(true).FallthroughVariation(0).AddRule(
   250  			ldbuilders.NewRuleBuilder().ID("rule0").Variation(trueVar).Clauses(
   251  				ldbuilders.ClauseWithKind("user", "name", ldmodel.OperatorIn, ldvalue.String("Lucy")),
   252  			),
   253  		).AddRule(
   254  			ldbuilders.NewRuleBuilder().ID("rule1").Variation(trueVar).Clauses(
   255  				ldbuilders.ClauseWithKind("user", "name", ldmodel.OperatorIn, ldvalue.String("Mina")),
   256  			),
   257  		))
   258  	})
   259  
   260  	t.Run("simple match with context kind", func(t *testing.T) {
   261  		matchReturnsVariation0 := basicBool().On(true).FallthroughVariation(0).AddRule(
   262  			ldbuilders.NewRuleBuilder().ID("rule0").Variation(trueVar).Clauses(
   263  				ldbuilders.ClauseWithKind("org", "name", ldmodel.OperatorIn, ldvalue.String("Catco")),
   264  			),
   265  		)
   266  
   267  		verifyFlag(t, func(f *FlagBuilder) {
   268  			f.IfMatchContext("org", "name", ldvalue.String("Catco")).ThenReturn(true)
   269  		}, matchReturnsVariation0)
   270  
   271  		verifyFlag(t, func(f *FlagBuilder) {
   272  			f.IfMatchContext("org", "name", ldvalue.String("Catco")).ThenReturnIndex(0)
   273  		}, matchReturnsVariation0)
   274  	})
   275  
   276  	t.Run("negated match with context kind", func(t *testing.T) {
   277  		verifyFlag(t, func(f *FlagBuilder) {
   278  			f.IfNotMatchContext("org", "name", ldvalue.String("Catco")).ThenReturn(true)
   279  		}, basicBool().On(true).FallthroughVariation(0).AddRule(
   280  			ldbuilders.NewRuleBuilder().ID("rule0").Variation(trueVar).Clauses(
   281  				ldbuilders.Negate(ldbuilders.ClauseWithKind("org", "name", ldmodel.OperatorIn, ldvalue.String("Catco"))),
   282  			),
   283  		))
   284  	})
   285  }
   286  

View as plain text