launchdarkly-server-sdk 6.1.1 → 6.4.0

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -5
  3. data/lib/ldclient-rb/config.rb +118 -4
  4. data/lib/ldclient-rb/evaluation_detail.rb +104 -14
  5. data/lib/ldclient-rb/events.rb +201 -107
  6. data/lib/ldclient-rb/file_data_source.rb +9 -300
  7. data/lib/ldclient-rb/flags_state.rb +23 -12
  8. data/lib/ldclient-rb/impl/big_segments.rb +117 -0
  9. data/lib/ldclient-rb/impl/diagnostic_events.rb +1 -1
  10. data/lib/ldclient-rb/impl/evaluator.rb +116 -62
  11. data/lib/ldclient-rb/impl/evaluator_bucketing.rb +22 -9
  12. data/lib/ldclient-rb/impl/evaluator_helpers.rb +53 -0
  13. data/lib/ldclient-rb/impl/evaluator_operators.rb +1 -1
  14. data/lib/ldclient-rb/impl/event_summarizer.rb +63 -0
  15. data/lib/ldclient-rb/impl/event_types.rb +90 -0
  16. data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +82 -18
  17. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +212 -0
  18. data/lib/ldclient-rb/impl/integrations/redis_impl.rb +84 -31
  19. data/lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb +40 -0
  20. data/lib/ldclient-rb/impl/model/preprocessed_data.rb +177 -0
  21. data/lib/ldclient-rb/impl/model/serialization.rb +7 -37
  22. data/lib/ldclient-rb/impl/repeating_task.rb +47 -0
  23. data/lib/ldclient-rb/impl/util.rb +62 -1
  24. data/lib/ldclient-rb/integrations/consul.rb +8 -1
  25. data/lib/ldclient-rb/integrations/dynamodb.rb +48 -3
  26. data/lib/ldclient-rb/integrations/file_data.rb +108 -0
  27. data/lib/ldclient-rb/integrations/redis.rb +42 -2
  28. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +438 -0
  29. data/lib/ldclient-rb/integrations/test_data.rb +209 -0
  30. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +5 -0
  31. data/lib/ldclient-rb/integrations.rb +2 -51
  32. data/lib/ldclient-rb/interfaces.rb +152 -2
  33. data/lib/ldclient-rb/ldclient.rb +131 -33
  34. data/lib/ldclient-rb/polling.rb +22 -41
  35. data/lib/ldclient-rb/requestor.rb +3 -3
  36. data/lib/ldclient-rb/stream.rb +4 -3
  37. data/lib/ldclient-rb/util.rb +10 -1
  38. data/lib/ldclient-rb/version.rb +1 -1
  39. data/lib/ldclient-rb.rb +0 -1
  40. metadata +35 -132
  41. data/.circleci/config.yml +0 -40
  42. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -37
  43. data/.github/ISSUE_TEMPLATE/config.yml +0 -5
  44. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  45. data/.github/pull_request_template.md +0 -21
  46. data/.gitignore +0 -16
  47. data/.hound.yml +0 -2
  48. data/.ldrelease/build-docs.sh +0 -18
  49. data/.ldrelease/circleci/linux/execute.sh +0 -18
  50. data/.ldrelease/circleci/mac/execute.sh +0 -18
  51. data/.ldrelease/circleci/template/build.sh +0 -29
  52. data/.ldrelease/circleci/template/publish.sh +0 -23
  53. data/.ldrelease/circleci/template/set-gem-home.sh +0 -7
  54. data/.ldrelease/circleci/template/test.sh +0 -10
  55. data/.ldrelease/circleci/template/update-version.sh +0 -8
  56. data/.ldrelease/circleci/windows/execute.ps1 +0 -19
  57. data/.ldrelease/config.yml +0 -29
  58. data/.rspec +0 -2
  59. data/.rubocop.yml +0 -600
  60. data/.simplecov +0 -4
  61. data/CHANGELOG.md +0 -351
  62. data/CODEOWNERS +0 -1
  63. data/CONTRIBUTING.md +0 -37
  64. data/Gemfile +0 -3
  65. data/azure-pipelines.yml +0 -51
  66. data/docs/Makefile +0 -26
  67. data/docs/index.md +0 -9
  68. data/launchdarkly-server-sdk.gemspec +0 -45
  69. data/lib/ldclient-rb/event_summarizer.rb +0 -55
  70. data/lib/ldclient-rb/impl/event_factory.rb +0 -120
  71. data/spec/config_spec.rb +0 -63
  72. data/spec/diagnostic_events_spec.rb +0 -163
  73. data/spec/evaluation_detail_spec.rb +0 -135
  74. data/spec/event_sender_spec.rb +0 -197
  75. data/spec/event_summarizer_spec.rb +0 -63
  76. data/spec/events_spec.rb +0 -607
  77. data/spec/expiring_cache_spec.rb +0 -76
  78. data/spec/feature_store_spec_base.rb +0 -213
  79. data/spec/file_data_source_spec.rb +0 -283
  80. data/spec/fixtures/feature.json +0 -37
  81. data/spec/fixtures/feature1.json +0 -36
  82. data/spec/fixtures/user.json +0 -9
  83. data/spec/flags_state_spec.rb +0 -81
  84. data/spec/http_util.rb +0 -132
  85. data/spec/impl/evaluator_bucketing_spec.rb +0 -111
  86. data/spec/impl/evaluator_clause_spec.rb +0 -55
  87. data/spec/impl/evaluator_operators_spec.rb +0 -141
  88. data/spec/impl/evaluator_rule_spec.rb +0 -96
  89. data/spec/impl/evaluator_segment_spec.rb +0 -125
  90. data/spec/impl/evaluator_spec.rb +0 -305
  91. data/spec/impl/evaluator_spec_base.rb +0 -75
  92. data/spec/impl/model/serialization_spec.rb +0 -41
  93. data/spec/in_memory_feature_store_spec.rb +0 -12
  94. data/spec/integrations/consul_feature_store_spec.rb +0 -40
  95. data/spec/integrations/dynamodb_feature_store_spec.rb +0 -103
  96. data/spec/integrations/store_wrapper_spec.rb +0 -276
  97. data/spec/launchdarkly-server-sdk_spec.rb +0 -13
  98. data/spec/launchdarkly-server-sdk_spec_autoloadtest.rb +0 -9
  99. data/spec/ldclient_end_to_end_spec.rb +0 -157
  100. data/spec/ldclient_spec.rb +0 -643
  101. data/spec/newrelic_spec.rb +0 -5
  102. data/spec/polling_spec.rb +0 -120
  103. data/spec/redis_feature_store_spec.rb +0 -121
  104. data/spec/requestor_spec.rb +0 -196
  105. data/spec/segment_store_spec_base.rb +0 -95
  106. data/spec/simple_lru_cache_spec.rb +0 -24
  107. data/spec/spec_helper.rb +0 -9
  108. data/spec/store_spec.rb +0 -10
  109. data/spec/stream_spec.rb +0 -45
  110. data/spec/user_filter_spec.rb +0 -91
  111. data/spec/util_spec.rb +0 -17
  112. data/spec/version_spec.rb +0 -7
@@ -1,103 +0,0 @@
1
- require "feature_store_spec_base"
2
- require "aws-sdk-dynamodb"
3
- require "spec_helper"
4
-
5
-
6
- $table_name = 'LD_DYNAMODB_TEST_TABLE'
7
- $endpoint = 'http://localhost:8000'
8
- $my_prefix = 'testprefix'
9
-
10
- $dynamodb_opts = {
11
- credentials: Aws::Credentials.new("key", "secret"),
12
- region: "us-east-1",
13
- endpoint: $endpoint
14
- }
15
-
16
- $ddb_base_opts = {
17
- dynamodb_opts: $dynamodb_opts,
18
- prefix: $my_prefix,
19
- logger: $null_log
20
- }
21
-
22
- def create_dynamodb_store(opts = {})
23
- LaunchDarkly::Integrations::DynamoDB::new_feature_store($table_name,
24
- $ddb_base_opts.merge(opts).merge({ expiration: 60 }))
25
- end
26
-
27
- def create_dynamodb_store_uncached(opts = {})
28
- LaunchDarkly::Integrations::DynamoDB::new_feature_store($table_name,
29
- $ddb_base_opts.merge(opts).merge({ expiration: 0 }))
30
- end
31
-
32
- def clear_all_data
33
- client = create_test_client
34
- items_to_delete = []
35
- req = {
36
- table_name: $table_name,
37
- projection_expression: '#namespace, #key',
38
- expression_attribute_names: {
39
- '#namespace' => 'namespace',
40
- '#key' => 'key'
41
- }
42
- }
43
- while true
44
- resp = client.scan(req)
45
- items_to_delete = items_to_delete + resp.items
46
- break if resp.last_evaluated_key.nil? || resp.last_evaluated_key.length == 0
47
- req.exclusive_start_key = resp.last_evaluated_key
48
- end
49
- requests = items_to_delete.map do |item|
50
- { delete_request: { key: item } }
51
- end
52
- LaunchDarkly::Impl::Integrations::DynamoDB::DynamoDBUtil.batch_write_requests(client, $table_name, requests)
53
- end
54
-
55
- def create_table_if_necessary
56
- client = create_test_client
57
- begin
58
- client.describe_table({ table_name: $table_name })
59
- return # no error, table exists
60
- rescue Aws::DynamoDB::Errors::ResourceNotFoundException
61
- # fall through to code below - we'll create the table
62
- end
63
-
64
- req = {
65
- table_name: $table_name,
66
- key_schema: [
67
- { attribute_name: "namespace", key_type: "HASH" },
68
- { attribute_name: "key", key_type: "RANGE" }
69
- ],
70
- attribute_definitions: [
71
- { attribute_name: "namespace", attribute_type: "S" },
72
- { attribute_name: "key", attribute_type: "S" }
73
- ],
74
- provisioned_throughput: {
75
- read_capacity_units: 1,
76
- write_capacity_units: 1
77
- }
78
- }
79
- client.create_table(req)
80
-
81
- # When DynamoDB creates a table, it may not be ready to use immediately
82
- end
83
-
84
- def create_test_client
85
- Aws::DynamoDB::Client.new($dynamodb_opts)
86
- end
87
-
88
-
89
- describe "DynamoDB feature store" do
90
- break if ENV['LD_SKIP_DATABASE_TESTS'] == '1'
91
-
92
- # These tests will all fail if there isn't a local DynamoDB instance running.
93
-
94
- create_table_if_necessary
95
-
96
- context "with local cache" do
97
- include_examples "feature_store", method(:create_dynamodb_store), method(:clear_all_data)
98
- end
99
-
100
- context "without local cache" do
101
- include_examples "feature_store", method(:create_dynamodb_store_uncached), method(:clear_all_data)
102
- end
103
- end
@@ -1,276 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe LaunchDarkly::Integrations::Util::CachingStoreWrapper do
4
- subject { LaunchDarkly::Integrations::Util::CachingStoreWrapper }
5
-
6
- THINGS = { namespace: "things" }
7
-
8
- shared_examples "tests" do |cached|
9
- opts = cached ? { expiration: 30 } : { expiration: 0 }
10
-
11
- it "gets item" do
12
- core = MockCore.new
13
- wrapper = subject.new(core, opts)
14
- key = "flag"
15
- itemv1 = { key: key, version: 1 }
16
- itemv2 = { key: key, version: 2 }
17
-
18
- core.force_set(THINGS, itemv1)
19
- expect(wrapper.get(THINGS, key)).to eq itemv1
20
-
21
- core.force_set(THINGS, itemv2)
22
- expect(wrapper.get(THINGS, key)).to eq (cached ? itemv1 : itemv2) # if cached, we will not see the new underlying value yet
23
- end
24
-
25
- it "gets deleted item" do
26
- core = MockCore.new
27
- wrapper = subject.new(core, opts)
28
- key = "flag"
29
- itemv1 = { key: key, version: 1, deleted: true }
30
- itemv2 = { key: key, version: 2, deleted: false }
31
-
32
- core.force_set(THINGS, itemv1)
33
- expect(wrapper.get(THINGS, key)).to eq nil # item is filtered out because deleted is true
34
-
35
- core.force_set(THINGS, itemv2)
36
- expect(wrapper.get(THINGS, key)).to eq (cached ? nil : itemv2) # if cached, we will not see the new underlying value yet
37
- end
38
-
39
- it "gets missing item" do
40
- core = MockCore.new
41
- wrapper = subject.new(core, opts)
42
- key = "flag"
43
- item = { key: key, version: 1 }
44
-
45
- expect(wrapper.get(THINGS, key)).to eq nil
46
-
47
- core.force_set(THINGS, item)
48
- expect(wrapper.get(THINGS, key)).to eq (cached ? nil : item) # the cache can retain a nil result
49
- end
50
-
51
- it "gets all items" do
52
- core = MockCore.new
53
- wrapper = subject.new(core, opts)
54
- item1 = { key: "flag1", version: 1 }
55
- item2 = { key: "flag2", version: 1 }
56
-
57
- core.force_set(THINGS, item1)
58
- core.force_set(THINGS, item2)
59
- expect(wrapper.all(THINGS)).to eq({ item1[:key] => item1, item2[:key] => item2 })
60
-
61
- core.force_remove(THINGS, item2[:key])
62
- expect(wrapper.all(THINGS)).to eq (cached ?
63
- { item1[:key] => item1, item2[:key] => item2 } :
64
- { item1[:key] => item1 })
65
- end
66
-
67
- it "gets all items filtering out deleted items" do
68
- core = MockCore.new
69
- wrapper = subject.new(core, opts)
70
- item1 = { key: "flag1", version: 1 }
71
- item2 = { key: "flag2", version: 1, deleted: true }
72
-
73
- core.force_set(THINGS, item1)
74
- core.force_set(THINGS, item2)
75
- expect(wrapper.all(THINGS)).to eq({ item1[:key] => item1 })
76
- end
77
-
78
- it "upserts item successfully" do
79
- core = MockCore.new
80
- wrapper = subject.new(core, opts)
81
- key = "flag"
82
- itemv1 = { key: key, version: 1 }
83
- itemv2 = { key: key, version: 2 }
84
-
85
- wrapper.upsert(THINGS, itemv1)
86
- expect(core.data[THINGS][key]).to eq itemv1
87
-
88
- wrapper.upsert(THINGS, itemv2)
89
- expect(core.data[THINGS][key]).to eq itemv2
90
-
91
- # if we have a cache, verify that the new item is now cached by writing a different value
92
- # to the underlying data - Get should still return the cached item
93
- if cached
94
- itemv3 = { key: key, version: 3 }
95
- core.force_set(THINGS, itemv3)
96
- end
97
-
98
- expect(wrapper.get(THINGS, key)).to eq itemv2
99
- end
100
-
101
- it "deletes item" do
102
- core = MockCore.new
103
- wrapper = subject.new(core, opts)
104
- key = "flag"
105
- itemv1 = { key: key, version: 1 }
106
- itemv2 = { key: key, version: 2, deleted: true }
107
- itemv3 = { key: key, version: 3 }
108
-
109
- core.force_set(THINGS, itemv1)
110
- expect(wrapper.get(THINGS, key)).to eq itemv1
111
-
112
- wrapper.delete(THINGS, key, 2)
113
- expect(core.data[THINGS][key]).to eq itemv2
114
-
115
- core.force_set(THINGS, itemv3) # make a change that bypasses the cache
116
-
117
- expect(wrapper.get(THINGS, key)).to eq (cached ? nil : itemv3)
118
- end
119
- end
120
-
121
- context "cached" do
122
- include_examples "tests", true
123
-
124
- cached_opts = { expiration: 30 }
125
-
126
- it "get uses values from init" do
127
- core = MockCore.new
128
- wrapper = subject.new(core, cached_opts)
129
- item1 = { key: "flag1", version: 1 }
130
- item2 = { key: "flag2", version: 1 }
131
-
132
- wrapper.init({ THINGS => { item1[:key] => item1, item2[:key] => item2 } })
133
- core.force_remove(THINGS, item1[:key])
134
-
135
- expect(wrapper.get(THINGS, item1[:key])).to eq item1
136
- end
137
-
138
- it "get all uses values from init" do
139
- core = MockCore.new
140
- wrapper = subject.new(core, cached_opts)
141
- item1 = { key: "flag1", version: 1 }
142
- item2 = { key: "flag2", version: 1 }
143
-
144
- wrapper.init({ THINGS => { item1[:key] => item1, item2[:key] => item2 } })
145
- core.force_remove(THINGS, item1[:key])
146
-
147
- expect(wrapper.all(THINGS)).to eq ({ item1[:key] => item1, item2[:key] => item2 })
148
- end
149
-
150
- it "upsert doesn't update cache if unsuccessful" do
151
- # This is for an upsert where the data in the store has a higher version. In an uncached
152
- # store, this is just a no-op as far as the wrapper is concerned so there's nothing to
153
- # test here. In a cached store, we need to verify that the cache has been refreshed
154
- # using the data that was found in the store.
155
- core = MockCore.new
156
- wrapper = subject.new(core, cached_opts)
157
- key = "flag"
158
- itemv1 = { key: key, version: 1 }
159
- itemv2 = { key: key, version: 2 }
160
-
161
- wrapper.upsert(THINGS, itemv2)
162
- expect(core.data[THINGS][key]).to eq itemv2
163
-
164
- wrapper.upsert(THINGS, itemv1)
165
- expect(core.data[THINGS][key]).to eq itemv2 # value in store remains the same
166
-
167
- itemv3 = { key: key, version: 3 }
168
- core.force_set(THINGS, itemv3) # bypasses cache so we can verify that itemv2 is in the cache
169
- expect(wrapper.get(THINGS, key)).to eq itemv2
170
- end
171
-
172
- it "initialized? can cache false result" do
173
- core = MockCore.new
174
- wrapper = subject.new(core, { expiration: 0.2 }) # use a shorter cache TTL for this test
175
-
176
- expect(wrapper.initialized?).to eq false
177
- expect(core.inited_query_count).to eq 1
178
-
179
- core.inited = true
180
- expect(wrapper.initialized?).to eq false
181
- expect(core.inited_query_count).to eq 1
182
-
183
- sleep(0.5)
184
-
185
- expect(wrapper.initialized?).to eq true
186
- expect(core.inited_query_count).to eq 2
187
-
188
- # From this point on it should remain true and the method should not be called
189
- expect(wrapper.initialized?).to eq true
190
- expect(core.inited_query_count).to eq 2
191
- end
192
- end
193
-
194
- context "uncached" do
195
- include_examples "tests", false
196
-
197
- uncached_opts = { expiration: 0 }
198
-
199
- it "queries internal initialized state only if not already inited" do
200
- core = MockCore.new
201
- wrapper = subject.new(core, uncached_opts)
202
-
203
- expect(wrapper.initialized?).to eq false
204
- expect(core.inited_query_count).to eq 1
205
-
206
- core.inited = true
207
- expect(wrapper.initialized?).to eq true
208
- expect(core.inited_query_count).to eq 2
209
-
210
- core.inited = false
211
- expect(wrapper.initialized?).to eq true
212
- expect(core.inited_query_count).to eq 2
213
- end
214
-
215
- it "does not query internal initialized state if init has been called" do
216
- core = MockCore.new
217
- wrapper = subject.new(core, uncached_opts)
218
-
219
- expect(wrapper.initialized?).to eq false
220
- expect(core.inited_query_count).to eq 1
221
-
222
- wrapper.init({})
223
-
224
- expect(wrapper.initialized?).to eq true
225
- expect(core.inited_query_count).to eq 1
226
- end
227
- end
228
-
229
- class MockCore
230
- def initialize
231
- @data = {}
232
- @inited = false
233
- @inited_query_count = 0
234
- end
235
-
236
- attr_reader :data
237
- attr_reader :inited_query_count
238
- attr_accessor :inited
239
-
240
- def force_set(kind, item)
241
- @data[kind] = {} if !@data.has_key?(kind)
242
- @data[kind][item[:key]] = item
243
- end
244
-
245
- def force_remove(kind, key)
246
- @data[kind].delete(key) if @data.has_key?(kind)
247
- end
248
-
249
- def init_internal(all_data)
250
- @data = all_data
251
- @inited = true
252
- end
253
-
254
- def get_internal(kind, key)
255
- items = @data[kind]
256
- items.nil? ? nil : items[key]
257
- end
258
-
259
- def get_all_internal(kind)
260
- @data[kind]
261
- end
262
-
263
- def upsert_internal(kind, item)
264
- @data[kind] = {} if !@data.has_key?(kind)
265
- old_item = @data[kind][item[:key]]
266
- return old_item if !old_item.nil? && old_item[:version] >= item[:version]
267
- @data[kind][item[:key]] = item
268
- item
269
- end
270
-
271
- def initialized_internal?
272
- @inited_query_count = @inited_query_count + 1
273
- @inited
274
- end
275
- end
276
- end
@@ -1,13 +0,0 @@
1
- require "spec_helper"
2
- require "bundler"
3
-
4
- describe LaunchDarkly do
5
- it "can be automatically loaded by Bundler.require" do
6
- ldclient_loaded =
7
- Bundler.with_unbundled_env do
8
- Kernel.system("ruby", "./spec/launchdarkly-server-sdk_spec_autoloadtest.rb")
9
- end
10
-
11
- expect(ldclient_loaded).to be true
12
- end
13
- end
@@ -1,9 +0,0 @@
1
- require "bundler/setup"
2
- require "bundler/inline"
3
-
4
- gemfile do
5
- gem "launchdarkly-server-sdk", path: "."
6
- end
7
-
8
- Bundler.require(:development)
9
- abort unless $LOADED_FEATURES.any? { |file| file =~ /ldclient-rb\.rb/ }
@@ -1,157 +0,0 @@
1
- require "http_util"
2
- require "spec_helper"
3
-
4
-
5
- SDK_KEY = "sdk-key"
6
-
7
- USER = { key: 'userkey' }
8
-
9
- ALWAYS_TRUE_FLAG = { key: 'flagkey', version: 1, on: false, offVariation: 1, variations: [ false, true ] }
10
- DATA_WITH_ALWAYS_TRUE_FLAG = {
11
- flags: { ALWAYS_TRUE_FLAG[:key ].to_sym => ALWAYS_TRUE_FLAG },
12
- segments: {}
13
- }
14
- PUT_EVENT_WITH_ALWAYS_TRUE_FLAG = "event: put\ndata:{\"data\":#{DATA_WITH_ALWAYS_TRUE_FLAG.to_json}}\n\n'"
15
-
16
- def with_client(config)
17
- client = LaunchDarkly::LDClient.new(SDK_KEY, config)
18
- begin
19
- yield client
20
- ensure
21
- client.close
22
- end
23
- end
24
-
25
- module LaunchDarkly
26
- # Note that we can't do end-to-end tests in streaming mode until we have a test server that can do streaming
27
- # responses, which is difficult in WEBrick.
28
-
29
- describe "LDClient end-to-end" do
30
- it "starts in polling mode" do
31
- with_server do |poll_server|
32
- poll_server.setup_ok_response("/sdk/latest-all", DATA_WITH_ALWAYS_TRUE_FLAG.to_json, "application/json")
33
-
34
- config = Config.new(
35
- stream: false,
36
- base_uri: poll_server.base_uri.to_s,
37
- send_events: false,
38
- logger: NullLogger.new
39
- )
40
- with_client(config) do |client|
41
- expect(client.initialized?).to be true
42
- expect(client.variation(ALWAYS_TRUE_FLAG[:key], USER, false)).to be true
43
- end
44
- end
45
- end
46
-
47
- it "fails in polling mode with 401 error" do
48
- with_server do |poll_server|
49
- poll_server.setup_status_response("/sdk/latest-all", 401)
50
-
51
- config = Config.new(
52
- stream: false,
53
- base_uri: poll_server.base_uri.to_s,
54
- send_events: false,
55
- logger: NullLogger.new
56
- )
57
- with_client(config) do |client|
58
- expect(client.initialized?).to be false
59
- expect(client.variation(ALWAYS_TRUE_FLAG[:key], USER, false)).to be false
60
- end
61
- end
62
- end
63
-
64
- it "sends event without diagnostics" do
65
- with_server do |poll_server|
66
- with_server do |events_server|
67
- events_server.setup_ok_response("/bulk", "")
68
- poll_server.setup_ok_response("/sdk/latest-all", '{"flags":{},"segments":{}}', "application/json")
69
-
70
- config = Config.new(
71
- stream: false,
72
- base_uri: poll_server.base_uri.to_s,
73
- events_uri: events_server.base_uri.to_s,
74
- diagnostic_opt_out: true,
75
- logger: NullLogger.new
76
- )
77
- with_client(config) do |client|
78
- client.identify(USER)
79
- client.flush
80
-
81
- req, body = events_server.await_request_with_body
82
- expect(req.header['authorization']).to eq [ SDK_KEY ]
83
- expect(req.header['connection']).to eq [ "Keep-Alive" ]
84
- data = JSON.parse(body)
85
- expect(data.length).to eq 1
86
- expect(data[0]["kind"]).to eq "identify"
87
- end
88
- end
89
- end
90
- end
91
-
92
- it "sends diagnostic event" do
93
- with_server do |poll_server|
94
- with_server do |events_server|
95
- events_server.setup_ok_response("/bulk", "")
96
- events_server.setup_ok_response("/diagnostic", "")
97
- poll_server.setup_ok_response("/sdk/latest-all", '{"flags":{},"segments":{}}', "application/json")
98
-
99
- config = Config.new(
100
- stream: false,
101
- base_uri: poll_server.base_uri.to_s,
102
- events_uri: events_server.base_uri.to_s,
103
- logger: NullLogger.new
104
- )
105
- with_client(config) do |client|
106
- user = { key: 'userkey' }
107
- client.identify(user)
108
- client.flush
109
-
110
- req0, body0 = events_server.await_request_with_body
111
- req1, body1 = events_server.await_request_with_body
112
- req = req0.path == "/diagnostic" ? req0 : req1
113
- body = req0.path == "/diagnostic" ? body0 : body1
114
- expect(req.header['authorization']).to eq [ SDK_KEY ]
115
- expect(req.header['connection']).to eq [ "Keep-Alive" ]
116
- data = JSON.parse(body)
117
- expect(data["kind"]).to eq "diagnostic-init"
118
- end
119
- end
120
- end
121
- end
122
-
123
- it "can use socket factory" do
124
- with_server do |poll_server|
125
- with_server do |events_server|
126
- events_server.setup_ok_response("/bulk", "")
127
- poll_server.setup_ok_response("/sdk/latest-all", '{"flags":{},"segments":{}}', "application/json")
128
-
129
- config = Config.new(
130
- stream: false,
131
- base_uri: "http://polling.com",
132
- events_uri: "http://events.com",
133
- diagnostic_opt_out: true,
134
- logger: NullLogger.new,
135
- socket_factory: SocketFactoryFromHash.new({
136
- "polling.com" => poll_server.port,
137
- "events.com" => events_server.port
138
- })
139
- )
140
- with_client(config) do |client|
141
- client.identify(USER)
142
- client.flush
143
-
144
- req, body = events_server.await_request_with_body
145
- expect(req.header['authorization']).to eq [ SDK_KEY ]
146
- expect(req.header['connection']).to eq [ "Keep-Alive" ]
147
- data = JSON.parse(body)
148
- expect(data.length).to eq 1
149
- expect(data[0]["kind"]).to eq "identify"
150
- end
151
- end
152
- end
153
- end
154
-
155
- # TODO: TLS tests with self-signed cert
156
- end
157
- end