launchdarkly-server-sdk 6.2.3 → 6.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/lib/ldclient-rb/config.rb +81 -4
  4. data/lib/ldclient-rb/evaluation_detail.rb +67 -8
  5. data/lib/ldclient-rb/file_data_source.rb +9 -300
  6. data/lib/ldclient-rb/impl/big_segments.rb +117 -0
  7. data/lib/ldclient-rb/impl/evaluator.rb +80 -28
  8. data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +82 -18
  9. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +212 -0
  10. data/lib/ldclient-rb/impl/integrations/redis_impl.rb +84 -31
  11. data/lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb +40 -0
  12. data/lib/ldclient-rb/impl/repeating_task.rb +47 -0
  13. data/lib/ldclient-rb/impl/util.rb +4 -1
  14. data/lib/ldclient-rb/integrations/consul.rb +7 -0
  15. data/lib/ldclient-rb/integrations/dynamodb.rb +47 -2
  16. data/lib/ldclient-rb/integrations/file_data.rb +108 -0
  17. data/lib/ldclient-rb/integrations/redis.rb +41 -1
  18. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +438 -0
  19. data/lib/ldclient-rb/integrations/test_data.rb +209 -0
  20. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +5 -0
  21. data/lib/ldclient-rb/integrations.rb +2 -51
  22. data/lib/ldclient-rb/interfaces.rb +152 -2
  23. data/lib/ldclient-rb/ldclient.rb +21 -7
  24. data/lib/ldclient-rb/polling.rb +22 -41
  25. data/lib/ldclient-rb/util.rb +1 -1
  26. data/lib/ldclient-rb/version.rb +1 -1
  27. metadata +31 -132
  28. data/.circleci/config.yml +0 -40
  29. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -37
  30. data/.github/ISSUE_TEMPLATE/config.yml +0 -5
  31. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  32. data/.github/pull_request_template.md +0 -21
  33. data/.gitignore +0 -16
  34. data/.hound.yml +0 -2
  35. data/.ldrelease/build-docs.sh +0 -18
  36. data/.ldrelease/circleci/linux/execute.sh +0 -18
  37. data/.ldrelease/circleci/mac/execute.sh +0 -18
  38. data/.ldrelease/circleci/template/build.sh +0 -29
  39. data/.ldrelease/circleci/template/publish.sh +0 -23
  40. data/.ldrelease/circleci/template/set-gem-home.sh +0 -7
  41. data/.ldrelease/circleci/template/test.sh +0 -10
  42. data/.ldrelease/circleci/template/update-version.sh +0 -8
  43. data/.ldrelease/circleci/windows/execute.ps1 +0 -19
  44. data/.ldrelease/config.yml +0 -29
  45. data/.rspec +0 -2
  46. data/.rubocop.yml +0 -600
  47. data/.simplecov +0 -4
  48. data/CHANGELOG.md +0 -367
  49. data/CODEOWNERS +0 -1
  50. data/CONTRIBUTING.md +0 -37
  51. data/Gemfile +0 -3
  52. data/azure-pipelines.yml +0 -51
  53. data/docs/Makefile +0 -26
  54. data/docs/index.md +0 -9
  55. data/launchdarkly-server-sdk.gemspec +0 -45
  56. data/spec/config_spec.rb +0 -63
  57. data/spec/diagnostic_events_spec.rb +0 -165
  58. data/spec/evaluation_detail_spec.rb +0 -135
  59. data/spec/event_sender_spec.rb +0 -197
  60. data/spec/event_summarizer_spec.rb +0 -63
  61. data/spec/events_spec.rb +0 -607
  62. data/spec/expiring_cache_spec.rb +0 -76
  63. data/spec/feature_store_spec_base.rb +0 -213
  64. data/spec/file_data_source_spec.rb +0 -283
  65. data/spec/fixtures/feature.json +0 -37
  66. data/spec/fixtures/feature1.json +0 -36
  67. data/spec/fixtures/user.json +0 -9
  68. data/spec/flags_state_spec.rb +0 -81
  69. data/spec/http_util.rb +0 -132
  70. data/spec/impl/evaluator_bucketing_spec.rb +0 -216
  71. data/spec/impl/evaluator_clause_spec.rb +0 -55
  72. data/spec/impl/evaluator_operators_spec.rb +0 -141
  73. data/spec/impl/evaluator_rule_spec.rb +0 -128
  74. data/spec/impl/evaluator_segment_spec.rb +0 -125
  75. data/spec/impl/evaluator_spec.rb +0 -349
  76. data/spec/impl/evaluator_spec_base.rb +0 -75
  77. data/spec/impl/event_factory_spec.rb +0 -108
  78. data/spec/impl/model/serialization_spec.rb +0 -41
  79. data/spec/in_memory_feature_store_spec.rb +0 -12
  80. data/spec/integrations/consul_feature_store_spec.rb +0 -40
  81. data/spec/integrations/dynamodb_feature_store_spec.rb +0 -103
  82. data/spec/integrations/store_wrapper_spec.rb +0 -276
  83. data/spec/launchdarkly-server-sdk_spec.rb +0 -13
  84. data/spec/launchdarkly-server-sdk_spec_autoloadtest.rb +0 -9
  85. data/spec/ldclient_end_to_end_spec.rb +0 -157
  86. data/spec/ldclient_spec.rb +0 -635
  87. data/spec/newrelic_spec.rb +0 -5
  88. data/spec/polling_spec.rb +0 -120
  89. data/spec/redis_feature_store_spec.rb +0 -121
  90. data/spec/requestor_spec.rb +0 -209
  91. data/spec/segment_store_spec_base.rb +0 -95
  92. data/spec/simple_lru_cache_spec.rb +0 -24
  93. data/spec/spec_helper.rb +0 -9
  94. data/spec/store_spec.rb +0 -10
  95. data/spec/stream_spec.rb +0 -45
  96. data/spec/user_filter_spec.rb +0 -91
  97. data/spec/util_spec.rb +0 -17
  98. data/spec/version_spec.rb +0 -7
data/spec/events_spec.rb DELETED
@@ -1,607 +0,0 @@
1
- require "http_util"
2
- require "spec_helper"
3
- require "time"
4
-
5
- describe LaunchDarkly::EventProcessor do
6
- subject { LaunchDarkly::EventProcessor }
7
-
8
- let(:default_config_opts) { { diagnostic_opt_out: true, logger: $null_log } }
9
- let(:default_config) { LaunchDarkly::Config.new(default_config_opts) }
10
- let(:user) { { key: "userkey", name: "Red" } }
11
- let(:filtered_user) { { key: "userkey", privateAttrs: [ "name" ] } }
12
- let(:numeric_user) { { key: 1, secondary: 2, ip: 3, country: 4, email: 5, firstName: 6, lastName: 7,
13
- avatar: 8, name: 9, anonymous: false, custom: { age: 99 } } }
14
- let(:stringified_numeric_user) { { key: '1', secondary: '2', ip: '3', country: '4', email: '5', firstName: '6',
15
- lastName: '7', avatar: '8', name: '9', anonymous: false, custom: { age: 99 } } }
16
-
17
- def with_processor_and_sender(config)
18
- sender = FakeEventSender.new
19
- ep = subject.new("sdk_key", config, nil, nil, { event_sender: sender })
20
- begin
21
- yield ep, sender
22
- ensure
23
- ep.stop
24
- end
25
- end
26
-
27
- it "queues identify event" do
28
- with_processor_and_sender(default_config) do |ep, sender|
29
- e = { kind: "identify", key: user[:key], user: user }
30
- ep.add_event(e)
31
-
32
- output = flush_and_get_events(ep, sender)
33
- expect(output).to contain_exactly(e)
34
- end
35
- end
36
-
37
- it "filters user in identify event" do
38
- config = LaunchDarkly::Config.new(default_config_opts.merge(all_attributes_private: true))
39
- with_processor_and_sender(config) do |ep, sender|
40
- e = { kind: "identify", key: user[:key], user: user }
41
- ep.add_event(e)
42
-
43
- output = flush_and_get_events(ep, sender)
44
- expect(output).to contain_exactly({
45
- kind: "identify",
46
- key: user[:key],
47
- creationDate: e[:creationDate],
48
- user: filtered_user
49
- })
50
- end
51
- end
52
-
53
- it "stringifies built-in user attributes in identify event" do
54
- with_processor_and_sender(default_config) do |ep, sender|
55
- flag = { key: "flagkey", version: 11 }
56
- e = { kind: "identify", key: numeric_user[:key], user: numeric_user }
57
- ep.add_event(e)
58
-
59
- output = flush_and_get_events(ep, sender)
60
- expect(output).to contain_exactly(
61
- kind: "identify",
62
- key: numeric_user[:key].to_s,
63
- creationDate: e[:creationDate],
64
- user: stringified_numeric_user
65
- )
66
- end
67
- end
68
-
69
- it "queues individual feature event with index event" do
70
- with_processor_and_sender(default_config) do |ep, sender|
71
- flag = { key: "flagkey", version: 11 }
72
- fe = {
73
- kind: "feature", key: "flagkey", version: 11, user: user,
74
- variation: 1, value: "value", trackEvents: true
75
- }
76
- ep.add_event(fe)
77
-
78
- output = flush_and_get_events(ep, sender)
79
- expect(output).to contain_exactly(
80
- eq(index_event(fe, user)),
81
- eq(feature_event(fe, flag, false, nil)),
82
- include(:kind => "summary")
83
- )
84
- end
85
- end
86
-
87
- it "filters user in index event" do
88
- config = LaunchDarkly::Config.new(default_config_opts.merge(all_attributes_private: true))
89
- with_processor_and_sender(config) do |ep, sender|
90
- flag = { key: "flagkey", version: 11 }
91
- fe = {
92
- kind: "feature", key: "flagkey", version: 11, user: user,
93
- variation: 1, value: "value", trackEvents: true
94
- }
95
- ep.add_event(fe)
96
-
97
- output = flush_and_get_events(ep, sender)
98
- expect(output).to contain_exactly(
99
- eq(index_event(fe, filtered_user)),
100
- eq(feature_event(fe, flag, false, nil)),
101
- include(:kind => "summary")
102
- )
103
- end
104
- end
105
-
106
- it "stringifies built-in user attributes in index event" do
107
- with_processor_and_sender(default_config) do |ep, sender|
108
- flag = { key: "flagkey", version: 11 }
109
- fe = {
110
- kind: "feature", key: "flagkey", version: 11, user: numeric_user,
111
- variation: 1, value: "value", trackEvents: true
112
- }
113
- ep.add_event(fe)
114
-
115
- output = flush_and_get_events(ep, sender)
116
- expect(output).to contain_exactly(
117
- eq(index_event(fe, stringified_numeric_user)),
118
- eq(feature_event(fe, flag, false, nil)),
119
- include(:kind => "summary")
120
- )
121
- end
122
- end
123
-
124
- it "can include inline user in feature event" do
125
- config = LaunchDarkly::Config.new(default_config_opts.merge(inline_users_in_events: true))
126
- with_processor_and_sender(config) do |ep, sender|
127
- flag = { key: "flagkey", version: 11 }
128
- fe = {
129
- kind: "feature", key: "flagkey", version: 11, user: user,
130
- variation: 1, value: "value", trackEvents: true
131
- }
132
- ep.add_event(fe)
133
-
134
- output = flush_and_get_events(ep, sender)
135
- expect(output).to contain_exactly(
136
- eq(feature_event(fe, flag, false, user)),
137
- include(:kind => "summary")
138
- )
139
- end
140
- end
141
-
142
- it "stringifies built-in user attributes in feature event" do
143
- config = LaunchDarkly::Config.new(default_config_opts.merge(inline_users_in_events: true))
144
- with_processor_and_sender(config) do |ep, sender|
145
- flag = { key: "flagkey", version: 11 }
146
- fe = {
147
- kind: "feature", key: "flagkey", version: 11, user: numeric_user,
148
- variation: 1, value: "value", trackEvents: true
149
- }
150
- ep.add_event(fe)
151
-
152
- output = flush_and_get_events(ep, sender)
153
- expect(output).to contain_exactly(
154
- eq(feature_event(fe, flag, false, stringified_numeric_user)),
155
- include(:kind => "summary")
156
- )
157
- end
158
- end
159
-
160
- it "filters user in feature event" do
161
- config = LaunchDarkly::Config.new(default_config_opts.merge(all_attributes_private: true, inline_users_in_events: true))
162
- with_processor_and_sender(config) do |ep, sender|
163
- flag = { key: "flagkey", version: 11 }
164
- fe = {
165
- kind: "feature", key: "flagkey", version: 11, user: user,
166
- variation: 1, value: "value", trackEvents: true
167
- }
168
- ep.add_event(fe)
169
-
170
- output = flush_and_get_events(ep, sender)
171
- expect(output).to contain_exactly(
172
- eq(feature_event(fe, flag, false, filtered_user)),
173
- include(:kind => "summary")
174
- )
175
- end
176
- end
177
-
178
- it "still generates index event if inline_users is true but feature event was not tracked" do
179
- config = LaunchDarkly::Config.new(default_config_opts.merge(inline_users_in_events: true))
180
- with_processor_and_sender(config) do |ep, sender|
181
- flag = { key: "flagkey", version: 11 }
182
- fe = {
183
- kind: "feature", key: "flagkey", version: 11, user: user,
184
- variation: 1, value: "value", trackEvents: false
185
- }
186
- ep.add_event(fe)
187
-
188
- output = flush_and_get_events(ep, sender)
189
- expect(output).to contain_exactly(
190
- eq(index_event(fe, user)),
191
- include(:kind => "summary")
192
- )
193
- end
194
- end
195
-
196
- it "sets event kind to debug if flag is temporarily in debug mode" do
197
- with_processor_and_sender(default_config) do |ep, sender|
198
- flag = { key: "flagkey", version: 11 }
199
- future_time = (Time.now.to_f * 1000).to_i + 1000000
200
- fe = {
201
- kind: "feature", key: "flagkey", version: 11, user: user,
202
- variation: 1, value: "value", trackEvents: false, debugEventsUntilDate: future_time
203
- }
204
- ep.add_event(fe)
205
-
206
- output = flush_and_get_events(ep, sender)
207
- expect(output).to contain_exactly(
208
- eq(index_event(fe, user)),
209
- eq(feature_event(fe, flag, true, user)),
210
- include(:kind => "summary")
211
- )
212
- end
213
- end
214
-
215
- it "can be both debugging and tracking an event" do
216
- with_processor_and_sender(default_config) do |ep, sender|
217
- flag = { key: "flagkey", version: 11 }
218
- future_time = (Time.now.to_f * 1000).to_i + 1000000
219
- fe = {
220
- kind: "feature", key: "flagkey", version: 11, user: user,
221
- variation: 1, value: "value", trackEvents: true, debugEventsUntilDate: future_time
222
- }
223
- ep.add_event(fe)
224
-
225
- output = flush_and_get_events(ep, sender)
226
- expect(output).to contain_exactly(
227
- eq(index_event(fe, user)),
228
- eq(feature_event(fe, flag, false, nil)),
229
- eq(feature_event(fe, flag, true, user)),
230
- include(:kind => "summary")
231
- )
232
- end
233
- end
234
-
235
- it "ends debug mode based on client time if client time is later than server time" do
236
- with_processor_and_sender(default_config) do |ep, sender|
237
- # Pick a server time that is somewhat behind the client time
238
- server_time = Time.now - 20
239
-
240
- # Send and flush an event we don't care about, just to set the last server time
241
- sender.result = LaunchDarkly::Impl::EventSenderResult.new(true, false, server_time)
242
- ep.add_event({ kind: "identify", user: user })
243
- flush_and_get_events(ep, sender)
244
-
245
- # Now send an event with debug mode on, with a "debug until" time that is further in
246
- # the future than the server time, but in the past compared to the client.
247
- flag = { key: "flagkey", version: 11 }
248
- debug_until = (server_time.to_f * 1000).to_i + 1000
249
- fe = {
250
- kind: "feature", key: "flagkey", version: 11, user: user,
251
- variation: 1, value: "value", trackEvents: false, debugEventsUntilDate: debug_until
252
- }
253
- ep.add_event(fe)
254
-
255
- # Should get a summary event only, not a full feature event
256
- output = flush_and_get_events(ep, sender)
257
- expect(output).to contain_exactly(
258
- include(:kind => "summary")
259
- )
260
- end
261
- end
262
-
263
- it "ends debug mode based on server time if server time is later than client time" do
264
- with_processor_and_sender(default_config) do |ep, sender|
265
- # Pick a server time that is somewhat ahead of the client time
266
- server_time = Time.now + 20
267
-
268
- # Send and flush an event we don't care about, just to set the last server time
269
- sender.result = LaunchDarkly::Impl::EventSenderResult.new(true, false, server_time)
270
- ep.add_event({ kind: "identify", user: user })
271
- flush_and_get_events(ep, sender)
272
-
273
- # Now send an event with debug mode on, with a "debug until" time that is further in
274
- # the future than the server time, but in the past compared to the client.
275
- flag = { key: "flagkey", version: 11 }
276
- debug_until = (server_time.to_f * 1000).to_i - 1000
277
- fe = {
278
- kind: "feature", key: "flagkey", version: 11, user: user,
279
- variation: 1, value: "value", trackEvents: false, debugEventsUntilDate: debug_until
280
- }
281
- ep.add_event(fe)
282
-
283
- # Should get a summary event only, not a full feature event
284
- output = flush_and_get_events(ep, sender)
285
- expect(output).to contain_exactly(
286
- include(:kind => "summary")
287
- )
288
- end
289
- end
290
-
291
- it "generates only one index event for multiple events with same user" do
292
- with_processor_and_sender(default_config) do |ep, sender|
293
- flag1 = { key: "flagkey1", version: 11 }
294
- flag2 = { key: "flagkey2", version: 22 }
295
- future_time = (Time.now.to_f * 1000).to_i + 1000000
296
- fe1 = {
297
- kind: "feature", key: "flagkey1", version: 11, user: user,
298
- variation: 1, value: "value", trackEvents: true
299
- }
300
- fe2 = {
301
- kind: "feature", key: "flagkey2", version: 22, user: user,
302
- variation: 1, value: "value", trackEvents: true
303
- }
304
- ep.add_event(fe1)
305
- ep.add_event(fe2)
306
-
307
- output = flush_and_get_events(ep, sender)
308
- expect(output).to contain_exactly(
309
- eq(index_event(fe1, user)),
310
- eq(feature_event(fe1, flag1, false, nil)),
311
- eq(feature_event(fe2, flag2, false, nil)),
312
- include(:kind => "summary")
313
- )
314
- end
315
- end
316
-
317
- it "summarizes non-tracked events" do
318
- with_processor_and_sender(default_config) do |ep, sender|
319
- flag1 = { key: "flagkey1", version: 11 }
320
- flag2 = { key: "flagkey2", version: 22 }
321
- future_time = (Time.now.to_f * 1000).to_i + 1000000
322
- fe1 = {
323
- kind: "feature", key: "flagkey1", version: 11, user: user,
324
- variation: 1, value: "value1", default: "default1"
325
- }
326
- fe2 = {
327
- kind: "feature", key: "flagkey2", version: 22, user: user,
328
- variation: 2, value: "value2", default: "default2"
329
- }
330
- ep.add_event(fe1)
331
- ep.add_event(fe2)
332
-
333
- output = flush_and_get_events(ep, sender)
334
- expect(output).to contain_exactly(
335
- eq(index_event(fe1, user)),
336
- eq({
337
- kind: "summary",
338
- startDate: fe1[:creationDate],
339
- endDate: fe2[:creationDate],
340
- features: {
341
- flagkey1: {
342
- default: "default1",
343
- counters: [
344
- { version: 11, variation: 1, value: "value1", count: 1 }
345
- ]
346
- },
347
- flagkey2: {
348
- default: "default2",
349
- counters: [
350
- { version: 22, variation: 2, value: "value2", count: 1 }
351
- ]
352
- }
353
- }
354
- })
355
- )
356
- end
357
- end
358
-
359
- it "queues custom event with user" do
360
- with_processor_and_sender(default_config) do |ep, sender|
361
- e = { kind: "custom", key: "eventkey", user: user, data: { thing: "stuff" }, metricValue: 1.5 }
362
- ep.add_event(e)
363
-
364
- output = flush_and_get_events(ep, sender)
365
- expect(output).to contain_exactly(
366
- eq(index_event(e, user)),
367
- eq(custom_event(e, nil))
368
- )
369
- end
370
- end
371
-
372
- it "can include inline user in custom event" do
373
- config = LaunchDarkly::Config.new(default_config_opts.merge(inline_users_in_events: true))
374
- with_processor_and_sender(config) do |ep, sender|
375
- e = { kind: "custom", key: "eventkey", user: user, data: { thing: "stuff" } }
376
- ep.add_event(e)
377
-
378
- output = flush_and_get_events(ep, sender)
379
- expect(output).to contain_exactly(
380
- eq(custom_event(e, user))
381
- )
382
- end
383
- end
384
-
385
- it "filters user in custom event" do
386
- config = LaunchDarkly::Config.new(default_config_opts.merge(all_attributes_private: true, inline_users_in_events: true))
387
- with_processor_and_sender(config) do |ep, sender|
388
- e = { kind: "custom", key: "eventkey", user: user, data: { thing: "stuff" } }
389
- ep.add_event(e)
390
-
391
- output = flush_and_get_events(ep, sender)
392
- expect(output).to contain_exactly(
393
- eq(custom_event(e, filtered_user))
394
- )
395
- end
396
- end
397
-
398
- it "stringifies built-in user attributes in custom event" do
399
- config = LaunchDarkly::Config.new(default_config_opts.merge(inline_users_in_events: true))
400
- with_processor_and_sender(config) do |ep, sender|
401
- e = { kind: "custom", key: "eventkey", user: numeric_user }
402
- ep.add_event(e)
403
-
404
- output = flush_and_get_events(ep, sender)
405
- expect(output).to contain_exactly(
406
- eq(custom_event(e, stringified_numeric_user))
407
- )
408
- end
409
- end
410
-
411
- it "queues alias event" do
412
- with_processor_and_sender(default_config) do |ep, sender|
413
- e = { kind: "alias", key: "a", contextKind: "user", previousKey: "b", previousContextKind: "user" }
414
- ep.add_event(e)
415
-
416
- output = flush_and_get_events(ep, sender)
417
- expect(output).to contain_exactly(e)
418
- end
419
- end
420
-
421
- it "treats nil value for custom the same as an empty hash" do
422
- with_processor_and_sender(default_config) do |ep, sender|
423
- user_with_nil_custom = { key: "userkey", custom: nil }
424
- e = { kind: "identify", key: "userkey", user: user_with_nil_custom }
425
- ep.add_event(e)
426
-
427
- output = flush_and_get_events(ep, sender)
428
- expect(output).to contain_exactly(e)
429
- end
430
- end
431
-
432
- it "does a final flush when shutting down" do
433
- with_processor_and_sender(default_config) do |ep, sender|
434
- e = { kind: "identify", key: user[:key], user: user }
435
- ep.add_event(e)
436
-
437
- ep.stop
438
-
439
- output = sender.analytics_payloads.pop
440
- expect(output).to contain_exactly(e)
441
- end
442
- end
443
-
444
- it "sends nothing if there are no events" do
445
- with_processor_and_sender(default_config) do |ep, sender|
446
- ep.flush
447
- ep.wait_until_inactive
448
- expect(sender.analytics_payloads.empty?).to be true
449
- end
450
- end
451
-
452
- it "stops posting events after unrecoverable error" do
453
- with_processor_and_sender(default_config) do |ep, sender|
454
- sender.result = LaunchDarkly::Impl::EventSenderResult.new(false, true, nil)
455
- e = { kind: "identify", key: user[:key], user: user }
456
- ep.add_event(e)
457
- flush_and_get_events(ep, sender)
458
-
459
- e = { kind: "identify", key: user[:key], user: user }
460
- ep.add_event(e)
461
- ep.flush
462
- ep.wait_until_inactive
463
- expect(sender.analytics_payloads.empty?).to be true
464
- end
465
- end
466
-
467
- describe "diagnostic events" do
468
- let(:default_id) { LaunchDarkly::Impl::DiagnosticAccumulator.create_diagnostic_id('sdk_key') }
469
- let(:diagnostic_config) { LaunchDarkly::Config.new(diagnostic_opt_out: false, logger: $null_log) }
470
-
471
- def with_diagnostic_processor_and_sender(config)
472
- sender = FakeEventSender.new
473
- acc = LaunchDarkly::Impl::DiagnosticAccumulator.new(default_id)
474
- ep = subject.new("sdk_key", config, nil, acc,
475
- { diagnostic_recording_interval: 0.2, event_sender: sender })
476
- begin
477
- yield ep, sender
478
- ensure
479
- ep.stop
480
- end
481
- end
482
-
483
- it "sends init event" do
484
- with_diagnostic_processor_and_sender(diagnostic_config) do |ep, sender|
485
- event = sender.diagnostic_payloads.pop
486
- expect(event).to include({
487
- kind: 'diagnostic-init',
488
- id: default_id
489
- })
490
- end
491
- end
492
-
493
- it "sends periodic event" do
494
- with_diagnostic_processor_and_sender(diagnostic_config) do |ep, sender|
495
- init_event = sender.diagnostic_payloads.pop
496
- periodic_event = sender.diagnostic_payloads.pop
497
- expect(periodic_event).to include({
498
- kind: 'diagnostic',
499
- id: default_id,
500
- droppedEvents: 0,
501
- deduplicatedUsers: 0,
502
- eventsInLastBatch: 0,
503
- streamInits: []
504
- })
505
- end
506
- end
507
-
508
- it "counts events in queue from last flush and dropped events" do
509
- config = LaunchDarkly::Config.new(diagnostic_opt_out: false, capacity: 2, logger: $null_log)
510
- with_diagnostic_processor_and_sender(config) do |ep, sender|
511
- init_event = sender.diagnostic_payloads.pop
512
-
513
- ep.add_event({ kind: 'identify', user: user })
514
- ep.add_event({ kind: 'identify', user: user })
515
- ep.add_event({ kind: 'identify', user: user })
516
- flush_and_get_events(ep, sender)
517
-
518
- periodic_event = sender.diagnostic_payloads.pop
519
- expect(periodic_event).to include({
520
- kind: 'diagnostic',
521
- droppedEvents: 1,
522
- eventsInLastBatch: 2
523
- })
524
- end
525
- end
526
-
527
- it "counts deduplicated users" do
528
- with_diagnostic_processor_and_sender(diagnostic_config) do |ep, sender|
529
- init_event = sender.diagnostic_payloads.pop
530
-
531
- ep.add_event({ kind: 'custom', key: 'event1', user: user })
532
- ep.add_event({ kind: 'custom', key: 'event2', user: user })
533
- events = flush_and_get_events(ep, sender)
534
-
535
- periodic_event = sender.diagnostic_payloads.pop
536
- expect(periodic_event).to include({
537
- kind: 'diagnostic',
538
- deduplicatedUsers: 1
539
- })
540
- end
541
- end
542
- end
543
-
544
- def index_event(e, user)
545
- {
546
- kind: "index",
547
- creationDate: e[:creationDate],
548
- user: user
549
- }
550
- end
551
-
552
- def feature_event(e, flag, debug, inline_user)
553
- out = {
554
- kind: debug ? "debug" : "feature",
555
- creationDate: e[:creationDate],
556
- key: flag[:key],
557
- variation: e[:variation],
558
- version: flag[:version],
559
- value: e[:value]
560
- }
561
- if inline_user.nil?
562
- out[:userKey] = e[:user][:key]
563
- else
564
- out[:user] = inline_user
565
- end
566
- out
567
- end
568
-
569
- def custom_event(e, inline_user)
570
- out = {
571
- kind: "custom",
572
- creationDate: e[:creationDate],
573
- key: e[:key]
574
- }
575
- out[:data] = e[:data] if e.has_key?(:data)
576
- if inline_user.nil?
577
- out[:userKey] = e[:user][:key]
578
- else
579
- out[:user] = inline_user
580
- end
581
- out[:metricValue] = e[:metricValue] if e.has_key?(:metricValue)
582
- out
583
- end
584
-
585
- def flush_and_get_events(ep, sender)
586
- ep.flush
587
- ep.wait_until_inactive
588
- sender.analytics_payloads.pop
589
- end
590
-
591
- class FakeEventSender
592
- attr_accessor :result
593
- attr_reader :analytics_payloads
594
- attr_reader :diagnostic_payloads
595
-
596
- def initialize
597
- @result = LaunchDarkly::Impl::EventSenderResult.new(true, false, nil)
598
- @analytics_payloads = Queue.new
599
- @diagnostic_payloads = Queue.new
600
- end
601
-
602
- def send_event_data(data, description, is_diagnostic)
603
- (is_diagnostic ? @diagnostic_payloads : @analytics_payloads).push(JSON.parse(data, symbolize_names: true))
604
- @result
605
- end
606
- end
607
- end
@@ -1,76 +0,0 @@
1
- require 'timecop'
2
-
3
- describe LaunchDarkly::ExpiringCache do
4
- subject { LaunchDarkly::ExpiringCache }
5
-
6
- before(:each) do
7
- Timecop.freeze(Time.now)
8
- end
9
-
10
- after(:each) do
11
- Timecop.return
12
- end
13
-
14
- it "evicts entries based on TTL" do
15
- c = subject.new(3, 300)
16
- c[:a] = 1
17
- c[:b] = 2
18
-
19
- Timecop.freeze(Time.now + 330)
20
-
21
- c[:c] = 3
22
-
23
- expect(c[:a]).to be nil
24
- expect(c[:b]).to be nil
25
- expect(c[:c]).to eq 3
26
- end
27
-
28
- it "evicts entries based on max size" do
29
- c = subject.new(2, 300)
30
- c[:a] = 1
31
- c[:b] = 2
32
- c[:c] = 3
33
-
34
- expect(c[:a]).to be nil
35
- expect(c[:b]).to eq 2
36
- expect(c[:c]).to eq 3
37
- end
38
-
39
- it "does not reset LRU on get" do
40
- c = subject.new(2, 300)
41
- c[:a] = 1
42
- c[:b] = 2
43
- c[:a]
44
- c[:c] = 3
45
-
46
- expect(c[:a]).to be nil
47
- expect(c[:b]).to eq 2
48
- expect(c[:c]).to eq 3
49
- end
50
-
51
- it "resets LRU on put" do
52
- c = subject.new(2, 300)
53
- c[:a] = 1
54
- c[:b] = 2
55
- c[:a] = 1
56
- c[:c] = 3
57
-
58
- expect(c[:a]).to eq 1
59
- expect(c[:b]).to be nil
60
- expect(c[:c]).to eq 3
61
- end
62
-
63
- it "resets TTL on put" do
64
- c = subject.new(3, 300)
65
- c[:a] = 1
66
- c[:b] = 2
67
-
68
- Timecop.freeze(Time.now + 330)
69
- c[:a] = 1
70
- c[:c] = 3
71
-
72
- expect(c[:a]).to eq 1
73
- expect(c[:b]).to be nil
74
- expect(c[:c]).to eq 3
75
- end
76
- end