launchdarkly-server-sdk 5.7.1 → 5.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 35e90a3d6853e2a12b8cf6d3c44a5d84c397b76a
4
- data.tar.gz: 58a0229a7f331cb619568c8095a9381c60753a24
3
+ metadata.gz: dcb72b5ad43bf4a2f4250cbe1b12fb3eaf803e66
4
+ data.tar.gz: bd7ceebb0ff2a746d8b773fbeb7b3e287dcbcb01
5
5
  SHA512:
6
- metadata.gz: 4c2c1b2598e1ccf4a5f7f49fb4ef39974938100b4b9ea28fe910d7aea8a153d09a8e8ee978794293958c6040208fd055b271e1a4c8f4f3245e94dcc3d7c51812
7
- data.tar.gz: 4d0eadc0f93a217d36f89fae7b2f5b19ce5fa78f98c36a81d6d50d782ac7fed3f451384599bb24c7b8cec80e2e0a26df42d1dd1fcbe7ce6d29906f314fd929e7
6
+ metadata.gz: 4f3d71bf78a2cc31574470fd57af2eee84b5222dfaddfe90160ecd2bda746e5137df3fed136d12578b01ae84364f2fd04477046964bc8f73e5bced212988c59a
7
+ data.tar.gz: 165bb1c1b646ca0f759bb081020a16fd78b5df014be47cb9c5386f7e99b2287dfb640b7e865230e7604886dd3ad933ebae3d82b113bce21f549e03e2875c7d03
@@ -2,6 +2,31 @@
2
2
 
3
3
  All notable changes to the LaunchDarkly Ruby SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
4
4
 
5
+ ## [5.8.0] - 2020-05-27
6
+ ### Added:
7
+ - In `LaunchDarkly::Integrations::Redis::new_feature_store`, if you pass in an externally created `pool`, you can now set the new option `pool_shutdown_on_close` to `false` to indicate that the SDK should _not_ shut down this pool if the SDK is shut down. The default behavior, as before, is that it will be shut down. (Thanks, [jacobthemyth](https://github.com/launchdarkly/ruby-server-sdk/pull/158)!)
8
+
9
+ ## [5.7.4] - 2020-05-04
10
+ ### Fixed:
11
+ - Setting a user's `custom` property explicitly to `nil`, rather than omitting it entirely or setting it to an empty hash, would cause the SDK to log an error and drop the current batch of analytics events. Now, it will be treated the same as an empty hash. ([#147](https://github.com/launchdarkly/ruby-server-sdk/issues/147))
12
+
13
+ ## [5.7.3] - 2020-04-27
14
+ ### Changed:
15
+ - Previously, installing the SDK in an environment that did not have `openssl` would cause a failure at build time. The SDK still requires `openssl` at runtime, but this check has been removed because it caused the `rake` problem mentioned below, and because `openssl` is normally bundled in modern Ruby versions.
16
+
17
+ ### Fixed:
18
+ - The `LDClient` constructor will fail immediately with a descriptive `ArgumentError` if you provide a `nil` SDK key in a configuration that requires an SDK key (that is, a configuration that _will_ require communicating with LaunchDarkly services). Previously, it would still fail, but without a clear error message. You are still allowed to omit the SDK key in an offline configuration. ([#154](https://github.com/launchdarkly/ruby-server-sdk/issues/154))
19
+ - Removed a hidden dependency on `rake` which could cause your build to fail if you had a dependency on this SDK and you did not have `rake` installed. ([#155](https://github.com/launchdarkly/ruby-server-sdk/issues/155))
20
+ - Previously a clause in a feature flag rule that used a string operator (such as "starts with") or a numeric operator (such as "greater than") could cause evaluation of the flag to completely fail and return a default value if the value on the right-hand side of the expression did not have the right data type-- for instance, "greater than" with a string value. The LaunchDarkly dashboard does not allow creation of such a rule, but it might be possible to do so via the REST API; the correct behavior of the SDK is to simply treat the expression as a non-match.
21
+
22
+ ## [5.7.2] - 2020-03-27
23
+ ### Fixed:
24
+ - Fixed a bug in the 5.7.0 and 5.7.1 releases that caused analytics events not to be sent unless diagnostic events were explicitly disabled. This also caused an error to be logged: `undefined method started?`.
25
+
26
+ ## [5.7.1] - 2020-03-18
27
+ ### Fixed:
28
+ - The backoff delay logic for reconnecting after a stream failure was broken so that if a failure occurred after a stream had been active for at least 60 seconds, retries would use _no_ delay, potentially causing a flood of requests and a spike in CPU usage. This bug was introduced in version 5.5.0 of the SDK.
29
+
5
30
  ## [5.7.0] - 2020-03-10
6
31
  ### Added:
7
32
  - The SDK now periodically sends diagnostic data to LaunchDarkly, describing the version and configuration of the SDK, the architecture and version of the runtime platform, and performance statistics. No credentials, hostnames, or other identifiable values are included. This behavior can be disabled with `Config.diagnostic_opt_out` or configured with `Config.diagnostic_recording_interval`.
@@ -1,94 +1,83 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- launchdarkly-server-sdk (5.7.1)
4
+ launchdarkly-server-sdk (5.8.1)
5
5
  concurrent-ruby (~> 1.0)
6
- json (>= 1.8, < 3)
6
+ json (~> 2.3.1)
7
7
  ld-eventsource (= 1.0.3)
8
8
  semantic (~> 1.6)
9
9
 
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- aws-eventstream (1.0.1)
14
- aws-partitions (1.128.0)
15
- aws-sdk-core (3.44.2)
16
- aws-eventstream (~> 1.0)
17
- aws-partitions (~> 1.0)
18
- aws-sigv4 (~> 1.0)
13
+ aws-eventstream (1.1.0)
14
+ aws-partitions (1.388.0)
15
+ aws-sdk-core (3.109.1)
16
+ aws-eventstream (~> 1, >= 1.0.2)
17
+ aws-partitions (~> 1, >= 1.239.0)
18
+ aws-sigv4 (~> 1.1)
19
19
  jmespath (~> 1.0)
20
- aws-sdk-dynamodb (1.19.0)
21
- aws-sdk-core (~> 3, >= 3.39.0)
22
- aws-sigv4 (~> 1.0)
23
- aws-sigv4 (1.0.3)
24
- codeclimate-test-reporter (0.6.0)
25
- simplecov (>= 0.7.1, < 1.0.0)
26
- concurrent-ruby (1.1.6)
27
- connection_pool (2.2.1)
28
- diff-lcs (1.3)
29
- diplomat (2.0.2)
30
- faraday (~> 0.9)
31
- json
32
- docile (1.1.5)
33
- faraday (0.15.4)
20
+ aws-sdk-dynamodb (1.55.0)
21
+ aws-sdk-core (~> 3, >= 3.109.0)
22
+ aws-sigv4 (~> 1.1)
23
+ aws-sigv4 (1.2.2)
24
+ aws-eventstream (~> 1, >= 1.0.2)
25
+ concurrent-ruby (1.1.7)
26
+ connection_pool (2.2.3)
27
+ deep_merge (1.2.1)
28
+ diff-lcs (1.4.4)
29
+ diplomat (2.4.2)
30
+ deep_merge (~> 1.0, >= 1.0.1)
31
+ faraday (>= 0.9, < 1.1.0)
32
+ faraday (0.17.3)
34
33
  multipart-post (>= 1.2, < 3)
35
- ffi (1.9.25)
36
- ffi (1.9.25-java)
34
+ ffi (1.12.0)
37
35
  hitimes (1.3.1)
38
- hitimes (1.3.1-java)
39
36
  http_tools (0.4.5)
40
37
  jmespath (1.4.0)
41
- json (1.8.6)
42
- json (1.8.6-java)
38
+ json (2.3.1)
43
39
  ld-eventsource (1.0.3)
44
40
  concurrent-ruby (~> 1.0)
45
41
  http_tools (~> 0.4.5)
46
42
  socketry (~> 0.5.1)
47
- listen (3.1.5)
48
- rb-fsevent (~> 0.9, >= 0.9.4)
49
- rb-inotify (~> 0.9, >= 0.9.7)
50
- ruby_dep (~> 1.2)
51
- multipart-post (2.0.0)
52
- rb-fsevent (0.10.3)
53
- rb-inotify (0.9.10)
54
- ffi (>= 0.5.0, < 2)
43
+ listen (3.2.1)
44
+ rb-fsevent (~> 0.10, >= 0.10.3)
45
+ rb-inotify (~> 0.9, >= 0.9.10)
46
+ multipart-post (2.1.1)
47
+ rb-fsevent (0.10.4)
48
+ rb-inotify (0.10.1)
49
+ ffi (~> 1.0)
55
50
  redis (3.3.5)
56
- rspec (3.7.0)
57
- rspec-core (~> 3.7.0)
58
- rspec-expectations (~> 3.7.0)
59
- rspec-mocks (~> 3.7.0)
60
- rspec-core (3.7.1)
61
- rspec-support (~> 3.7.0)
62
- rspec-expectations (3.7.0)
51
+ rspec (3.9.0)
52
+ rspec-core (~> 3.9.0)
53
+ rspec-expectations (~> 3.9.0)
54
+ rspec-mocks (~> 3.9.0)
55
+ rspec-core (3.9.3)
56
+ rspec-support (~> 3.9.3)
57
+ rspec-expectations (3.9.3)
63
58
  diff-lcs (>= 1.2.0, < 2.0)
64
- rspec-support (~> 3.7.0)
65
- rspec-mocks (3.7.0)
59
+ rspec-support (~> 3.9.0)
60
+ rspec-mocks (3.9.1)
66
61
  diff-lcs (>= 1.2.0, < 2.0)
67
- rspec-support (~> 3.7.0)
68
- rspec-support (3.7.0)
62
+ rspec-support (~> 3.9.0)
63
+ rspec-support (3.9.4)
69
64
  rspec_junit_formatter (0.3.0)
70
65
  rspec-core (>= 2, < 4, != 2.12.0)
71
- ruby_dep (1.5.0)
72
66
  semantic (1.6.1)
73
- simplecov (0.15.1)
74
- docile (~> 1.1.0)
75
- json (>= 1.8, < 3)
76
- simplecov-html (~> 0.10.0)
77
- simplecov-html (0.10.2)
78
67
  socketry (0.5.1)
79
68
  hitimes (~> 1.2)
80
- timecop (0.9.1)
69
+ timecop (0.9.2)
81
70
 
82
71
  PLATFORMS
83
- java
84
72
  ruby
85
73
 
86
74
  DEPENDENCIES
87
75
  aws-sdk-dynamodb (~> 1.18)
88
- bundler (~> 1.7)
89
- codeclimate-test-reporter (~> 0)
76
+ bundler (~> 1.17)
90
77
  connection_pool (>= 2.1.2)
91
78
  diplomat (>= 2.0.2)
79
+ faraday (~> 0.17)
80
+ ffi (<= 1.12)
92
81
  launchdarkly-server-sdk!
93
82
  listen (~> 3.0)
94
83
  redis (~> 3.3.5)
@@ -19,21 +19,27 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
21
  spec.require_paths = ["lib"]
22
- spec.extensions = 'ext/mkrf_conf.rb'
23
22
 
24
23
  spec.add_development_dependency "aws-sdk-dynamodb", "~> 1.18"
25
- spec.add_development_dependency "bundler", "~> 1.7"
24
+ spec.add_development_dependency "bundler", "~> 1.17"
26
25
  spec.add_development_dependency "rspec", "~> 3.2"
27
- spec.add_development_dependency "codeclimate-test-reporter", "~> 0"
28
26
  spec.add_development_dependency "diplomat", ">= 2.0.2"
29
27
  spec.add_development_dependency "redis", "~> 3.3.5"
30
28
  spec.add_development_dependency "connection_pool", ">= 2.1.2"
31
29
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.3.0"
32
30
  spec.add_development_dependency "timecop", "~> 0.9.1"
33
31
  spec.add_development_dependency "listen", "~> 3.0" # see file_data_source.rb
32
+ # these are transitive dependencies of listen and consul respectively
33
+ # we constrain them here to make sure the ruby 2.2, 2.3, and 2.4 CI
34
+ # cases all pass
35
+ spec.add_development_dependency "ffi", "<= 1.12" # >1.12 doesnt support ruby 2.2
36
+ spec.add_development_dependency "faraday", "~> 0.17" # >=0.18 doesnt support ruby 2.2
34
37
 
35
- spec.add_runtime_dependency "json", [">= 1.8", "< 3"]
36
38
  spec.add_runtime_dependency "semantic", "~> 1.6"
37
39
  spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
38
40
  spec.add_runtime_dependency "ld-eventsource", "1.0.3"
41
+
42
+ # lock json to 2.3.x as ruby libraries often remove
43
+ # support for older ruby versions in minor releases
44
+ spec.add_runtime_dependency "json", "~> 2.3.1"
39
45
  end
@@ -140,35 +140,44 @@ module LaunchDarkly
140
140
  end,
141
141
  endsWith:
142
142
  lambda do |a, b|
143
- (a.is_a? String) && (a.end_with? b)
143
+ (a.is_a? String) && (b.is_a? String) && (a.end_with? b)
144
144
  end,
145
145
  startsWith:
146
146
  lambda do |a, b|
147
- (a.is_a? String) && (a.start_with? b)
147
+ (a.is_a? String) && (b.is_a? String) && (a.start_with? b)
148
148
  end,
149
149
  matches:
150
150
  lambda do |a, b|
151
- (b.is_a? String) && !(Regexp.new b).match(a).nil?
151
+ if (b.is_a? String) && (b.is_a? String)
152
+ begin
153
+ re = Regexp.new b
154
+ !re.match(a).nil?
155
+ rescue
156
+ false
157
+ end
158
+ else
159
+ false
160
+ end
152
161
  end,
153
162
  contains:
154
163
  lambda do |a, b|
155
- (a.is_a? String) && (a.include? b)
164
+ (a.is_a? String) && (b.is_a? String) && (a.include? b)
156
165
  end,
157
166
  lessThan:
158
167
  lambda do |a, b|
159
- (a.is_a? Numeric) && (a < b)
168
+ (a.is_a? Numeric) && (b.is_a? Numeric) && (a < b)
160
169
  end,
161
170
  lessThanOrEqual:
162
171
  lambda do |a, b|
163
- (a.is_a? Numeric) && (a <= b)
172
+ (a.is_a? Numeric) && (b.is_a? Numeric) && (a <= b)
164
173
  end,
165
174
  greaterThan:
166
175
  lambda do |a, b|
167
- (a.is_a? Numeric) && (a > b)
176
+ (a.is_a? Numeric) && (b.is_a? Numeric) && (a > b)
168
177
  end,
169
178
  greaterThanOrEqual:
170
179
  lambda do |a, b|
171
- (a.is_a? Numeric) && (a >= b)
180
+ (a.is_a? Numeric) && (b.is_a? Numeric) && (a >= b)
172
181
  end,
173
182
  before:
174
183
  comparator(DATE_OPERAND) { |n| n < 0 },
@@ -91,6 +91,7 @@ module LaunchDarkly
91
91
  # @private
92
92
  class EventProcessor
93
93
  def initialize(sdk_key, config, client = nil, diagnostic_accumulator = nil, test_properties = nil)
94
+ raise ArgumentError, "sdk_key must not be nil" if sdk_key.nil? # see LDClient constructor comment on sdk_key
94
95
  @logger = config.logger
95
96
  @inbox = SizedQueue.new(config.capacity < 100 ? 100 : config.capacity)
96
97
  @flush_task = Concurrent::TimerTask.new(execution_interval: config.flush_interval) do
@@ -319,7 +320,7 @@ module LaunchDarkly
319
320
  success = flush_workers.post do
320
321
  begin
321
322
  events_out = @formatter.make_output_events(payload.events, payload.summary)
322
- result = @event_sender.send_event_data(events_out.to_json, false)
323
+ result = @event_sender.send_event_data(events_out.to_json, "#{events_out.length} events", false)
323
324
  @disabled.value = true if result.must_shutdown
324
325
  if !result.time_from_server.nil?
325
326
  @last_known_past_time.value = (result.time_from_server.to_f * 1000).to_i
@@ -348,7 +349,7 @@ module LaunchDarkly
348
349
  uri = URI(@config.events_uri + "/diagnostic")
349
350
  diagnostic_event_workers.post do
350
351
  begin
351
- @event_sender.send_event_data(event.to_json, true)
352
+ @event_sender.send_event_data(event.to_json, "diagnostic event", true)
352
353
  rescue => e
353
354
  Util.log_exception(@config.logger, "Unexpected error in event processor", e)
354
355
  end
@@ -18,10 +18,9 @@ module LaunchDarkly
18
18
  @retry_interval = retry_interval
19
19
  end
20
20
 
21
- def send_event_data(event_data, is_diagnostic)
21
+ def send_event_data(event_data, description, is_diagnostic)
22
22
  uri = is_diagnostic ? @diagnostic_uri : @events_uri
23
23
  payload_id = is_diagnostic ? nil : SecureRandom.uuid
24
- description = is_diagnostic ? 'diagnostic event' : "#{event_data.length} events"
25
24
  res = nil
26
25
  (0..1).each do |attempt|
27
26
  if attempt > 0
@@ -30,7 +29,7 @@ module LaunchDarkly
30
29
  end
31
30
  begin
32
31
  @client.start if !@client.started?
33
- @logger.debug { "[LDClient] sending #{description}: #{body}" }
32
+ @logger.debug { "[LDClient] sending #{description}: #{event_data}" }
34
33
  req = Net::HTTP::Post.new(uri)
35
34
  req.content_type = "application/json"
36
35
  req.body = event_data
@@ -33,6 +33,8 @@ module LaunchDarkly
33
33
  @pool = opts[:pool] || ConnectionPool.new(size: max_connections) do
34
34
  ::Redis.new(@redis_opts)
35
35
  end
36
+ # shutdown pool on close unless the client passed a custom pool and specified not to shutdown
37
+ @pool_shutdown_on_close = (!opts[:pool] || opts.fetch(:pool_shutdown_on_close, true))
36
38
  @prefix = opts[:prefix] || LaunchDarkly::Integrations::Redis::default_prefix
37
39
  @logger = opts[:logger] || Config.default_logger
38
40
  @test_hook = opts[:test_hook] # used for unit tests, deliberately undocumented
@@ -118,6 +120,7 @@ module LaunchDarkly
118
120
 
119
121
  def stop
120
122
  if @stopped.make_true
123
+ return unless @pool_shutdown_on_close
121
124
  @pool.shutdown { |redis| redis.close }
122
125
  end
123
126
  end
@@ -45,6 +45,9 @@ module LaunchDarkly
45
45
  # @option opts [Integer] :expiration (15) expiration time for the in-memory cache, in seconds; 0 for no local caching
46
46
  # @option opts [Integer] :capacity (1000) maximum number of items in the cache
47
47
  # @option opts [Object] :pool custom connection pool, if desired
48
+ # @option opts [Boolean] :pool_shutdown_on_close whether calling `close` should shutdown the custom connection pool;
49
+ # this is true by default, and should be set to false only if you are managing the pool yourself and want its
50
+ # lifecycle to be independent of the SDK client
48
51
  # @return [LaunchDarkly::Interfaces::FeatureStore] a feature store object
49
52
  #
50
53
  def self.new_feature_store(opts)
@@ -33,6 +33,16 @@ module LaunchDarkly
33
33
  # @return [LDClient] The LaunchDarkly client instance
34
34
  #
35
35
  def initialize(sdk_key, config = Config.default, wait_for_sec = 5)
36
+ # Note that sdk_key is normally a required parameter, and a nil value would cause the SDK to
37
+ # fail in most configurations. However, there are some configurations where it would be OK
38
+ # (offline = true, *or* we are using LDD mode or the file data source and events are disabled
39
+ # so we're not connecting to any LD services) so rather than try to check for all of those
40
+ # up front, we will let the constructors for the data source implementations implement this
41
+ # fail-fast as appropriate, and just check here for the part regarding events.
42
+ if !config.offline? && config.send_events
43
+ raise ArgumentError, "sdk_key must not be nil" if sdk_key.nil?
44
+ end
45
+
36
46
  @sdk_key = sdk_key
37
47
 
38
48
  @event_factory_default = EventFactory.new(false)
@@ -56,7 +66,7 @@ module LaunchDarkly
56
66
  if @config.offline? || !@config.send_events
57
67
  @event_processor = NullEventProcessor.new
58
68
  else
59
- @event_processor = EventProcessor.new(sdk_key, config, diagnostic_accumulator)
69
+ @event_processor = EventProcessor.new(sdk_key, config, nil, diagnostic_accumulator)
60
70
  end
61
71
 
62
72
  if @config.use_ldd?
@@ -352,12 +362,13 @@ module LaunchDarkly
352
362
  if config.offline?
353
363
  return NullUpdateProcessor.new
354
364
  end
355
- requestor = Requestor.new(sdk_key, config)
365
+ raise ArgumentError, "sdk_key must not be nil" if sdk_key.nil? # see LDClient constructor comment on sdk_key
356
366
  if config.stream?
357
- StreamProcessor.new(sdk_key, config, requestor, diagnostic_accumulator)
367
+ StreamProcessor.new(sdk_key, config, diagnostic_accumulator)
358
368
  else
359
369
  config.logger.info { "Disabling streaming API" }
360
370
  config.logger.warn { "You should only disable the streaming API if instructed to do so by LaunchDarkly support" }
371
+ requestor = Requestor.new(sdk_key, config)
361
372
  PollingProcessor.new(config, requestor)
362
373
  end
363
374
  end
@@ -35,6 +35,7 @@ module LaunchDarkly
35
35
  # @option opts [Integer] :expiration expiration time for the in-memory cache, in seconds; 0 for no local caching
36
36
  # @option opts [Integer] :capacity maximum number of feature flags (or related objects) to cache locally
37
37
  # @option opts [Object] :pool custom connection pool, if desired
38
+ # @option opts [Boolean] :pool_shutdown_on_close whether calling `close` should shutdown the custom connection pool.
38
39
  #
39
40
  def initialize(opts = {})
40
41
  core = LaunchDarkly::Impl::Integrations::Redis::RedisFeatureStoreCore.new(opts)
@@ -26,14 +26,6 @@ module LaunchDarkly
26
26
  @cache = @config.cache_store
27
27
  end
28
28
 
29
- def request_flag(key)
30
- make_request("/sdk/latest-flags/" + key)
31
- end
32
-
33
- def request_segment(key)
34
- make_request("/sdk/latest-segments/" + key)
35
- end
36
-
37
29
  def request_all_data()
38
30
  make_request("/sdk/latest-all")
39
31
  end
@@ -10,10 +10,6 @@ module LaunchDarkly
10
10
  # @private
11
11
  DELETE = :delete
12
12
  # @private
13
- INDIRECT_PUT = :'indirect/put'
14
- # @private
15
- INDIRECT_PATCH = :'indirect/patch'
16
- # @private
17
13
  READ_TIMEOUT_SECONDS = 300 # 5 minutes; the stream should send a ping every 3 minutes
18
14
 
19
15
  # @private
@@ -24,11 +20,10 @@ module LaunchDarkly
24
20
 
25
21
  # @private
26
22
  class StreamProcessor
27
- def initialize(sdk_key, config, requestor, diagnostic_accumulator = nil)
23
+ def initialize(sdk_key, config, diagnostic_accumulator = nil)
28
24
  @sdk_key = sdk_key
29
25
  @config = config
30
26
  @feature_store = config.feature_store
31
- @requestor = requestor
32
27
  @initialized = Concurrent::AtomicBoolean.new(false)
33
28
  @started = Concurrent::AtomicBoolean.new(false)
34
29
  @stopped = Concurrent::AtomicBoolean.new(false)
@@ -112,24 +107,6 @@ module LaunchDarkly
112
107
  break
113
108
  end
114
109
  end
115
- elsif method == INDIRECT_PUT
116
- all_data = @requestor.request_all_data
117
- @feature_store.init({
118
- FEATURES => all_data[:flags],
119
- SEGMENTS => all_data[:segments]
120
- })
121
- @initialized.make_true
122
- @config.logger.info { "[LDClient] Stream initialized (via indirect message)" }
123
- elsif method == INDIRECT_PATCH
124
- key = key_for_path(FEATURES, message.data)
125
- if key
126
- @feature_store.upsert(FEATURES, @requestor.request_flag(key))
127
- else
128
- key = key_for_path(SEGMENTS, message.data)
129
- if key
130
- @feature_store.upsert(SEGMENTS, @requestor.request_segment(key))
131
- end
132
- end
133
110
  else
134
111
  @config.logger.warn { "[LDClient] Unknown message received: #{method}" }
135
112
  end
@@ -15,8 +15,9 @@ module LaunchDarkly
15
15
  user_private_attrs = Set.new((user_props[:privateAttributeNames] || []).map(&:to_sym))
16
16
 
17
17
  filtered_user_props, removed = filter_values(user_props, user_private_attrs, ALLOWED_TOP_LEVEL_KEYS, IGNORED_TOP_LEVEL_KEYS)
18
- if user_props.has_key?(:custom)
19
- filtered_user_props[:custom], removed_custom = filter_values(user_props[:custom], user_private_attrs)
18
+ custom = user_props[:custom]
19
+ if !custom.nil?
20
+ filtered_user_props[:custom], removed_custom = filter_values(custom, user_private_attrs)
20
21
  removed.merge(removed_custom)
21
22
  end
22
23
 
@@ -1,3 +1,3 @@
1
1
  module LaunchDarkly
2
- VERSION = "5.7.1"
2
+ VERSION = "5.8.1"
3
3
  end
@@ -495,13 +495,13 @@ describe LaunchDarkly::Evaluation do
495
495
  # mixed strings and numbers
496
496
  [ :in, "99", 99, false ],
497
497
  [ :in, 99, "99", false ],
498
- #[ :contains, "99", 99, false ], # currently throws exception - would return false in Java SDK
499
- #[ :startsWith, "99", 99, false ], # currently throws exception - would return false in Java SDK
500
- #[ :endsWith, "99", 99, false ] # currently throws exception - would return false in Java SDK
498
+ [ :contains, "99", 99, false ],
499
+ [ :startsWith, "99", 99, false ],
500
+ [ :endsWith, "99", 99, false ],
501
501
  [ :lessThanOrEqual, "99", 99, false ],
502
- #[ :lessThanOrEqual, 99, "99", false ], # currently throws exception - would return false in Java SDK
502
+ [ :lessThanOrEqual, 99, "99", false ],
503
503
  [ :greaterThanOrEqual, "99", 99, false ],
504
- #[ :greaterThanOrEqual, 99, "99", false ], # currently throws exception - would return false in Java SDK
504
+ [ :greaterThanOrEqual, 99, "99", false ],
505
505
 
506
506
  # regex
507
507
  [ :matches, "hello world", "hello.*rld", true ],
@@ -509,7 +509,7 @@ describe LaunchDarkly::Evaluation do
509
509
  [ :matches, "hello world", "l+", true ],
510
510
  [ :matches, "hello world", "(world|planet)", true ],
511
511
  [ :matches, "hello world", "aloha", false ],
512
- #[ :matches, "hello world", "***not a regex", false ] # currently throws exception - same as Java SDK
512
+ [ :matches, "hello world", "***not a regex", false ],
513
513
 
514
514
  # dates
515
515
  [ :before, dateStr1, dateStr2, true ],
@@ -27,7 +27,7 @@ module LaunchDarkly
27
27
  with_sender_and_server do |es, server|
28
28
  server.setup_ok_response("/bulk", "")
29
29
 
30
- result = es.send_event_data(fake_data, false)
30
+ result = es.send_event_data(fake_data, "", false)
31
31
 
32
32
  expect(result.success).to be true
33
33
  expect(result.must_shutdown).to be false
@@ -49,8 +49,8 @@ module LaunchDarkly
49
49
  with_sender_and_server do |es, server|
50
50
  server.setup_ok_response("/bulk", "")
51
51
 
52
- result1 = es.send_event_data(fake_data, false)
53
- result2 = es.send_event_data(fake_data, false)
52
+ result1 = es.send_event_data(fake_data, "", false)
53
+ result2 = es.send_event_data(fake_data, "", false)
54
54
  expect(result1.success).to be true
55
55
  expect(result2.success).to be true
56
56
 
@@ -66,7 +66,7 @@ module LaunchDarkly
66
66
  with_sender_and_server do |es, server|
67
67
  server.setup_ok_response("/diagnostic", "")
68
68
 
69
- result = es.send_event_data(fake_data, true)
69
+ result = es.send_event_data(fake_data, "", true)
70
70
 
71
71
  expect(result.success).to be true
72
72
  expect(result.must_shutdown).to be false
@@ -94,7 +94,7 @@ module LaunchDarkly
94
94
 
95
95
  es = make_sender(server)
96
96
 
97
- result = es.send_event_data(fake_data, false)
97
+ result = es.send_event_data(fake_data, "", false)
98
98
 
99
99
  expect(result.success).to be true
100
100
 
@@ -116,7 +116,7 @@ module LaunchDarkly
116
116
  res.status = req_count == 2 ? 200 : status
117
117
  end
118
118
 
119
- result = es.send_event_data(fake_data, false)
119
+ result = es.send_event_data(fake_data, "", false)
120
120
 
121
121
  expect(result.success).to be true
122
122
  expect(result.must_shutdown).to be false
@@ -141,7 +141,7 @@ module LaunchDarkly
141
141
  res.status = req_count == 3 ? 200 : status
142
142
  end
143
143
 
144
- result = es.send_event_data(fake_data, false)
144
+ result = es.send_event_data(fake_data, "", false)
145
145
 
146
146
  expect(result.success).to be false
147
147
  expect(result.must_shutdown).to be false
@@ -164,7 +164,7 @@ module LaunchDarkly
164
164
  res.status = status
165
165
  end
166
166
 
167
- result = es.send_event_data(fake_data, false)
167
+ result = es.send_event_data(fake_data, "", false)
168
168
 
169
169
  expect(result.success).to be false
170
170
  expect(result.must_shutdown).to be true
@@ -408,6 +408,17 @@ describe LaunchDarkly::EventProcessor do
408
408
  end
409
409
  end
410
410
 
411
+ it "treats nil value for custom the same as an empty hash" do
412
+ with_processor_and_sender(default_config) do |ep, sender|
413
+ user_with_nil_custom = { key: "userkey", custom: nil }
414
+ e = { kind: "identify", key: "userkey", user: user_with_nil_custom }
415
+ ep.add_event(e)
416
+
417
+ output = flush_and_get_events(ep, sender)
418
+ expect(output).to contain_exactly(e)
419
+ end
420
+ end
421
+
411
422
  it "does a final flush when shutting down" do
412
423
  with_processor_and_sender(default_config) do |ep, sender|
413
424
  e = { kind: "identify", key: user[:key], user: user }
@@ -578,7 +589,7 @@ describe LaunchDarkly::EventProcessor do
578
589
  @diagnostic_payloads = Queue.new
579
590
  end
580
591
 
581
- def send_event_data(data, is_diagnostic)
592
+ def send_event_data(data, description, is_diagnostic)
582
593
  (is_diagnostic ? @diagnostic_payloads : @analytics_payloads).push(JSON.parse(data, symbolize_names: true))
583
594
  @result
584
595
  end
@@ -0,0 +1,123 @@
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
+ data = JSON.parse(body)
84
+ expect(data.length).to eq 1
85
+ expect(data[0]["kind"]).to eq "identify"
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ it "sends diagnostic event" do
92
+ with_server do |poll_server|
93
+ with_server do |events_server|
94
+ events_server.setup_ok_response("/bulk", "")
95
+ events_server.setup_ok_response("/diagnostic", "")
96
+ poll_server.setup_ok_response("/sdk/latest-all", '{"flags":{},"segments":{}}', "application/json")
97
+
98
+ config = Config.new(
99
+ stream: false,
100
+ base_uri: poll_server.base_uri.to_s,
101
+ events_uri: events_server.base_uri.to_s,
102
+ logger: NullLogger.new
103
+ )
104
+ with_client(config) do |client|
105
+ user = { key: 'userkey' }
106
+ client.identify(user)
107
+ client.flush
108
+
109
+ req0, body0 = events_server.await_request_with_body
110
+ req1, body1 = events_server.await_request_with_body
111
+ req = req0.path == "/diagnostic" ? req0 : req1
112
+ body = req0.path == "/diagnostic" ? body0 : body1
113
+ expect(req.header['authorization']).to eq [ SDK_KEY ]
114
+ data = JSON.parse(body)
115
+ expect(data["kind"]).to eq "diagnostic-init"
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ # TODO: TLS tests with self-signed cert
122
+ end
123
+ end
@@ -49,6 +49,46 @@ describe LaunchDarkly::LDClient do
49
49
  client.instance_variable_get(:@event_processor)
50
50
  end
51
51
 
52
+ describe "constructor requirement of non-nil sdk key" do
53
+ it "is not enforced when offline" do
54
+ subject.new(nil, offline_config)
55
+ end
56
+
57
+ it "is not enforced if use_ldd is true and send_events is false" do
58
+ subject.new(nil, LaunchDarkly::Config.new({ use_ldd: true, send_events: false }))
59
+ end
60
+
61
+ it "is not enforced if using file data and send_events is false" do
62
+ source = LaunchDarkly::FileDataSource.factory({})
63
+ subject.new(nil, LaunchDarkly::Config.new({ data_source: source, send_events: false }))
64
+ end
65
+
66
+ it "is enforced in streaming mode even if send_events is false" do
67
+ expect {
68
+ subject.new(nil, LaunchDarkly::Config.new({ send_events: false }))
69
+ }.to raise_error(ArgumentError)
70
+ end
71
+
72
+ it "is enforced in polling mode even if send_events is false" do
73
+ expect {
74
+ subject.new(nil, LaunchDarkly::Config.new({ stream: false, send_events: false }))
75
+ }.to raise_error(ArgumentError)
76
+ end
77
+
78
+ it "is enforced if use_ldd is true and send_events is true" do
79
+ expect {
80
+ subject.new(nil, LaunchDarkly::Config.new({ use_ldd: true }))
81
+ }.to raise_error(ArgumentError)
82
+ end
83
+
84
+ it "is enforced if using file data and send_events is true" do
85
+ source = LaunchDarkly::FileDataSource.factory({})
86
+ expect {
87
+ subject.new(nil, LaunchDarkly::Config.new({ data_source: source }))
88
+ }.to raise_error(ArgumentError)
89
+ end
90
+ end
91
+
52
92
  describe '#variation' do
53
93
  feature_with_value = { key: "key", on: false, offVariation: 0, variations: ["value"], version: 100,
54
94
  trackEvents: true, debugEventsUntilDate: 1000 }
@@ -1,3 +1,4 @@
1
+ require "connection_pool"
1
2
  require "feature_store_spec_base"
2
3
  require "json"
3
4
  require "redis"
@@ -27,11 +28,11 @@ end
27
28
 
28
29
  describe LaunchDarkly::RedisFeatureStore do
29
30
  subject { LaunchDarkly::RedisFeatureStore }
30
-
31
+
31
32
  break if ENV['LD_SKIP_DATABASE_TESTS'] == '1'
32
33
 
33
34
  # These tests will all fail if there isn't a Redis instance running on the default port.
34
-
35
+
35
36
  context "real Redis with local cache" do
36
37
  include_examples "feature_store", method(:create_redis_store), method(:clear_all_data)
37
38
  end
@@ -59,7 +60,7 @@ describe LaunchDarkly::RedisFeatureStore do
59
60
  flag = { key: "foo", version: 1 }
60
61
  test_hook = make_concurrent_modifier_test_hook(other_client, flag, 2, 4)
61
62
  store = create_redis_store({ test_hook: test_hook })
62
-
63
+
63
64
  begin
64
65
  store.init(LaunchDarkly::FEATURES => { flag[:key] => flag })
65
66
 
@@ -77,7 +78,7 @@ describe LaunchDarkly::RedisFeatureStore do
77
78
  flag = { key: "foo", version: 1 }
78
79
  test_hook = make_concurrent_modifier_test_hook(other_client, flag, 3, 3)
79
80
  store = create_redis_store({ test_hook: test_hook })
80
-
81
+
81
82
  begin
82
83
  store.init(LaunchDarkly::FEATURES => { flag[:key] => flag })
83
84
 
@@ -89,4 +90,32 @@ describe LaunchDarkly::RedisFeatureStore do
89
90
  other_client.close
90
91
  end
91
92
  end
93
+
94
+ it "shuts down a custom Redis pool by default" do
95
+ unowned_pool = ConnectionPool.new(size: 1, timeout: 1) { Redis.new({ url: "redis://localhost:6379" }) }
96
+ store = create_redis_store({ pool: unowned_pool })
97
+
98
+ begin
99
+ store.init(LaunchDarkly::FEATURES => { })
100
+ store.stop
101
+
102
+ expect { unowned_pool.with {} }.to raise_error(ConnectionPool::PoolShuttingDownError)
103
+ ensure
104
+ unowned_pool.shutdown { |conn| conn.close }
105
+ end
106
+ end
107
+
108
+ it "doesn't shut down a custom Redis pool if pool_shutdown_on_close = false" do
109
+ unowned_pool = ConnectionPool.new(size: 1, timeout: 1) { Redis.new({ url: "redis://localhost:6379" }) }
110
+ store = create_redis_store({ pool: unowned_pool, pool_shutdown_on_close: false })
111
+
112
+ begin
113
+ store.init(LaunchDarkly::FEATURES => { })
114
+ store.stop
115
+
116
+ expect { unowned_pool.with {} }.not_to raise_error(ConnectionPool::PoolShuttingDownError)
117
+ ensure
118
+ unowned_pool.shutdown { |conn| conn.close }
119
+ end
120
+ end
92
121
  end
@@ -193,38 +193,4 @@ describe LaunchDarkly::Requestor do
193
193
  end
194
194
  end
195
195
  end
196
-
197
- describe "request_flag" do
198
- it "uses expected URI and headers" do
199
- with_server do |server|
200
- with_requestor(server.base_uri.to_s) do |requestor|
201
- server.setup_ok_response("/", "{}")
202
- requestor.request_flag("key")
203
- expect(server.requests.count).to eq 1
204
- expect(server.requests[0].unparsed_uri).to eq "/sdk/latest-flags/key"
205
- expect(server.requests[0].header).to include({
206
- "authorization" => [ $sdk_key ],
207
- "user-agent" => [ "RubyClient/" + LaunchDarkly::VERSION ]
208
- })
209
- end
210
- end
211
- end
212
- end
213
-
214
- describe "request_segment" do
215
- it "uses expected URI and headers" do
216
- with_server do |server|
217
- with_requestor(server.base_uri.to_s) do |requestor|
218
- server.setup_ok_response("/", "{}")
219
- requestor.request_segment("key")
220
- expect(server.requests.count).to eq 1
221
- expect(server.requests[0].unparsed_uri).to eq "/sdk/latest-segments/key"
222
- expect(server.requests[0].header).to include({
223
- "authorization" => [ $sdk_key ],
224
- "user-agent" => [ "RubyClient/" + LaunchDarkly::VERSION ]
225
- })
226
- end
227
- end
228
- end
229
- end
230
196
  end
@@ -1,6 +1,3 @@
1
- require "codeclimate-test-reporter"
2
- CodeClimate::TestReporter.start
3
-
4
1
  require "ldclient-rb"
5
2
 
6
3
  $null_log = ::Logger.new($stdout)
@@ -4,8 +4,7 @@ require "spec_helper"
4
4
  describe LaunchDarkly::StreamProcessor do
5
5
  subject { LaunchDarkly::StreamProcessor }
6
6
  let(:config) { LaunchDarkly::Config.new }
7
- let(:requestor) { double() }
8
- let(:processor) { subject.new("sdk_key", config, requestor) }
7
+ let(:processor) { subject.new("sdk_key", config) }
9
8
 
10
9
  describe '#process_message' do
11
10
  let(:put_message) { SSE::StreamEvent.new(:put, '{"data":{"flags":{"asdf": {"key": "asdf"}},"segments":{"segkey": {"key": "segkey"}}}}') }
@@ -13,8 +12,6 @@ describe LaunchDarkly::StreamProcessor do
13
12
  let(:patch_seg_message) { SSE::StreamEvent.new(:patch, '{"path": "/segments/key", "data": {"key": "asdf", "version": 1}}') }
14
13
  let(:delete_flag_message) { SSE::StreamEvent.new(:delete, '{"path": "/flags/key", "version": 2}') }
15
14
  let(:delete_seg_message) { SSE::StreamEvent.new(:delete, '{"path": "/segments/key", "version": 2}') }
16
- let(:indirect_patch_flag_message) { SSE::StreamEvent.new(:'indirect/patch', "/flags/key") }
17
- let(:indirect_patch_segment_message) { SSE::StreamEvent.new(:'indirect/patch', "/segments/key") }
18
15
 
19
16
  it "will accept PUT methods" do
20
17
  processor.send(:process_message, put_message)
@@ -39,18 +36,6 @@ describe LaunchDarkly::StreamProcessor do
39
36
  processor.send(:process_message, delete_seg_message)
40
37
  expect(config.feature_store.get(LaunchDarkly::SEGMENTS, "key")).to eq(nil)
41
38
  end
42
- it "will accept INDIRECT PATCH method for flags" do
43
- flag = { key: 'key', version: 1 }
44
- allow(requestor).to receive(:request_flag).with(flag[:key]).and_return(flag)
45
- processor.send(:process_message, indirect_patch_flag_message);
46
- expect(config.feature_store.get(LaunchDarkly::FEATURES, flag[:key])).to eq(flag)
47
- end
48
- it "will accept INDIRECT PATCH method for segments" do
49
- segment = { key: 'key', version: 1 }
50
- allow(requestor).to receive(:request_segment).with(segment[:key]).and_return(segment)
51
- processor.send(:process_message, indirect_patch_segment_message);
52
- expect(config.feature_store.get(LaunchDarkly::SEGMENTS, segment[:key])).to eq(segment)
53
- end
54
39
  it "will log a warning if the method is not recognized" do
55
40
  expect(processor.instance_variable_get(:@config).logger).to receive :warn
56
41
  processor.send(:process_message, SSE::StreamEvent.new(type: :get, data: "", id: nil))
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: launchdarkly-server-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.7.1
4
+ version: 5.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - LaunchDarkly
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-18 00:00:00.000000000 Z
11
+ date: 2020-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-dynamodb
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.7'
33
+ version: '1.17'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.7'
40
+ version: '1.17'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.2'
55
- - !ruby/object:Gem::Dependency
56
- name: codeclimate-test-reporter
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: diplomat
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -151,25 +137,33 @@ dependencies:
151
137
  - !ruby/object:Gem::Version
152
138
  version: '3.0'
153
139
  - !ruby/object:Gem::Dependency
154
- name: json
140
+ name: ffi
155
141
  requirement: !ruby/object:Gem::Requirement
156
142
  requirements:
157
- - - ">="
143
+ - - "<="
158
144
  - !ruby/object:Gem::Version
159
- version: '1.8'
160
- - - "<"
161
- - !ruby/object:Gem::Version
162
- version: '3'
163
- type: :runtime
145
+ version: '1.12'
146
+ type: :development
164
147
  prerelease: false
165
148
  version_requirements: !ruby/object:Gem::Requirement
166
149
  requirements:
167
- - - ">="
150
+ - - "<="
168
151
  - !ruby/object:Gem::Version
169
- version: '1.8'
170
- - - "<"
152
+ version: '1.12'
153
+ - !ruby/object:Gem::Dependency
154
+ name: faraday
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.17'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
171
165
  - !ruby/object:Gem::Version
172
- version: '3'
166
+ version: '0.17'
173
167
  - !ruby/object:Gem::Dependency
174
168
  name: semantic
175
169
  requirement: !ruby/object:Gem::Requirement
@@ -212,12 +206,25 @@ dependencies:
212
206
  - - '='
213
207
  - !ruby/object:Gem::Version
214
208
  version: 1.0.3
209
+ - !ruby/object:Gem::Dependency
210
+ name: json
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: 2.3.1
216
+ type: :runtime
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: 2.3.1
215
223
  description: Official LaunchDarkly SDK for Ruby
216
224
  email:
217
225
  - team@launchdarkly.com
218
226
  executables: []
219
- extensions:
220
- - ext/mkrf_conf.rb
227
+ extensions: []
221
228
  extra_rdoc_files: []
222
229
  files:
223
230
  - ".circleci/config.yml"
@@ -239,7 +246,6 @@ files:
239
246
  - LICENSE.txt
240
247
  - README.md
241
248
  - azure-pipelines.yml
242
- - ext/mkrf_conf.rb
243
249
  - launchdarkly-server-sdk.gemspec
244
250
  - lib/launchdarkly-server-sdk.rb
245
251
  - lib/ldclient-rb.rb
@@ -302,6 +308,7 @@ files:
302
308
  - spec/integrations/store_wrapper_spec.rb
303
309
  - spec/launchdarkly-server-sdk_spec.rb
304
310
  - spec/launchdarkly-server-sdk_spec_autoloadtest.rb
311
+ - spec/ldclient_end_to_end_spec.rb
305
312
  - spec/ldclient_spec.rb
306
313
  - spec/newrelic_spec.rb
307
314
  - spec/polling_spec.rb
@@ -360,6 +367,7 @@ test_files:
360
367
  - spec/integrations/store_wrapper_spec.rb
361
368
  - spec/launchdarkly-server-sdk_spec.rb
362
369
  - spec/launchdarkly-server-sdk_spec_autoloadtest.rb
370
+ - spec/ldclient_end_to_end_spec.rb
363
371
  - spec/ldclient_spec.rb
364
372
  - spec/newrelic_spec.rb
365
373
  - spec/polling_spec.rb
@@ -1,11 +0,0 @@
1
- require "rubygems"
2
-
3
-
4
- # From http://stackoverflow.com/questions/5830835/how-to-add-openssl-dependency-to-gemspec
5
- # the whole reason this file exists: to return an error if openssl
6
- # isn't installed.
7
- require "openssl"
8
-
9
- f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w") # create dummy rakefile to indicate success
10
- f.write("task :default\n")
11
- f.close