launchdarkly-server-sdk 6.2.2 → 6.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) 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/diagnostic_events.rb +1 -1
  8. data/lib/ldclient-rb/impl/evaluator.rb +80 -28
  9. data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +82 -18
  10. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +212 -0
  11. data/lib/ldclient-rb/impl/integrations/redis_impl.rb +84 -31
  12. data/lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb +40 -0
  13. data/lib/ldclient-rb/impl/repeating_task.rb +47 -0
  14. data/lib/ldclient-rb/impl/util.rb +4 -1
  15. data/lib/ldclient-rb/integrations/consul.rb +7 -0
  16. data/lib/ldclient-rb/integrations/dynamodb.rb +47 -2
  17. data/lib/ldclient-rb/integrations/file_data.rb +108 -0
  18. data/lib/ldclient-rb/integrations/redis.rb +41 -1
  19. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +438 -0
  20. data/lib/ldclient-rb/integrations/test_data.rb +209 -0
  21. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +5 -0
  22. data/lib/ldclient-rb/integrations.rb +2 -51
  23. data/lib/ldclient-rb/interfaces.rb +152 -2
  24. data/lib/ldclient-rb/ldclient.rb +21 -7
  25. data/lib/ldclient-rb/polling.rb +22 -41
  26. data/lib/ldclient-rb/util.rb +1 -1
  27. data/lib/ldclient-rb/version.rb +1 -1
  28. metadata +31 -132
  29. data/.circleci/config.yml +0 -40
  30. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -37
  31. data/.github/ISSUE_TEMPLATE/config.yml +0 -5
  32. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  33. data/.github/pull_request_template.md +0 -21
  34. data/.gitignore +0 -16
  35. data/.hound.yml +0 -2
  36. data/.ldrelease/build-docs.sh +0 -18
  37. data/.ldrelease/circleci/linux/execute.sh +0 -18
  38. data/.ldrelease/circleci/mac/execute.sh +0 -18
  39. data/.ldrelease/circleci/template/build.sh +0 -29
  40. data/.ldrelease/circleci/template/publish.sh +0 -23
  41. data/.ldrelease/circleci/template/set-gem-home.sh +0 -7
  42. data/.ldrelease/circleci/template/test.sh +0 -10
  43. data/.ldrelease/circleci/template/update-version.sh +0 -8
  44. data/.ldrelease/circleci/windows/execute.ps1 +0 -19
  45. data/.ldrelease/config.yml +0 -29
  46. data/.rspec +0 -2
  47. data/.rubocop.yml +0 -600
  48. data/.simplecov +0 -4
  49. data/CHANGELOG.md +0 -363
  50. data/CODEOWNERS +0 -1
  51. data/CONTRIBUTING.md +0 -37
  52. data/Gemfile +0 -3
  53. data/azure-pipelines.yml +0 -51
  54. data/docs/Makefile +0 -26
  55. data/docs/index.md +0 -9
  56. data/launchdarkly-server-sdk.gemspec +0 -45
  57. data/spec/config_spec.rb +0 -63
  58. data/spec/diagnostic_events_spec.rb +0 -163
  59. data/spec/evaluation_detail_spec.rb +0 -135
  60. data/spec/event_sender_spec.rb +0 -197
  61. data/spec/event_summarizer_spec.rb +0 -63
  62. data/spec/events_spec.rb +0 -607
  63. data/spec/expiring_cache_spec.rb +0 -76
  64. data/spec/feature_store_spec_base.rb +0 -213
  65. data/spec/file_data_source_spec.rb +0 -283
  66. data/spec/fixtures/feature.json +0 -37
  67. data/spec/fixtures/feature1.json +0 -36
  68. data/spec/fixtures/user.json +0 -9
  69. data/spec/flags_state_spec.rb +0 -81
  70. data/spec/http_util.rb +0 -132
  71. data/spec/impl/evaluator_bucketing_spec.rb +0 -216
  72. data/spec/impl/evaluator_clause_spec.rb +0 -55
  73. data/spec/impl/evaluator_operators_spec.rb +0 -141
  74. data/spec/impl/evaluator_rule_spec.rb +0 -128
  75. data/spec/impl/evaluator_segment_spec.rb +0 -125
  76. data/spec/impl/evaluator_spec.rb +0 -349
  77. data/spec/impl/evaluator_spec_base.rb +0 -75
  78. data/spec/impl/event_factory_spec.rb +0 -108
  79. data/spec/impl/model/serialization_spec.rb +0 -41
  80. data/spec/in_memory_feature_store_spec.rb +0 -12
  81. data/spec/integrations/consul_feature_store_spec.rb +0 -40
  82. data/spec/integrations/dynamodb_feature_store_spec.rb +0 -103
  83. data/spec/integrations/store_wrapper_spec.rb +0 -276
  84. data/spec/launchdarkly-server-sdk_spec.rb +0 -13
  85. data/spec/launchdarkly-server-sdk_spec_autoloadtest.rb +0 -9
  86. data/spec/ldclient_end_to_end_spec.rb +0 -157
  87. data/spec/ldclient_spec.rb +0 -635
  88. data/spec/newrelic_spec.rb +0 -5
  89. data/spec/polling_spec.rb +0 -120
  90. data/spec/redis_feature_store_spec.rb +0 -121
  91. data/spec/requestor_spec.rb +0 -209
  92. data/spec/segment_store_spec_base.rb +0 -95
  93. data/spec/simple_lru_cache_spec.rb +0 -24
  94. data/spec/spec_helper.rb +0 -9
  95. data/spec/store_spec.rb +0 -10
  96. data/spec/stream_spec.rb +0 -45
  97. data/spec/user_filter_spec.rb +0 -91
  98. data/spec/util_spec.rb +0 -17
  99. data/spec/version_spec.rb +0 -7
@@ -1,125 +0,0 @@
1
- require "spec_helper"
2
- require "impl/evaluator_spec_base"
3
-
4
- module LaunchDarkly
5
- module Impl
6
- describe "Evaluator (segments)", :evaluator_spec_base => true do
7
- subject { Evaluator }
8
-
9
- def test_segment_match(segment)
10
- clause = make_segment_match_clause(segment)
11
- flag = boolean_flag_with_clauses([clause])
12
- e = Evaluator.new(get_nothing, get_things({ segment[:key] => segment }), logger)
13
- e.evaluate(flag, user, factory).detail.value
14
- end
15
-
16
- it "retrieves segment from segment store for segmentMatch operator" do
17
- segment = {
18
- key: 'segkey',
19
- included: [ 'userkey' ],
20
- version: 1,
21
- deleted: false
22
- }
23
- get_segment = get_things({ 'segkey' => segment })
24
- e = subject.new(get_nothing, get_segment, logger)
25
- user = { key: 'userkey' }
26
- clause = { attribute: '', op: 'segmentMatch', values: ['segkey'] }
27
- flag = boolean_flag_with_clauses([clause])
28
- expect(e.evaluate(flag, user, factory).detail.value).to be true
29
- end
30
-
31
- it "falls through with no errors if referenced segment is not found" do
32
- e = subject.new(get_nothing, get_things({ 'segkey' => nil }), logger)
33
- user = { key: 'userkey' }
34
- clause = { attribute: '', op: 'segmentMatch', values: ['segkey'] }
35
- flag = boolean_flag_with_clauses([clause])
36
- expect(e.evaluate(flag, user, factory).detail.value).to be false
37
- end
38
-
39
- it 'explicitly includes user' do
40
- segment = make_segment('segkey')
41
- segment[:included] = [ user[:key] ]
42
- expect(test_segment_match(segment)).to be true
43
- end
44
-
45
- it 'explicitly excludes user' do
46
- segment = make_segment('segkey')
47
- segment[:excluded] = [ user[:key] ]
48
- expect(test_segment_match(segment)).to be false
49
- end
50
-
51
- it 'both includes and excludes user; include takes priority' do
52
- segment = make_segment('segkey')
53
- segment[:included] = [ user[:key] ]
54
- segment[:excluded] = [ user[:key] ]
55
- expect(test_segment_match(segment)).to be true
56
- end
57
-
58
- it 'matches user by rule when weight is absent' do
59
- segClause = make_user_matching_clause(user, :email)
60
- segRule = {
61
- clauses: [ segClause ]
62
- }
63
- segment = make_segment('segkey')
64
- segment[:rules] = [ segRule ]
65
- expect(test_segment_match(segment)).to be true
66
- end
67
-
68
- it 'matches user by rule when weight is nil' do
69
- segClause = make_user_matching_clause(user, :email)
70
- segRule = {
71
- clauses: [ segClause ],
72
- weight: nil
73
- }
74
- segment = make_segment('segkey')
75
- segment[:rules] = [ segRule ]
76
- expect(test_segment_match(segment)).to be true
77
- end
78
-
79
- it 'matches user with full rollout' do
80
- segClause = make_user_matching_clause(user, :email)
81
- segRule = {
82
- clauses: [ segClause ],
83
- weight: 100000
84
- }
85
- segment = make_segment('segkey')
86
- segment[:rules] = [ segRule ]
87
- expect(test_segment_match(segment)).to be true
88
- end
89
-
90
- it "doesn't match user with zero rollout" do
91
- segClause = make_user_matching_clause(user, :email)
92
- segRule = {
93
- clauses: [ segClause ],
94
- weight: 0
95
- }
96
- segment = make_segment('segkey')
97
- segment[:rules] = [ segRule ]
98
- expect(test_segment_match(segment)).to be false
99
- end
100
-
101
- it "matches user with multiple clauses" do
102
- segClause1 = make_user_matching_clause(user, :email)
103
- segClause2 = make_user_matching_clause(user, :name)
104
- segRule = {
105
- clauses: [ segClause1, segClause2 ]
106
- }
107
- segment = make_segment('segkey')
108
- segment[:rules] = [ segRule ]
109
- expect(test_segment_match(segment)).to be true
110
- end
111
-
112
- it "doesn't match user with multiple clauses if a clause doesn't match" do
113
- segClause1 = make_user_matching_clause(user, :email)
114
- segClause2 = make_user_matching_clause(user, :name)
115
- segClause2[:values] = [ 'wrong' ]
116
- segRule = {
117
- clauses: [ segClause1, segClause2 ]
118
- }
119
- segment = make_segment('segkey')
120
- segment[:rules] = [ segRule ]
121
- expect(test_segment_match(segment)).to be false
122
- end
123
- end
124
- end
125
- end
@@ -1,349 +0,0 @@
1
- require "spec_helper"
2
- require "impl/evaluator_spec_base"
3
-
4
- module LaunchDarkly
5
- module Impl
6
- describe "Evaluator (general)", :evaluator_spec_base => true do
7
- subject { Evaluator }
8
-
9
- describe "evaluate" do
10
- it "returns off variation if flag is off" do
11
- flag = {
12
- key: 'feature',
13
- on: false,
14
- offVariation: 1,
15
- fallthrough: { variation: 0 },
16
- variations: ['a', 'b', 'c']
17
- }
18
- user = { key: 'x' }
19
- detail = EvaluationDetail.new('b', 1, EvaluationReason::off)
20
- result = basic_evaluator.evaluate(flag, user, factory)
21
- expect(result.detail).to eq(detail)
22
- expect(result.events).to eq(nil)
23
- end
24
-
25
- it "returns nil if flag is off and off variation is unspecified" do
26
- flag = {
27
- key: 'feature',
28
- on: false,
29
- fallthrough: { variation: 0 },
30
- variations: ['a', 'b', 'c']
31
- }
32
- user = { key: 'x' }
33
- detail = EvaluationDetail.new(nil, nil, EvaluationReason::off)
34
- result = basic_evaluator.evaluate(flag, user, factory)
35
- expect(result.detail).to eq(detail)
36
- expect(result.events).to eq(nil)
37
- end
38
-
39
- it "returns an error if off variation is too high" do
40
- flag = {
41
- key: 'feature',
42
- on: false,
43
- offVariation: 999,
44
- fallthrough: { variation: 0 },
45
- variations: ['a', 'b', 'c']
46
- }
47
- user = { key: 'x' }
48
- detail = EvaluationDetail.new(nil, nil,
49
- EvaluationReason::error(EvaluationReason::ERROR_MALFORMED_FLAG))
50
- result = basic_evaluator.evaluate(flag, user, factory)
51
- expect(result.detail).to eq(detail)
52
- expect(result.events).to eq(nil)
53
- end
54
-
55
- it "returns an error if off variation is negative" do
56
- flag = {
57
- key: 'feature',
58
- on: false,
59
- offVariation: -1,
60
- fallthrough: { variation: 0 },
61
- variations: ['a', 'b', 'c']
62
- }
63
- user = { key: 'x' }
64
- detail = EvaluationDetail.new(nil, nil,
65
- EvaluationReason::error(EvaluationReason::ERROR_MALFORMED_FLAG))
66
- result = basic_evaluator.evaluate(flag, user, factory)
67
- expect(result.detail).to eq(detail)
68
- expect(result.events).to eq(nil)
69
- end
70
-
71
- it "returns off variation if prerequisite is not found" do
72
- flag = {
73
- key: 'feature0',
74
- on: true,
75
- prerequisites: [{key: 'badfeature', variation: 1}],
76
- fallthrough: { variation: 0 },
77
- offVariation: 1,
78
- variations: ['a', 'b', 'c']
79
- }
80
- user = { key: 'x' }
81
- detail = EvaluationDetail.new('b', 1, EvaluationReason::prerequisite_failed('badfeature'))
82
- e = subject.new(get_things( 'badfeature' => nil ), get_nothing, logger)
83
- result = e.evaluate(flag, user, factory)
84
- expect(result.detail).to eq(detail)
85
- expect(result.events).to eq(nil)
86
- end
87
-
88
- it "reuses prerequisite-failed reason instances if possible" do
89
- flag = {
90
- key: 'feature0',
91
- on: true,
92
- prerequisites: [{key: 'badfeature', variation: 1}],
93
- fallthrough: { variation: 0 },
94
- offVariation: 1,
95
- variations: ['a', 'b', 'c']
96
- }
97
- Model.postprocess_item_after_deserializing!(FEATURES, flag) # now there's a cached reason
98
- user = { key: 'x' }
99
- e = subject.new(get_things( 'badfeature' => nil ), get_nothing, logger)
100
- result1 = e.evaluate(flag, user, factory)
101
- expect(result1.detail.reason).to eq EvaluationReason::prerequisite_failed('badfeature')
102
- result2 = e.evaluate(flag, user, factory)
103
- expect(result2.detail.reason).to be result1.detail.reason
104
- end
105
-
106
- it "returns off variation and event if prerequisite of a prerequisite is not found" do
107
- flag = {
108
- key: 'feature0',
109
- on: true,
110
- prerequisites: [{key: 'feature1', variation: 1}],
111
- fallthrough: { variation: 0 },
112
- offVariation: 1,
113
- variations: ['a', 'b', 'c'],
114
- version: 1
115
- }
116
- flag1 = {
117
- key: 'feature1',
118
- on: true,
119
- prerequisites: [{key: 'feature2', variation: 1}], # feature2 doesn't exist
120
- fallthrough: { variation: 0 },
121
- variations: ['d', 'e'],
122
- version: 2
123
- }
124
- user = { key: 'x' }
125
- detail = EvaluationDetail.new('b', 1, EvaluationReason::prerequisite_failed('feature1'))
126
- events_should_be = [{
127
- kind: 'feature', key: 'feature1', user: user, value: nil, default: nil, variation: nil, version: 2, prereqOf: 'feature0'
128
- }]
129
- get_flag = get_things('feature1' => flag1, 'feature2' => nil)
130
- e = subject.new(get_flag, get_nothing, logger)
131
- result = e.evaluate(flag, user, factory)
132
- expect(result.detail).to eq(detail)
133
- expect(result.events).to eq(events_should_be)
134
- end
135
-
136
- it "returns off variation and event if prerequisite is off" do
137
- flag = {
138
- key: 'feature0',
139
- on: true,
140
- prerequisites: [{key: 'feature1', variation: 1}],
141
- fallthrough: { variation: 0 },
142
- offVariation: 1,
143
- variations: ['a', 'b', 'c'],
144
- version: 1
145
- }
146
- flag1 = {
147
- key: 'feature1',
148
- on: false,
149
- # note that even though it returns the desired variation, it is still off and therefore not a match
150
- offVariation: 1,
151
- fallthrough: { variation: 0 },
152
- variations: ['d', 'e'],
153
- version: 2
154
- }
155
- user = { key: 'x' }
156
- detail = EvaluationDetail.new('b', 1, EvaluationReason::prerequisite_failed('feature1'))
157
- events_should_be = [{
158
- kind: 'feature', key: 'feature1', user: user, variation: 1, value: 'e', default: nil, version: 2, prereqOf: 'feature0'
159
- }]
160
- get_flag = get_things({ 'feature1' => flag1 })
161
- e = subject.new(get_flag, get_nothing, logger)
162
- result = e.evaluate(flag, user, factory)
163
- expect(result.detail).to eq(detail)
164
- expect(result.events).to eq(events_should_be)
165
- end
166
-
167
- it "returns off variation and event if prerequisite is not met" do
168
- flag = {
169
- key: 'feature0',
170
- on: true,
171
- prerequisites: [{key: 'feature1', variation: 1}],
172
- fallthrough: { variation: 0 },
173
- offVariation: 1,
174
- variations: ['a', 'b', 'c'],
175
- version: 1
176
- }
177
- flag1 = {
178
- key: 'feature1',
179
- on: true,
180
- fallthrough: { variation: 0 },
181
- variations: ['d', 'e'],
182
- version: 2
183
- }
184
- user = { key: 'x' }
185
- detail = EvaluationDetail.new('b', 1, EvaluationReason::prerequisite_failed('feature1'))
186
- events_should_be = [{
187
- kind: 'feature', key: 'feature1', user: user, variation: 0, value: 'd', default: nil, version: 2, prereqOf: 'feature0'
188
- }]
189
- get_flag = get_things({ 'feature1' => flag1 })
190
- e = subject.new(get_flag, get_nothing, logger)
191
- result = e.evaluate(flag, user, factory)
192
- expect(result.detail).to eq(detail)
193
- expect(result.events).to eq(events_should_be)
194
- end
195
-
196
- it "returns fallthrough variation and event if prerequisite is met and there are no rules" do
197
- flag = {
198
- key: 'feature0',
199
- on: true,
200
- prerequisites: [{key: 'feature1', variation: 1}],
201
- fallthrough: { variation: 0 },
202
- offVariation: 1,
203
- variations: ['a', 'b', 'c'],
204
- version: 1
205
- }
206
- flag1 = {
207
- key: 'feature1',
208
- on: true,
209
- fallthrough: { variation: 1 },
210
- variations: ['d', 'e'],
211
- version: 2
212
- }
213
- user = { key: 'x' }
214
- detail = EvaluationDetail.new('a', 0, EvaluationReason::fallthrough)
215
- events_should_be = [{
216
- kind: 'feature', key: 'feature1', user: user, variation: 1, value: 'e', default: nil, version: 2, prereqOf: 'feature0'
217
- }]
218
- get_flag = get_things({ 'feature1' => flag1 })
219
- e = subject.new(get_flag, get_nothing, logger)
220
- result = e.evaluate(flag, user, factory)
221
- expect(result.detail).to eq(detail)
222
- expect(result.events).to eq(events_should_be)
223
- end
224
-
225
- it "returns an error if fallthrough variation is too high" do
226
- flag = {
227
- key: 'feature',
228
- on: true,
229
- fallthrough: { variation: 999 },
230
- offVariation: 1,
231
- variations: ['a', 'b', 'c']
232
- }
233
- user = { key: 'userkey' }
234
- detail = EvaluationDetail.new(nil, nil, EvaluationReason::error(EvaluationReason::ERROR_MALFORMED_FLAG))
235
- result = basic_evaluator.evaluate(flag, user, factory)
236
- expect(result.detail).to eq(detail)
237
- expect(result.events).to eq(nil)
238
- end
239
-
240
- it "returns an error if fallthrough variation is negative" do
241
- flag = {
242
- key: 'feature',
243
- on: true,
244
- fallthrough: { variation: -1 },
245
- offVariation: 1,
246
- variations: ['a', 'b', 'c']
247
- }
248
- user = { key: 'userkey' }
249
- detail = EvaluationDetail.new(nil, nil, EvaluationReason::error(EvaluationReason::ERROR_MALFORMED_FLAG))
250
- result = basic_evaluator.evaluate(flag, user, factory)
251
- expect(result.detail).to eq(detail)
252
- expect(result.events).to eq(nil)
253
- end
254
-
255
- it "returns an error if fallthrough has no variation or rollout" do
256
- flag = {
257
- key: 'feature',
258
- on: true,
259
- fallthrough: { },
260
- offVariation: 1,
261
- variations: ['a', 'b', 'c']
262
- }
263
- user = { key: 'userkey' }
264
- detail = EvaluationDetail.new(nil, nil, EvaluationReason::error(EvaluationReason::ERROR_MALFORMED_FLAG))
265
- result = basic_evaluator.evaluate(flag, user, factory)
266
- expect(result.detail).to eq(detail)
267
- expect(result.events).to eq(nil)
268
- end
269
-
270
- it "returns an error if fallthrough has a rollout with no variations" do
271
- flag = {
272
- key: 'feature',
273
- on: true,
274
- fallthrough: { rollout: { variations: [] } },
275
- offVariation: 1,
276
- variations: ['a', 'b', 'c']
277
- }
278
- user = { key: 'userkey' }
279
- detail = EvaluationDetail.new(nil, nil, EvaluationReason::error(EvaluationReason::ERROR_MALFORMED_FLAG))
280
- result = basic_evaluator.evaluate(flag, user, factory)
281
- expect(result.detail).to eq(detail)
282
- expect(result.events).to eq(nil)
283
- end
284
-
285
- it "matches user from targets" do
286
- flag = {
287
- key: 'feature',
288
- on: true,
289
- targets: [
290
- { values: [ 'whoever', 'userkey' ], variation: 2 }
291
- ],
292
- fallthrough: { variation: 0 },
293
- offVariation: 1,
294
- variations: ['a', 'b', 'c']
295
- }
296
- user = { key: 'userkey' }
297
- detail = EvaluationDetail.new('c', 2, EvaluationReason::target_match)
298
- result = basic_evaluator.evaluate(flag, user, factory)
299
- expect(result.detail).to eq(detail)
300
- expect(result.events).to eq(nil)
301
- end
302
-
303
- describe "experiment rollout behavior" do
304
- it "sets the in_experiment value if rollout kind is experiment and untracked false" do
305
- flag = {
306
- key: 'feature',
307
- on: true,
308
- fallthrough: { rollout: { kind: 'experiment', variations: [ { weight: 100000, variation: 1, untracked: false } ] } },
309
- offVariation: 1,
310
- variations: ['a', 'b', 'c']
311
- }
312
- user = { key: 'userkey' }
313
- result = basic_evaluator.evaluate(flag, user, factory)
314
- expect(result.detail.reason.to_json).to include('"inExperiment":true')
315
- expect(result.detail.reason.in_experiment).to eq(true)
316
- end
317
-
318
- it "does not set the in_experiment value if rollout kind is not experiment" do
319
- flag = {
320
- key: 'feature',
321
- on: true,
322
- fallthrough: { rollout: { kind: 'rollout', variations: [ { weight: 100000, variation: 1, untracked: false } ] } },
323
- offVariation: 1,
324
- variations: ['a', 'b', 'c']
325
- }
326
- user = { key: 'userkey' }
327
- result = basic_evaluator.evaluate(flag, user, factory)
328
- expect(result.detail.reason.to_json).to_not include('"inExperiment":true')
329
- expect(result.detail.reason.in_experiment).to eq(nil)
330
- end
331
-
332
- it "does not set the in_experiment value if rollout kind is experiment and untracked is true" do
333
- flag = {
334
- key: 'feature',
335
- on: true,
336
- fallthrough: { rollout: { kind: 'experiment', variations: [ { weight: 100000, variation: 1, untracked: true } ] } },
337
- offVariation: 1,
338
- variations: ['a', 'b', 'c']
339
- }
340
- user = { key: 'userkey' }
341
- result = basic_evaluator.evaluate(flag, user, factory)
342
- expect(result.detail.reason.to_json).to_not include('"inExperiment":true')
343
- expect(result.detail.reason.in_experiment).to eq(nil)
344
- end
345
- end
346
- end
347
- end
348
- end
349
- end
@@ -1,75 +0,0 @@
1
- require "spec_helper"
2
-
3
- module LaunchDarkly
4
- module Impl
5
- module EvaluatorSpecBase
6
- def factory
7
- EventFactory.new(false)
8
- end
9
-
10
- def user
11
- {
12
- key: "userkey",
13
- email: "test@example.com",
14
- name: "Bob"
15
- }
16
- end
17
-
18
- def logger
19
- ::Logger.new($stdout, level: ::Logger::FATAL)
20
- end
21
-
22
- def get_nothing
23
- lambda { |key| raise "should not have requested #{key}" }
24
- end
25
-
26
- def get_things(map)
27
- lambda { |key|
28
- raise "should not have requested #{key}" if !map.has_key?(key)
29
- map[key]
30
- }
31
- end
32
-
33
- def basic_evaluator
34
- subject.new(get_nothing, get_nothing, logger)
35
- end
36
-
37
- def boolean_flag_with_rules(rules)
38
- { key: 'feature', on: true, rules: rules, fallthrough: { variation: 0 }, variations: [ false, true ] }
39
- end
40
-
41
- def boolean_flag_with_clauses(clauses)
42
- boolean_flag_with_rules([{ id: 'ruleid', clauses: clauses, variation: 1 }])
43
- end
44
-
45
- def make_user_matching_clause(user, attr)
46
- {
47
- attribute: attr.to_s,
48
- op: :in,
49
- values: [ user[attr.to_sym] ],
50
- negate: false
51
- }
52
- end
53
-
54
- def make_segment(key)
55
- {
56
- key: key,
57
- included: [],
58
- excluded: [],
59
- salt: 'abcdef',
60
- version: 1
61
- }
62
- end
63
-
64
- def make_segment_match_clause(segment)
65
- {
66
- op: :segmentMatch,
67
- values: [ segment[:key] ],
68
- negate: false
69
- }
70
- end
71
- end
72
-
73
- RSpec.configure { |c| c.include EvaluatorSpecBase, :evaluator_spec_base => true }
74
- end
75
- end
@@ -1,108 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe LaunchDarkly::Impl::EventFactory do
4
- subject { LaunchDarkly::Impl::EventFactory }
5
-
6
- describe "#new_eval_event" do
7
- let(:event_factory_without_reason) { subject.new(false) }
8
- let(:user) { { 'key': 'userA' } }
9
- let(:rule_with_experiment_rollout) {
10
- { id: 'ruleid',
11
- clauses: [{ attribute: 'key', op: 'in', values: ['userkey'] }],
12
- trackEvents: false,
13
- rollout: { kind: 'experiment', salt: '', variations: [ { weight: 100000, variation: 0, untracked: false } ] }
14
- }
15
- }
16
-
17
- let(:rule_with_rollout) {
18
- { id: 'ruleid',
19
- trackEvents: false,
20
- clauses: [{ attribute: 'key', op: 'in', values: ['userkey'] }],
21
- rollout: { salt: '', variations: [ { weight: 100000, variation: 0, untracked: false } ] }
22
- }
23
- }
24
-
25
- let(:fallthrough_with_rollout) {
26
- { rollout: { kind: 'rollout', salt: '', variations: [ { weight: 100000, variation: 0, untracked: false } ], trackEventsFallthrough: false } }
27
- }
28
-
29
- let(:rule_reason) { LaunchDarkly::EvaluationReason::rule_match(0, 'ruleid') }
30
- let(:rule_reason_with_experiment) { LaunchDarkly::EvaluationReason::rule_match(0, 'ruleid', true) }
31
- let(:fallthrough_reason) { LaunchDarkly::EvaluationReason::fallthrough }
32
- let(:fallthrough_reason_with_experiment) { LaunchDarkly::EvaluationReason::fallthrough(true) }
33
-
34
- context "in_experiment is true" do
35
- it "sets the reason and trackevents: true for rules" do
36
- flag = createFlag('rule', rule_with_experiment_rollout)
37
- detail = LaunchDarkly::EvaluationDetail.new(true, 0, rule_reason_with_experiment)
38
- r = subject.new(false).new_eval_event(flag, user, detail, nil, nil)
39
- expect(r[:trackEvents]).to eql(true)
40
- expect(r[:reason].to_s).to eql("RULE_MATCH(0,ruleid,true)")
41
- end
42
-
43
- it "sets the reason and trackevents: true for the fallthrough" do
44
- fallthrough_with_rollout[:kind] = 'experiment'
45
- flag = createFlag('fallthrough', fallthrough_with_rollout)
46
- detail = LaunchDarkly::EvaluationDetail.new(true, 0, fallthrough_reason_with_experiment)
47
- r = subject.new(false).new_eval_event(flag, user, detail, nil, nil)
48
- expect(r[:trackEvents]).to eql(true)
49
- expect(r[:reason].to_s).to eql("FALLTHROUGH(true)")
50
- end
51
- end
52
-
53
- context "in_experiment is false" do
54
- it "sets the reason & trackEvents: true if rule has trackEvents set to true" do
55
- rule_with_rollout[:trackEvents] = true
56
- flag = createFlag('rule', rule_with_rollout)
57
- detail = LaunchDarkly::EvaluationDetail.new(true, 0, rule_reason)
58
- r = subject.new(false).new_eval_event(flag, user, detail, nil, nil)
59
- expect(r[:trackEvents]).to eql(true)
60
- expect(r[:reason].to_s).to eql("RULE_MATCH(0,ruleid)")
61
- end
62
-
63
- it "sets the reason & trackEvents: true if fallthrough has trackEventsFallthrough set to true" do
64
- flag = createFlag('fallthrough', fallthrough_with_rollout)
65
- flag[:trackEventsFallthrough] = true
66
- detail = LaunchDarkly::EvaluationDetail.new(true, 0, fallthrough_reason)
67
- r = subject.new(false).new_eval_event(flag, user, detail, nil, nil)
68
- expect(r[:trackEvents]).to eql(true)
69
- expect(r[:reason].to_s).to eql("FALLTHROUGH")
70
- end
71
-
72
- it "doesn't set the reason & trackEvents if rule has trackEvents set to false" do
73
- flag = createFlag('rule', rule_with_rollout)
74
- detail = LaunchDarkly::EvaluationDetail.new(true, 0, rule_reason)
75
- r = subject.new(false).new_eval_event(flag, user, detail, nil, nil)
76
- expect(r[:trackEvents]).to be_nil
77
- expect(r[:reason]).to be_nil
78
- end
79
-
80
- it "doesn't set the reason & trackEvents if fallthrough has trackEventsFallthrough set to false" do
81
- flag = createFlag('fallthrough', fallthrough_with_rollout)
82
- detail = LaunchDarkly::EvaluationDetail.new(true, 0, fallthrough_reason)
83
- r = subject.new(false).new_eval_event(flag, user, detail, nil, nil)
84
- expect(r[:trackEvents]).to be_nil
85
- expect(r[:reason]).to be_nil
86
- end
87
-
88
- it "sets trackEvents true and doesn't set the reason if flag[:trackEvents] = true" do
89
- flag = createFlag('fallthrough', fallthrough_with_rollout)
90
- flag[:trackEvents] = true
91
- detail = LaunchDarkly::EvaluationDetail.new(true, 0, fallthrough_reason)
92
- r = subject.new(false).new_eval_event(flag, user, detail, nil, nil)
93
- expect(r[:trackEvents]).to eql(true)
94
- expect(r[:reason]).to be_nil
95
- end
96
- end
97
- end
98
-
99
- def createFlag(kind, rule)
100
- if kind == 'rule'
101
- { key: 'feature', on: true, rules: [rule], fallthrough: { variation: 0 }, variations: [ false, true ] }
102
- elsif kind == 'fallthrough'
103
- { key: 'feature', on: true, fallthrough: rule, variations: [ false, true ] }
104
- else
105
- { key: 'feature', on: true, fallthrough: { variation: 0 }, variations: [ false, true ] }
106
- end
107
- end
108
- end