1 package ldclient
2
3 import (
4 "errors"
5 "net/http"
6 "os"
7 "testing"
8 "time"
9
10 "github.com/launchdarkly/go-sdk-common/v3/ldvalue"
11 "github.com/launchdarkly/go-server-sdk/v6/interfaces"
12 "github.com/launchdarkly/go-server-sdk/v6/ldcomponents"
13 "github.com/launchdarkly/go-server-sdk/v6/subsystems"
14
15 "github.com/stretchr/testify/assert"
16 )
17
18 var testStartWaitMillis = time.Second * 10
19
20 func expectedDiagnosticConfigForDefaultConfig() *ldvalue.ObjectBuilder {
21 return ldvalue.ObjectBuild().
22 Set("customEventsURI", ldvalue.Bool(false)).
23 Set("dataStoreType", ldvalue.String("memory")).
24 Set("eventsCapacity", ldvalue.Int(ldcomponents.DefaultEventsCapacity)).
25 Set("connectTimeoutMillis", durationToMillis(ldcomponents.DefaultConnectTimeout)).
26 Set("socketTimeoutMillis", durationToMillis(ldcomponents.DefaultConnectTimeout)).
27 Set("eventsFlushIntervalMillis", durationToMillis(ldcomponents.DefaultFlushInterval)).
28 Set("startWaitMillis", durationToMillis(testStartWaitMillis)).
29 Set("usingRelayDaemon", ldvalue.Bool(false)).
30 Set("allAttributesPrivate", ldvalue.Bool(false)).
31 Set("userKeysCapacity", ldvalue.Int(ldcomponents.DefaultContextKeysCapacity)).
32 Set("userKeysFlushIntervalMillis", durationToMillis(ldcomponents.DefaultContextKeysFlushInterval)).
33 Set("usingProxy", ldvalue.Bool(false)).
34 Set("diagnosticRecordingIntervalMillis", durationToMillis(ldcomponents.DefaultDiagnosticRecordingInterval))
35 }
36
37 func TestDiagnosticEventCustomConfig(t *testing.T) {
38 timeMillis := func(t time.Duration) ldvalue.Value { return ldvalue.Int(int(t / time.Millisecond)) }
39 doTestWithoutStreamingDefaults := func(setConfig func(*Config), setExpected func(*ldvalue.ObjectBuilder)) {
40 config := Config{}
41 setConfig(&config)
42 expected := expectedDiagnosticConfigForDefaultConfig()
43 setExpected(expected)
44 context, _ := newClientContextFromConfig(testSdkKey, config)
45 actual := makeDiagnosticConfigData(context, config, testStartWaitMillis)
46 assert.JSONEq(t, expected.Build().JSONString(), actual.JSONString())
47 }
48 doTest := func(setConfig func(*Config), setExpected func(*ldvalue.ObjectBuilder)) {
49 doTestWithoutStreamingDefaults(setConfig, func(b *ldvalue.ObjectBuilder) {
50 b.SetBool("customStreamURI", false).
51 Set("reconnectTimeMillis", timeMillis(ldcomponents.DefaultInitialReconnectDelay)).
52 SetBool("streamingDisabled", false)
53 setExpected(b)
54 })
55 }
56
57 doTest(func(c *Config) {}, func(b *ldvalue.ObjectBuilder) {})
58
59
60 doTest(func(c *Config) { c.DataStore = ldcomponents.InMemoryDataStore() }, func(b *ldvalue.ObjectBuilder) {})
61 doTest(func(c *Config) { c.DataStore = customStoreFactoryForDiagnostics{name: "Foo"} },
62 func(b *ldvalue.ObjectBuilder) { b.SetString("dataStoreType", "Foo") })
63 doTest(func(c *Config) { c.DataStore = customStoreFactoryWithoutDiagnosticDescription{} },
64 func(b *ldvalue.ObjectBuilder) { b.SetString("dataStoreType", "custom") })
65
66
67 doTest(func(c *Config) { c.DataSource = ldcomponents.StreamingDataSource() }, func(b *ldvalue.ObjectBuilder) {})
68 doTest(func(c *Config) {
69 c.ServiceEndpoints = interfaces.ServiceEndpoints{Streaming: "custom"}
70 }, func(b *ldvalue.ObjectBuilder) {
71 b.SetBool("customStreamURI", true)
72 })
73 doTest(func(c *Config) { c.DataSource = ldcomponents.StreamingDataSource().InitialReconnectDelay(time.Minute) },
74 func(b *ldvalue.ObjectBuilder) { b.Set("reconnectTimeMillis", ldvalue.Int(60000)) })
75 doTestWithoutStreamingDefaults(func(c *Config) { c.DataSource = ldcomponents.PollingDataSource() }, func(b *ldvalue.ObjectBuilder) {
76 b.SetBool("streamingDisabled", true)
77 b.SetBool("customBaseURI", false)
78 b.Set("pollingIntervalMillis", timeMillis(ldcomponents.DefaultPollInterval))
79 })
80 doTestWithoutStreamingDefaults(func(c *Config) {
81 c.DataSource = ldcomponents.PollingDataSource().PollInterval(time.Minute * 99)
82 }, func(b *ldvalue.ObjectBuilder) {
83 b.SetBool("streamingDisabled", true)
84 b.SetBool("customBaseURI", false)
85 b.Set("pollingIntervalMillis", timeMillis(time.Minute*99))
86 })
87 doTestWithoutStreamingDefaults(func(c *Config) {
88 c.DataSource = ldcomponents.PollingDataSource()
89 c.ServiceEndpoints = interfaces.ServiceEndpoints{Polling: "custom"}
90 }, func(b *ldvalue.ObjectBuilder) {
91 b.SetBool("streamingDisabled", true)
92 b.SetBool("customBaseURI", true)
93 b.Set("pollingIntervalMillis", timeMillis(ldcomponents.DefaultPollInterval))
94 })
95 doTestWithoutStreamingDefaults(func(c *Config) { c.DataSource = ldcomponents.ExternalUpdatesOnly() },
96 func(b *ldvalue.ObjectBuilder) { b.SetBool("usingRelayDaemon", true) })
97
98
99 doTest(func(c *Config) { c.Events = ldcomponents.SendEvents() }, func(b *ldvalue.ObjectBuilder) {})
100 doTest(func(c *Config) { c.Events = ldcomponents.SendEvents().AllAttributesPrivate(true) },
101 func(b *ldvalue.ObjectBuilder) { b.SetBool("allAttributesPrivate", true) })
102 doTest(func(c *Config) { c.Events = ldcomponents.SendEvents().DiagnosticRecordingInterval(time.Second * 99) },
103 func(b *ldvalue.ObjectBuilder) { b.SetInt("diagnosticRecordingIntervalMillis", 99000) })
104 doTest(func(c *Config) { c.Events = ldcomponents.SendEvents().Capacity(99) },
105 func(b *ldvalue.ObjectBuilder) { b.SetInt("eventsCapacity", 99) })
106 doTest(func(c *Config) { c.ServiceEndpoints = interfaces.ServiceEndpoints{Events: "custom"} },
107 func(b *ldvalue.ObjectBuilder) { b.SetBool("customEventsURI", true) })
108 doTest(func(c *Config) { c.Events = ldcomponents.SendEvents().FlushInterval(time.Second) },
109 func(b *ldvalue.ObjectBuilder) { b.SetInt("eventsFlushIntervalMillis", 1000) })
110 doTest(func(c *Config) { c.Events = ldcomponents.SendEvents().ContextKeysCapacity(2) },
111 func(b *ldvalue.ObjectBuilder) { b.SetInt("userKeysCapacity", 2) })
112 doTest(func(c *Config) { c.Events = ldcomponents.SendEvents().ContextKeysFlushInterval(time.Second) },
113 func(b *ldvalue.ObjectBuilder) { b.Set("userKeysFlushIntervalMillis", ldvalue.Int(1000)) })
114
115
116 doTest(
117 func(c *Config) {
118 c.HTTP = ldcomponents.HTTPConfiguration().ConnectTimeout(time.Second)
119 },
120 func(b *ldvalue.ObjectBuilder) {
121 b.SetInt("connectTimeoutMillis", 1000)
122 b.SetInt("socketTimeoutMillis", 1000)
123 })
124 doTest(
125 func(c *Config) {
126 c.HTTP = ldcomponents.HTTPConfiguration().ProxyURL("http://proxyhost")
127 },
128 func(b *ldvalue.ObjectBuilder) {
129 b.SetBool("usingProxy", true)
130 })
131 doTest(
132 func(c *Config) {
133 c.HTTP = ldcomponents.HTTPConfiguration().
134 HTTPClientFactory(func() *http.Client { return http.DefaultClient })
135 },
136 func(b *ldvalue.ObjectBuilder) {})
137 func() {
138 os.Setenv("HTTP_PROXY", "http://proxyhost")
139 defer os.Setenv("HTTP_PROXY", "")
140 doTest(
141 func(c *Config) {},
142 func(b *ldvalue.ObjectBuilder) {
143 b.SetBool("usingProxy", true)
144 })
145 }()
146 }
147
148 type customStoreFactoryForDiagnostics struct {
149 name string
150 }
151
152 func (c customStoreFactoryForDiagnostics) DescribeConfiguration(context subsystems.ClientContext) ldvalue.Value {
153 return ldvalue.String(c.name)
154 }
155
156 func (c customStoreFactoryForDiagnostics) Build(context subsystems.ClientContext) (subsystems.DataStore, error) {
157 return nil, errors.New("not implemented")
158 }
159
160 type customStoreFactoryWithoutDiagnosticDescription struct{}
161
162 func (c customStoreFactoryWithoutDiagnosticDescription) Build(context subsystems.ClientContext) (subsystems.DataStore, error) {
163 return nil, errors.New("not implemented")
164 }
165
View as plain text