1 package ldclient
2
3 import (
4 "errors"
5 "fmt"
6 "testing"
7
8 "github.com/launchdarkly/go-sdk-common/v3/ldlogtest"
9 "github.com/launchdarkly/go-sdk-common/v3/ldreason"
10 "github.com/launchdarkly/go-sdk-common/v3/ldvalue"
11 "github.com/launchdarkly/go-server-sdk-evaluation/v2/ldbuilders"
12 "github.com/launchdarkly/go-server-sdk-evaluation/v2/ldmodel"
13 "github.com/launchdarkly/go-server-sdk/v6/internal/bigsegments"
14 "github.com/launchdarkly/go-server-sdk/v6/internal/sharedtest/mocks"
15
16 "github.com/launchdarkly/go-server-sdk/v6/ldcomponents"
17 "github.com/launchdarkly/go-server-sdk/v6/subsystems"
18 "github.com/launchdarkly/go-server-sdk/v6/subsystems/ldstoreimpl"
19 "github.com/launchdarkly/go-server-sdk/v6/testhelpers/ldtestdata"
20
21 "github.com/stretchr/testify/assert"
22 "github.com/stretchr/testify/require"
23 )
24
25 const bigSegmentKey = "segmentkey"
26
27
28
29 func makeBigSegmentRef(segmentKey string, generation int) string {
30 return fmt.Sprintf("%s.g%d", segmentKey, generation)
31 }
32
33 func addBigSegmentAndFlag(testData *ldtestdata.TestDataSource) {
34 segment := ldbuilders.NewSegmentBuilder(bigSegmentKey).
35 Unbounded(true).
36 Generation(1).
37 Build()
38 flag := ldbuilders.NewFlagBuilder(evalFlagKey).On(true).
39 Variations(ldvalue.Bool(false), ldvalue.Bool(true)).
40 FallthroughVariation(0).
41 AddRule(ldbuilders.NewRuleBuilder().Variation(1).Clauses(
42 ldbuilders.Clause("", ldmodel.OperatorSegmentMatch, ldvalue.String(segment.Key)),
43 )).
44 Build()
45 testData.UsePreconfiguredSegment(segment)
46 testData.UsePreconfiguredFlag(flag)
47 }
48
49 func doBigSegmentsTest(
50 t *testing.T,
51 action func(client *LDClient, bsStore *mocks.MockBigSegmentStore),
52 ) {
53 mockLog := ldlogtest.NewMockLog()
54 defer mockLog.DumpIfTestFailed(t)
55 testData := ldtestdata.DataSource()
56 bsStore := &mocks.MockBigSegmentStore{}
57 bsStore.TestSetMetadataToCurrentTime()
58
59 addBigSegmentAndFlag(testData)
60
61 client := makeTestClientWithConfig(func(c *Config) {
62 c.DataSource = testData
63 c.BigSegments = ldcomponents.BigSegments(
64 mocks.SingleComponentConfigurer[subsystems.BigSegmentStore]{Instance: bsStore},
65 )
66 c.Logging = ldcomponents.Logging().Loggers(mockLog.Loggers)
67 })
68 defer client.Close()
69
70 action(client, bsStore)
71 }
72
73 func TestEvalWithBigSegments(t *testing.T) {
74 t.Run("user not found", func(t *testing.T) {
75 doBigSegmentsTest(t, func(client *LDClient, bsStore *mocks.MockBigSegmentStore) {
76 value, detail, err := client.BoolVariationDetail(evalFlagKey, evalTestUser, false)
77 require.NoError(t, err)
78 assert.False(t, value)
79 assert.Equal(t, ldreason.BigSegmentsHealthy, detail.Reason.GetBigSegmentsStatus())
80 })
81 })
82
83 t.Run("user found", func(t *testing.T) {
84 doBigSegmentsTest(t, func(client *LDClient, bsStore *mocks.MockBigSegmentStore) {
85 membership := ldstoreimpl.NewBigSegmentMembershipFromSegmentRefs(
86 []string{makeBigSegmentRef(bigSegmentKey, 1)}, nil)
87 bsStore.TestSetMembership(bigsegments.HashForContextKey(evalTestUser.Key()), membership)
88
89 value, detail, err := client.BoolVariationDetail(evalFlagKey, evalTestUser, false)
90 require.NoError(t, err)
91 assert.True(t, value)
92 assert.Equal(t, ldreason.BigSegmentsHealthy, detail.Reason.GetBigSegmentsStatus())
93 })
94 })
95
96 t.Run("store error", func(t *testing.T) {
97 doBigSegmentsTest(t, func(client *LDClient, bsStore *mocks.MockBigSegmentStore) {
98 bsStore.TestSetMembershipError(errors.New("sorry"))
99
100 value, detail, err := client.BoolVariationDetail(evalFlagKey, evalTestUser, false)
101 require.NoError(t, err)
102 assert.False(t, value)
103 assert.Equal(t, ldreason.BigSegmentsStoreError, detail.Reason.GetBigSegmentsStatus())
104 })
105 })
106
107 t.Run("store not configured", func(t *testing.T) {
108
109 withClientEvalTestParams(func(p clientEvalTestParams) {
110 addBigSegmentAndFlag(p.data)
111
112 value, detail, err := p.client.BoolVariationDetail(evalFlagKey, evalTestUser, false)
113 require.NoError(t, err)
114 assert.False(t, value)
115 assert.Equal(t, ldreason.BigSegmentsNotConfigured, detail.Reason.GetBigSegmentsStatus())
116 })
117 })
118 }
119
View as plain text