ldclient-rb 3.0.3 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,76 @@
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
@@ -32,5 +32,6 @@
32
32
  true,
33
33
  false
34
34
  ],
35
+ "trackEvents": true,
35
36
  "deleted":false
36
37
  }
@@ -3,7 +3,12 @@ require "spec_helper"
3
3
 
4
4
  describe LaunchDarkly::LDClient do
5
5
  subject { LaunchDarkly::LDClient }
6
- let(:config) { LaunchDarkly::Config.new({offline: true}) }
6
+ let(:offline_config) { LaunchDarkly::Config.new({offline: true}) }
7
+ let(:offline_client) do
8
+ subject.new("secret", offline_config)
9
+ end
10
+ let(:update_processor) { NullUpdateProcessor.new }
11
+ let(:config) { LaunchDarkly::Config.new({send_events: false, update_processor: update_processor}) }
7
12
  let(:client) do
8
13
  subject.new("secret", config)
9
14
  end
@@ -24,11 +29,74 @@ describe LaunchDarkly::LDClient do
24
29
  JSON.parse(data, symbolize_names: true)
25
30
  end
26
31
 
32
+ def event_processor
33
+ client.instance_variable_get(:@event_processor)
34
+ end
35
+
27
36
  describe '#variation' do
28
37
  it "will return the default value if the client is offline" do
29
- result = client.variation(feature[:key], user, "default")
38
+ result = offline_client.variation("doesntmatter", user, "default")
30
39
  expect(result).to eq "default"
31
40
  end
41
+
42
+ it "queues a feature request event for an unknown feature" do
43
+ expect(event_processor).to receive(:add_event).with(hash_including(
44
+ kind: "feature", key: "badkey", user: user, value: "default", default: "default"
45
+ ))
46
+ client.variation("badkey", user, "default")
47
+ end
48
+
49
+ it "queues a feature request event for an existing feature" do
50
+ config.feature_store.init({ LaunchDarkly::FEATURES => {} })
51
+ config.feature_store.upsert(LaunchDarkly::FEATURES, feature)
52
+ expect(event_processor).to receive(:add_event).with(hash_including(
53
+ kind: "feature",
54
+ key: feature[:key],
55
+ version: feature[:version],
56
+ user: user,
57
+ variation: 0,
58
+ value: true,
59
+ default: "default",
60
+ trackEvents: true,
61
+ debugEventsUntilDate: nil
62
+ ))
63
+ client.variation(feature[:key], user, "default")
64
+ end
65
+
66
+ it "queues a feature event for an existing feature when user is nil" do
67
+ config.feature_store.init({ LaunchDarkly::FEATURES => {} })
68
+ config.feature_store.upsert(LaunchDarkly::FEATURES, feature)
69
+ expect(event_processor).to receive(:add_event).with(hash_including(
70
+ kind: "feature",
71
+ key: feature[:key],
72
+ version: feature[:version],
73
+ user: nil,
74
+ variation: nil,
75
+ value: "default",
76
+ default: "default",
77
+ trackEvents: true,
78
+ debugEventsUntilDate: nil
79
+ ))
80
+ client.variation(feature[:key], nil, "default")
81
+ end
82
+
83
+ it "queues a feature event for an existing feature when user key is nil" do
84
+ config.feature_store.init({ LaunchDarkly::FEATURES => {} })
85
+ config.feature_store.upsert(LaunchDarkly::FEATURES, feature)
86
+ bad_user = { name: "Bob" }
87
+ expect(event_processor).to receive(:add_event).with(hash_including(
88
+ kind: "feature",
89
+ key: feature[:key],
90
+ version: feature[:version],
91
+ user: bad_user,
92
+ variation: nil,
93
+ value: "default",
94
+ default: "default",
95
+ trackEvents: true,
96
+ debugEventsUntilDate: nil
97
+ ))
98
+ client.variation(feature[:key], bad_user, "default")
99
+ end
32
100
  end
33
101
 
34
102
  describe '#secure_mode_hash' do
@@ -40,22 +108,24 @@ describe LaunchDarkly::LDClient do
40
108
 
41
109
  describe '#track' do
42
110
  it "queues up an custom event" do
43
- expect(client.instance_variable_get(:@event_processor)).to receive(:add_event).with(hash_including(kind: "custom", key: "custom_event_name", user: user, data: 42))
111
+ expect(event_processor).to receive(:add_event).with(hash_including(kind: "custom", key: "custom_event_name", user: user, data: 42))
44
112
  client.track("custom_event_name", user, 42)
45
113
  end
114
+
46
115
  it "sanitizes the user in the event" do
47
- expect(client.instance_variable_get(:@event_processor)).to receive(:add_event).with(hash_including(user: sanitized_numeric_key_user))
116
+ expect(event_processor).to receive(:add_event).with(hash_including(user: sanitized_numeric_key_user))
48
117
  client.track("custom_event_name", numeric_key_user, nil)
49
118
  end
50
119
  end
51
120
 
52
121
  describe '#identify' do
53
122
  it "queues up an identify event" do
54
- expect(client.instance_variable_get(:@event_processor)).to receive(:add_event).with(hash_including(kind: "identify", key: user[:key], user: user))
123
+ expect(event_processor).to receive(:add_event).with(hash_including(kind: "identify", key: user[:key], user: user))
55
124
  client.identify(user)
56
125
  end
126
+
57
127
  it "sanitizes the user in the event" do
58
- expect(client.instance_variable_get(:@event_processor)).to receive(:add_event).with(hash_including(user: sanitized_numeric_key_user))
128
+ expect(event_processor).to receive(:add_event).with(hash_including(user: sanitized_numeric_key_user))
59
129
  client.identify(numeric_key_user)
60
130
  end
61
131
  end
@@ -72,24 +142,31 @@ describe LaunchDarkly::LDClient do
72
142
  end
73
143
 
74
144
  describe 'with send_events: false' do
75
- let(:config) { LaunchDarkly::Config.new({offline: true, send_events: false}) }
145
+ let(:config) { LaunchDarkly::Config.new({offline: true, send_events: false, update_processor: update_processor}) }
76
146
  let(:client) { subject.new("secret", config) }
77
147
 
78
- let(:queue) { client.instance_variable_get(:@event_processor).instance_variable_get(:@queue) }
148
+ it "uses a NullEventProcessor" do
149
+ ep = client.instance_variable_get(:@event_processor)
150
+ expect(ep).to be_a(LaunchDarkly::NullEventProcessor)
151
+ end
152
+ end
153
+
154
+ describe 'with send_events: true' do
155
+ let(:config_with_events) { LaunchDarkly::Config.new({offline: false, send_events: true, update_processor: update_processor}) }
156
+ let(:client_with_events) { subject.new("secret", config_with_events) }
79
157
 
80
- it "does not enqueue a feature event" do
81
- client.variation(feature[:key], user, "default")
82
- expect(queue.empty?).to be true
158
+ it "does not use a NullEventProcessor" do
159
+ ep = client_with_events.instance_variable_get(:@event_processor)
160
+ expect(ep).not_to be_a(LaunchDarkly::NullEventProcessor)
83
161
  end
162
+ end
84
163
 
85
- it "does not enqueue a custom event" do
86
- client.track("custom_event_name", user, 42)
87
- expect(queue.empty?).to be true
164
+ class NullUpdateProcessor
165
+ def start
88
166
  end
89
167
 
90
- it "does not enqueue an identify event" do
91
- client.identify(user)
92
- expect(queue.empty?).to be true
168
+ def initialized?
169
+ true
93
170
  end
94
171
  end
95
172
  end
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+
3
+ describe LaunchDarkly::SimpleLRUCacheSet do
4
+ subject { LaunchDarkly::SimpleLRUCacheSet }
5
+
6
+ it "retains values up to capacity" do
7
+ lru = subject.new(3)
8
+ expect(lru.add("a")).to be false
9
+ expect(lru.add("b")).to be false
10
+ expect(lru.add("c")).to be false
11
+ expect(lru.add("a")).to be true
12
+ expect(lru.add("b")).to be true
13
+ expect(lru.add("c")).to be true
14
+ end
15
+
16
+ it "discards oldest value on overflow" do
17
+ lru = subject.new(2)
18
+ expect(lru.add("a")).to be false
19
+ expect(lru.add("b")).to be false
20
+ expect(lru.add("a")).to be true
21
+ expect(lru.add("c")).to be false # b is discarded as oldest
22
+ expect(lru.add("b")).to be false
23
+ end
24
+ end
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
- describe LaunchDarkly::EventSerializer do
4
- subject { LaunchDarkly::EventSerializer }
3
+ describe LaunchDarkly::UserFilter do
4
+ subject { LaunchDarkly::UserFilter }
5
5
 
6
6
  let(:base_config) { LaunchDarkly::Config.new }
7
7
  let(:config_with_all_attrs_private) { LaunchDarkly::Config.new({ all_attributes_private: true })}
@@ -45,68 +45,47 @@ describe LaunchDarkly::EventSerializer do
45
45
  { key: 'abc', anonymous: 'true', custom: { }, privateAttrs: [ 'bizzle', 'dizzle' ]}
46
46
  }
47
47
 
48
-
49
- def make_event(user)
50
- {
51
- creationDate: 1000000,
52
- key: 'xyz',
53
- kind: 'thing',
54
- user: user
55
- }
56
- end
57
-
58
- def parse_results(js)
59
- JSON.parse(js, symbolize_names: true)
60
- end
61
-
62
48
  describe "serialize_events" do
63
49
  it "includes all user attributes by default" do
64
- es = LaunchDarkly::EventSerializer.new(base_config)
65
- event = make_event(user)
66
- j = es.serialize_events([event])
67
- expect(parse_results(j)).to eq [event]
50
+ uf = LaunchDarkly::UserFilter.new(base_config)
51
+ result = uf.transform_user_props(user)
52
+ expect(result).to eq user
68
53
  end
69
54
 
70
55
  it "hides all except key if all_attributes_private is true" do
71
- es = LaunchDarkly::EventSerializer.new(config_with_all_attrs_private)
72
- event = make_event(user)
73
- j = es.serialize_events([event])
74
- expect(parse_results(j)).to eq [make_event(user_with_all_attrs_hidden)]
56
+ uf = LaunchDarkly::UserFilter.new(config_with_all_attrs_private)
57
+ result = uf.transform_user_props(user)
58
+ expect(result).to eq user_with_all_attrs_hidden
75
59
  end
76
60
 
77
61
  it "hides some attributes if private_attribute_names is set" do
78
- es = LaunchDarkly::EventSerializer.new(config_with_some_attrs_private)
79
- event = make_event(user)
80
- j = es.serialize_events([event])
81
- expect(parse_results(j)).to eq [make_event(user_with_some_attrs_hidden)]
62
+ uf = LaunchDarkly::UserFilter.new(config_with_some_attrs_private)
63
+ result = uf.transform_user_props(user)
64
+ expect(result).to eq user_with_some_attrs_hidden
82
65
  end
83
66
 
84
67
  it "hides attributes specified in per-user privateAttrs" do
85
- es = LaunchDarkly::EventSerializer.new(base_config)
86
- event = make_event(user_specifying_own_private_attr)
87
- j = es.serialize_events([event])
88
- expect(parse_results(j)).to eq [make_event(user_with_own_specified_attr_hidden)]
68
+ uf = LaunchDarkly::UserFilter.new(base_config)
69
+ result = uf.transform_user_props(user_specifying_own_private_attr)
70
+ expect(result).to eq user_with_own_specified_attr_hidden
89
71
  end
90
72
 
91
73
  it "looks at both per-user privateAttrs and global config" do
92
- es = LaunchDarkly::EventSerializer.new(config_with_some_attrs_private)
93
- event = make_event(user_specifying_own_private_attr)
94
- j = es.serialize_events([event])
95
- expect(parse_results(j)).to eq [make_event(user_with_all_attrs_hidden)]
74
+ uf = LaunchDarkly::UserFilter.new(config_with_some_attrs_private)
75
+ result = uf.transform_user_props(user_specifying_own_private_attr)
76
+ expect(result).to eq user_with_all_attrs_hidden
96
77
  end
97
78
 
98
79
  it "strips out any unknown top-level attributes" do
99
- es = LaunchDarkly::EventSerializer.new(base_config)
100
- event = make_event(user_with_unknown_top_level_attrs)
101
- j = es.serialize_events([event])
102
- expect(parse_results(j)).to eq [make_event(user)]
80
+ uf = LaunchDarkly::UserFilter.new(base_config)
81
+ result = uf.transform_user_props(user_with_unknown_top_level_attrs)
82
+ expect(result).to eq user
103
83
  end
104
84
 
105
85
  it "leaves the anonymous attribute as is" do
106
- es = LaunchDarkly::EventSerializer.new(config_with_all_attrs_private)
107
- event = make_event(anon_user)
108
- j = es.serialize_events([event])
109
- expect(parse_results(j)).to eq [make_event(anon_user_with_all_attrs_hidden)]
86
+ uf = LaunchDarkly::UserFilter.new(config_with_all_attrs_private)
87
+ result = uf.transform_user_props(anon_user)
88
+ expect(result).to eq anon_user_with_all_attrs_hidden
110
89
  end
111
90
  end
112
91
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ldclient-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - LaunchDarkly
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-23 00:00:00.000000000 Z
11
+ date: 2018-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.7'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '10.0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rspec
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -95,19 +81,47 @@ dependencies:
95
81
  - !ruby/object:Gem::Version
96
82
  version: 2.1.2
97
83
  - !ruby/object:Gem::Dependency
98
- name: moneta
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec_junit_formatter
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.3.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.3.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: timecop
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: 1.0.0
117
+ version: 0.9.1
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: 1.0.0
124
+ version: 0.9.1
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: json
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -302,6 +316,7 @@ extensions:
302
316
  - ext/mkrf_conf.rb
303
317
  extra_rdoc_files: []
304
318
  files:
319
+ - ".circleci/config.yml"
305
320
  - ".gitignore"
306
321
  - ".hound.yml"
307
322
  - ".rspec"
@@ -314,28 +329,33 @@ files:
314
329
  - LICENSE.txt
315
330
  - README.md
316
331
  - Rakefile
317
- - circle.yml
318
332
  - ext/mkrf_conf.rb
319
333
  - ldclient-rb.gemspec
320
334
  - lib/ldclient-rb.rb
321
335
  - lib/ldclient-rb/cache_store.rb
322
336
  - lib/ldclient-rb/config.rb
323
337
  - lib/ldclient-rb/evaluation.rb
324
- - lib/ldclient-rb/event_serializer.rb
338
+ - lib/ldclient-rb/event_summarizer.rb
325
339
  - lib/ldclient-rb/events.rb
340
+ - lib/ldclient-rb/expiring_cache.rb
326
341
  - lib/ldclient-rb/in_memory_store.rb
327
342
  - lib/ldclient-rb/ldclient.rb
328
343
  - lib/ldclient-rb/memoized_value.rb
329
344
  - lib/ldclient-rb/newrelic.rb
345
+ - lib/ldclient-rb/non_blocking_thread_pool.rb
330
346
  - lib/ldclient-rb/polling.rb
331
347
  - lib/ldclient-rb/redis_store.rb
332
348
  - lib/ldclient-rb/requestor.rb
349
+ - lib/ldclient-rb/simple_lru_cache.rb
333
350
  - lib/ldclient-rb/stream.rb
351
+ - lib/ldclient-rb/user_filter.rb
334
352
  - lib/ldclient-rb/version.rb
335
353
  - scripts/release.sh
336
354
  - spec/config_spec.rb
337
355
  - spec/evaluation_spec.rb
338
- - spec/event_serializer_spec.rb
356
+ - spec/event_summarizer_spec.rb
357
+ - spec/events_spec.rb
358
+ - spec/expiring_cache_spec.rb
339
359
  - spec/feature_store_spec_base.rb
340
360
  - spec/fixtures/feature.json
341
361
  - spec/fixtures/feature1.json
@@ -348,9 +368,11 @@ files:
348
368
  - spec/redis_feature_store_spec.rb
349
369
  - spec/requestor_spec.rb
350
370
  - spec/segment_store_spec_base.rb
371
+ - spec/simple_lru_cache_spec.rb
351
372
  - spec/spec_helper.rb
352
373
  - spec/store_spec.rb
353
374
  - spec/stream_spec.rb
375
+ - spec/user_filter_spec.rb
354
376
  - spec/version_spec.rb
355
377
  homepage: https://github.com/launchdarkly/ruby-client
356
378
  licenses:
@@ -379,7 +401,9 @@ summary: LaunchDarkly SDK for Ruby
379
401
  test_files:
380
402
  - spec/config_spec.rb
381
403
  - spec/evaluation_spec.rb
382
- - spec/event_serializer_spec.rb
404
+ - spec/event_summarizer_spec.rb
405
+ - spec/events_spec.rb
406
+ - spec/expiring_cache_spec.rb
383
407
  - spec/feature_store_spec_base.rb
384
408
  - spec/fixtures/feature.json
385
409
  - spec/fixtures/feature1.json
@@ -392,7 +416,9 @@ test_files:
392
416
  - spec/redis_feature_store_spec.rb
393
417
  - spec/requestor_spec.rb
394
418
  - spec/segment_store_spec_base.rb
419
+ - spec/simple_lru_cache_spec.rb
395
420
  - spec/spec_helper.rb
396
421
  - spec/store_spec.rb
397
422
  - spec/stream_spec.rb
423
+ - spec/user_filter_spec.rb
398
424
  - spec/version_spec.rb