launchdarkly-server-sdk 6.2.3 → 6.3.1

Sign up to get free protection for your applications and to get access to all the features.
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