launchdarkly-server-sdk 5.6.2 → 5.7.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +4 -6
- data/launchdarkly-server-sdk.gemspec +1 -2
- data/lib/ldclient-rb/config.rb +64 -0
- data/lib/ldclient-rb/events.rb +94 -86
- data/lib/ldclient-rb/flags_state.rb +1 -1
- data/lib/ldclient-rb/impl/diagnostic_events.rb +130 -0
- data/lib/ldclient-rb/impl/event_sender.rb +72 -0
- data/lib/ldclient-rb/impl/util.rb +19 -0
- data/lib/ldclient-rb/ldclient.rb +17 -4
- data/lib/ldclient-rb/requestor.rb +1 -2
- data/lib/ldclient-rb/stream.rb +18 -5
- data/lib/ldclient-rb/version.rb +1 -1
- data/spec/diagnostic_events_spec.rb +163 -0
- data/spec/evaluation_spec.rb +1 -1
- data/spec/event_sender_spec.rb +179 -0
- data/spec/events_spec.rb +437 -524
- data/spec/file_data_source_spec.rb +1 -1
- data/spec/http_util.rb +15 -2
- data/spec/integrations/consul_feature_store_spec.rb +0 -2
- data/spec/integrations/dynamodb_feature_store_spec.rb +0 -2
- data/spec/ldclient_spec.rb +1 -1
- data/spec/polling_spec.rb +1 -1
- data/spec/redis_feature_store_spec.rb +0 -3
- data/spec/requestor_spec.rb +20 -4
- data/spec/spec_helper.rb +3 -0
- metadata +11 -19
- data/Rakefile +0 -5
@@ -22,7 +22,7 @@ module LaunchDarkly
|
|
22
22
|
meta = {}
|
23
23
|
with_details = !details_only_if_tracked || flag[:trackEvents]
|
24
24
|
if !with_details && flag[:debugEventsUntilDate]
|
25
|
-
with_details = flag[:debugEventsUntilDate] >
|
25
|
+
with_details = flag[:debugEventsUntilDate] > Impl::Util::current_time_millis
|
26
26
|
end
|
27
27
|
if with_details
|
28
28
|
meta[:version] = flag[:version]
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require "ldclient-rb/impl/util"
|
2
|
+
|
3
|
+
require "rbconfig"
|
4
|
+
require "securerandom"
|
5
|
+
|
6
|
+
module LaunchDarkly
|
7
|
+
module Impl
|
8
|
+
class DiagnosticAccumulator
|
9
|
+
def self.create_diagnostic_id(sdk_key)
|
10
|
+
{
|
11
|
+
diagnosticId: SecureRandom.uuid,
|
12
|
+
sdkKeySuffix: sdk_key[-6..-1] || sdk_key
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(diagnostic_id)
|
17
|
+
@id = diagnostic_id
|
18
|
+
@lock = Mutex.new
|
19
|
+
self.reset(Util.current_time_millis)
|
20
|
+
end
|
21
|
+
|
22
|
+
def reset(time)
|
23
|
+
@data_since_date = time
|
24
|
+
@stream_inits = []
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_init_event(config)
|
28
|
+
return {
|
29
|
+
kind: 'diagnostic-init',
|
30
|
+
creationDate: Util.current_time_millis,
|
31
|
+
id: @id,
|
32
|
+
configuration: DiagnosticAccumulator.make_config_data(config),
|
33
|
+
sdk: DiagnosticAccumulator.make_sdk_data(config),
|
34
|
+
platform: DiagnosticAccumulator.make_platform_data
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def record_stream_init(timestamp, failed, duration_millis)
|
39
|
+
@lock.synchronize do
|
40
|
+
@stream_inits.push({ timestamp: timestamp, failed: failed, durationMillis: duration_millis })
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_periodic_event_and_reset(dropped_events, deduplicated_users, events_in_last_batch)
|
45
|
+
previous_stream_inits = @lock.synchronize do
|
46
|
+
si = @stream_inits
|
47
|
+
@stream_inits = []
|
48
|
+
si
|
49
|
+
end
|
50
|
+
|
51
|
+
current_time = Util.current_time_millis
|
52
|
+
event = {
|
53
|
+
kind: 'diagnostic',
|
54
|
+
creationDate: current_time,
|
55
|
+
id: @id,
|
56
|
+
dataSinceDate: @data_since_date,
|
57
|
+
droppedEvents: dropped_events,
|
58
|
+
deduplicatedUsers: deduplicated_users,
|
59
|
+
eventsInLastBatch: events_in_last_batch,
|
60
|
+
streamInits: previous_stream_inits
|
61
|
+
}
|
62
|
+
@data_since_date = current_time
|
63
|
+
event
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.make_config_data(config)
|
67
|
+
ret = {
|
68
|
+
allAttributesPrivate: config.all_attributes_private,
|
69
|
+
connectTimeoutMillis: self.seconds_to_millis(config.connect_timeout),
|
70
|
+
customBaseURI: config.base_uri != Config.default_base_uri,
|
71
|
+
customEventsURI: config.events_uri != Config.default_events_uri,
|
72
|
+
customStreamURI: config.stream_uri != Config.default_stream_uri,
|
73
|
+
diagnosticRecordingIntervalMillis: self.seconds_to_millis(config.diagnostic_recording_interval),
|
74
|
+
eventsCapacity: config.capacity,
|
75
|
+
eventsFlushIntervalMillis: self.seconds_to_millis(config.flush_interval),
|
76
|
+
inlineUsersInEvents: config.inline_users_in_events,
|
77
|
+
pollingIntervalMillis: self.seconds_to_millis(config.poll_interval),
|
78
|
+
socketTimeoutMillis: self.seconds_to_millis(config.read_timeout),
|
79
|
+
streamingDisabled: !config.stream?,
|
80
|
+
userKeysCapacity: config.user_keys_capacity,
|
81
|
+
userKeysFlushIntervalMillis: self.seconds_to_millis(config.user_keys_flush_interval),
|
82
|
+
usingProxy: ENV.has_key?('http_proxy') || ENV.has_key?('https_proxy') || ENV.has_key?('HTTP_PROXY'),
|
83
|
+
usingRelayDaemon: config.use_ldd?,
|
84
|
+
}
|
85
|
+
ret
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.make_sdk_data(config)
|
89
|
+
ret = {
|
90
|
+
name: 'ruby-server-sdk',
|
91
|
+
version: LaunchDarkly::VERSION
|
92
|
+
}
|
93
|
+
if config.wrapper_name
|
94
|
+
ret[:wrapperName] = config.wrapper_name
|
95
|
+
ret[:wrapperVersion] = config.wrapper_version
|
96
|
+
end
|
97
|
+
ret
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.make_platform_data
|
101
|
+
conf = RbConfig::CONFIG
|
102
|
+
{
|
103
|
+
name: 'ruby',
|
104
|
+
osArch: conf['host_cpu'],
|
105
|
+
osName: self.normalize_os_name(conf['host_os']),
|
106
|
+
osVersion: 'unknown', # there seems to be no portable way to detect this in Ruby
|
107
|
+
rubyVersion: conf['ruby_version'],
|
108
|
+
rubyImplementation: Object.constants.include?(:RUBY_ENGINE) ? RUBY_ENGINE : 'unknown'
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.normalize_os_name(name)
|
113
|
+
case name
|
114
|
+
when /linux|arch/i
|
115
|
+
'Linux'
|
116
|
+
when /darwin/i
|
117
|
+
'MacOS'
|
118
|
+
when /mswin|windows/i
|
119
|
+
'Windows'
|
120
|
+
else
|
121
|
+
name
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.seconds_to_millis(s)
|
126
|
+
(s * 1000).to_i
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
3
|
+
module LaunchDarkly
|
4
|
+
module Impl
|
5
|
+
EventSenderResult = Struct.new(:success, :must_shutdown, :time_from_server)
|
6
|
+
|
7
|
+
class EventSender
|
8
|
+
CURRENT_SCHEMA_VERSION = 3
|
9
|
+
DEFAULT_RETRY_INTERVAL = 1
|
10
|
+
|
11
|
+
def initialize(sdk_key, config, http_client = nil, retry_interval = DEFAULT_RETRY_INTERVAL)
|
12
|
+
@client = http_client ? http_client : LaunchDarkly::Util.new_http_client(config.events_uri, config)
|
13
|
+
@sdk_key = sdk_key
|
14
|
+
@config = config
|
15
|
+
@events_uri = config.events_uri + "/bulk"
|
16
|
+
@diagnostic_uri = config.events_uri + "/diagnostic"
|
17
|
+
@logger = config.logger
|
18
|
+
@retry_interval = retry_interval
|
19
|
+
end
|
20
|
+
|
21
|
+
def send_event_data(event_data, is_diagnostic)
|
22
|
+
uri = is_diagnostic ? @diagnostic_uri : @events_uri
|
23
|
+
payload_id = is_diagnostic ? nil : SecureRandom.uuid
|
24
|
+
description = is_diagnostic ? 'diagnostic event' : "#{event_data.length} events"
|
25
|
+
res = nil
|
26
|
+
(0..1).each do |attempt|
|
27
|
+
if attempt > 0
|
28
|
+
@logger.warn { "[LDClient] Will retry posting events after #{@retry_interval} second" }
|
29
|
+
sleep(@retry_interval)
|
30
|
+
end
|
31
|
+
begin
|
32
|
+
@client.start if !@client.started?
|
33
|
+
@logger.debug { "[LDClient] sending #{description}: #{body}" }
|
34
|
+
req = Net::HTTP::Post.new(uri)
|
35
|
+
req.content_type = "application/json"
|
36
|
+
req.body = event_data
|
37
|
+
Impl::Util.default_http_headers(@sdk_key, @config).each { |k, v| req[k] = v }
|
38
|
+
if !is_diagnostic
|
39
|
+
req["X-LaunchDarkly-Event-Schema"] = CURRENT_SCHEMA_VERSION.to_s
|
40
|
+
req["X-LaunchDarkly-Payload-ID"] = payload_id
|
41
|
+
end
|
42
|
+
req["Connection"] = "keep-alive"
|
43
|
+
res = @client.request(req)
|
44
|
+
rescue StandardError => exn
|
45
|
+
@logger.warn { "[LDClient] Error sending events: #{exn.inspect}." }
|
46
|
+
next
|
47
|
+
end
|
48
|
+
status = res.code.to_i
|
49
|
+
if status >= 200 && status < 300
|
50
|
+
res_time = nil
|
51
|
+
if !res["date"].nil?
|
52
|
+
begin
|
53
|
+
res_time = Time.httpdate(res["date"])
|
54
|
+
rescue ArgumentError
|
55
|
+
end
|
56
|
+
end
|
57
|
+
return EventSenderResult.new(true, false, res_time)
|
58
|
+
end
|
59
|
+
must_shutdown = !LaunchDarkly::Util.http_error_recoverable?(status)
|
60
|
+
can_retry = !must_shutdown && attempt == 0
|
61
|
+
message = LaunchDarkly::Util.http_error_message(status, "event delivery", can_retry ? "will retry" : "some events were dropped")
|
62
|
+
@logger.error { "[LDClient] #{message}" }
|
63
|
+
if must_shutdown
|
64
|
+
return EventSenderResult.new(false, true, nil)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
# used up our retries
|
68
|
+
return EventSenderResult.new(false, false, nil)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module LaunchDarkly
|
3
|
+
module Impl
|
4
|
+
module Util
|
5
|
+
def self.current_time_millis
|
6
|
+
(Time.now.to_f * 1000).to_i
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.default_http_headers(sdk_key, config)
|
10
|
+
ret = { "Authorization" => sdk_key, "User-Agent" => "RubyClient/" + LaunchDarkly::VERSION }
|
11
|
+
if config.wrapper_name
|
12
|
+
ret["X-LaunchDarkly-Wrapper"] = config.wrapper_name +
|
13
|
+
(config.wrapper_version ? "/" + config.wrapper_version : "")
|
14
|
+
end
|
15
|
+
ret
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/ldclient-rb/ldclient.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "ldclient-rb/impl/diagnostic_events"
|
1
2
|
require "ldclient-rb/impl/event_factory"
|
2
3
|
require "ldclient-rb/impl/store_client_wrapper"
|
3
4
|
require "concurrent/atomics"
|
@@ -46,10 +47,16 @@ module LaunchDarkly
|
|
46
47
|
updated_config.instance_variable_set(:@feature_store, @store)
|
47
48
|
@config = updated_config
|
48
49
|
|
50
|
+
if !@config.offline? && @config.send_events && !@config.diagnostic_opt_out?
|
51
|
+
diagnostic_accumulator = Impl::DiagnosticAccumulator.new(Impl::DiagnosticAccumulator.create_diagnostic_id(sdk_key))
|
52
|
+
else
|
53
|
+
diagnostic_accumulator = nil
|
54
|
+
end
|
55
|
+
|
49
56
|
if @config.offline? || !@config.send_events
|
50
57
|
@event_processor = NullEventProcessor.new
|
51
58
|
else
|
52
|
-
@event_processor = EventProcessor.new(sdk_key, config)
|
59
|
+
@event_processor = EventProcessor.new(sdk_key, config, diagnostic_accumulator)
|
53
60
|
end
|
54
61
|
|
55
62
|
if @config.use_ldd?
|
@@ -59,7 +66,13 @@ module LaunchDarkly
|
|
59
66
|
|
60
67
|
data_source_or_factory = @config.data_source || self.method(:create_default_data_source)
|
61
68
|
if data_source_or_factory.respond_to? :call
|
62
|
-
|
69
|
+
# Currently, data source factories take two parameters unless they need to be aware of diagnostic_accumulator, in
|
70
|
+
# which case they take three parameters. This will be changed in the future to use a less awkware mechanism.
|
71
|
+
if data_source_or_factory.arity == 3
|
72
|
+
@data_source = data_source_or_factory.call(sdk_key, @config, diagnostic_accumulator)
|
73
|
+
else
|
74
|
+
@data_source = data_source_or_factory.call(sdk_key, @config)
|
75
|
+
end
|
63
76
|
else
|
64
77
|
@data_source = data_source_or_factory
|
65
78
|
end
|
@@ -335,13 +348,13 @@ module LaunchDarkly
|
|
335
348
|
|
336
349
|
private
|
337
350
|
|
338
|
-
def create_default_data_source(sdk_key, config)
|
351
|
+
def create_default_data_source(sdk_key, config, diagnostic_accumulator)
|
339
352
|
if config.offline?
|
340
353
|
return NullUpdateProcessor.new
|
341
354
|
end
|
342
355
|
requestor = Requestor.new(sdk_key, config)
|
343
356
|
if config.stream?
|
344
|
-
StreamProcessor.new(sdk_key, config, requestor)
|
357
|
+
StreamProcessor.new(sdk_key, config, requestor, diagnostic_accumulator)
|
345
358
|
else
|
346
359
|
config.logger.info { "Disabling streaming API" }
|
347
360
|
config.logger.warn { "You should only disable the streaming API if instructed to do so by LaunchDarkly support" }
|
@@ -51,8 +51,7 @@ module LaunchDarkly
|
|
51
51
|
@client.start if !@client.started?
|
52
52
|
uri = URI(@config.base_uri + path)
|
53
53
|
req = Net::HTTP::Get.new(uri)
|
54
|
-
req[
|
55
|
-
req["User-Agent"] = "RubyClient/" + LaunchDarkly::VERSION
|
54
|
+
Impl::Util.default_http_headers(@sdk_key, @config).each { |k, v| req[k] = v }
|
56
55
|
req["Connection"] = "keep-alive"
|
57
56
|
cached = @cache.read(uri)
|
58
57
|
if !cached.nil?
|
data/lib/ldclient-rb/stream.rb
CHANGED
@@ -24,7 +24,7 @@ module LaunchDarkly
|
|
24
24
|
|
25
25
|
# @private
|
26
26
|
class StreamProcessor
|
27
|
-
def initialize(sdk_key, config, requestor)
|
27
|
+
def initialize(sdk_key, config, requestor, diagnostic_accumulator = nil)
|
28
28
|
@sdk_key = sdk_key
|
29
29
|
@config = config
|
30
30
|
@feature_store = config.feature_store
|
@@ -33,6 +33,7 @@ module LaunchDarkly
|
|
33
33
|
@started = Concurrent::AtomicBoolean.new(false)
|
34
34
|
@stopped = Concurrent::AtomicBoolean.new(false)
|
35
35
|
@ready = Concurrent::Event.new
|
36
|
+
@connection_attempt_start_time = 0
|
36
37
|
end
|
37
38
|
|
38
39
|
def initialized?
|
@@ -44,18 +45,17 @@ module LaunchDarkly
|
|
44
45
|
|
45
46
|
@config.logger.info { "[LDClient] Initializing stream connection" }
|
46
47
|
|
47
|
-
headers =
|
48
|
-
'Authorization' => @sdk_key,
|
49
|
-
'User-Agent' => 'RubyClient/' + LaunchDarkly::VERSION
|
50
|
-
}
|
48
|
+
headers = Impl::Util.default_http_headers(@sdk_key, @config)
|
51
49
|
opts = {
|
52
50
|
headers: headers,
|
53
51
|
read_timeout: READ_TIMEOUT_SECONDS,
|
54
52
|
logger: @config.logger
|
55
53
|
}
|
54
|
+
log_connection_started
|
56
55
|
@es = SSE::Client.new(@config.stream_uri + "/all", **opts) do |conn|
|
57
56
|
conn.on_event { |event| process_message(event) }
|
58
57
|
conn.on_error { |err|
|
58
|
+
log_connection_result(false)
|
59
59
|
case err
|
60
60
|
when SSE::Errors::HTTPStatusError
|
61
61
|
status = err.status
|
@@ -82,6 +82,7 @@ module LaunchDarkly
|
|
82
82
|
private
|
83
83
|
|
84
84
|
def process_message(message)
|
85
|
+
log_connection_result(true)
|
85
86
|
method = message.type
|
86
87
|
@config.logger.debug { "[LDClient] Stream received #{method} message: #{message.data}" }
|
87
88
|
if method == PUT
|
@@ -137,5 +138,17 @@ module LaunchDarkly
|
|
137
138
|
def key_for_path(kind, path)
|
138
139
|
path.start_with?(KEY_PATHS[kind]) ? path[KEY_PATHS[kind].length..-1] : nil
|
139
140
|
end
|
141
|
+
|
142
|
+
def log_connection_started
|
143
|
+
@connection_attempt_start_time = Impl::Util::current_time_millis
|
144
|
+
end
|
145
|
+
|
146
|
+
def log_connection_result(is_success)
|
147
|
+
if !@diagnostic_accumulator.nil? && @connection_attempt_start_time > 0
|
148
|
+
@diagnostic_accumulator.record_stream_init(@connection_attempt_start_time, !is_success,
|
149
|
+
Impl::Util::current_time_millis - @connection_attempt_start_time)
|
150
|
+
@connection_attempt_start_time = 0
|
151
|
+
end
|
152
|
+
end
|
140
153
|
end
|
141
154
|
end
|
data/lib/ldclient-rb/version.rb
CHANGED
@@ -0,0 +1,163 @@
|
|
1
|
+
require "ldclient-rb/impl/diagnostic_events"
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
module LaunchDarkly
|
6
|
+
module Impl
|
7
|
+
describe DiagnosticAccumulator do
|
8
|
+
subject { DiagnosticAccumulator }
|
9
|
+
|
10
|
+
let(:sdk_key) { "sdk_key" }
|
11
|
+
let(:default_id) { subject.create_diagnostic_id("my-key") }
|
12
|
+
let(:default_acc) { subject.new(default_id) }
|
13
|
+
|
14
|
+
it "creates unique ID with SDK key suffix" do
|
15
|
+
id1 = subject.create_diagnostic_id("1234567890")
|
16
|
+
expect(id1[:sdkKeySuffix]).to eq "567890"
|
17
|
+
expect(id1[:diagnosticId]).not_to be_nil
|
18
|
+
|
19
|
+
id2 = subject.create_diagnostic_id("1234567890")
|
20
|
+
expect(id2[:diagnosticId]).not_to eq id1[:diagnosticId]
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "init event" do
|
24
|
+
def expected_default_config
|
25
|
+
{
|
26
|
+
allAttributesPrivate: false,
|
27
|
+
connectTimeoutMillis: Config.default_connect_timeout * 1000,
|
28
|
+
customBaseURI: false,
|
29
|
+
customEventsURI: false,
|
30
|
+
customStreamURI: false,
|
31
|
+
diagnosticRecordingIntervalMillis: Config.default_diagnostic_recording_interval * 1000,
|
32
|
+
eventsCapacity: Config.default_capacity,
|
33
|
+
eventsFlushIntervalMillis: Config.default_flush_interval * 1000,
|
34
|
+
inlineUsersInEvents: false,
|
35
|
+
pollingIntervalMillis: Config.default_poll_interval * 1000,
|
36
|
+
socketTimeoutMillis: Config.default_read_timeout * 1000,
|
37
|
+
streamingDisabled: false,
|
38
|
+
userKeysCapacity: Config.default_user_keys_capacity,
|
39
|
+
userKeysFlushIntervalMillis: Config.default_user_keys_flush_interval * 1000,
|
40
|
+
usingProxy: false,
|
41
|
+
usingRelayDaemon: false
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
it "has basic fields" do
|
46
|
+
event = default_acc.create_init_event(Config.new)
|
47
|
+
expect(event[:kind]).to eq 'diagnostic-init'
|
48
|
+
expect(event[:creationDate]).not_to be_nil
|
49
|
+
expect(event[:id]).to eq default_id
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can have default config data" do
|
53
|
+
event = default_acc.create_init_event(Config.new)
|
54
|
+
expect(event[:configuration]).to eq expected_default_config
|
55
|
+
end
|
56
|
+
|
57
|
+
it "can have custom config data" do
|
58
|
+
changes_and_expected = [
|
59
|
+
[ { all_attributes_private: true }, { allAttributesPrivate: true } ],
|
60
|
+
[ { connect_timeout: 46 }, { connectTimeoutMillis: 46000 } ],
|
61
|
+
[ { base_uri: 'http://custom' }, { customBaseURI: true } ],
|
62
|
+
[ { events_uri: 'http://custom' }, { customEventsURI: true } ],
|
63
|
+
[ { stream_uri: 'http://custom' }, { customStreamURI: true } ],
|
64
|
+
[ { diagnostic_recording_interval: 9999 }, { diagnosticRecordingIntervalMillis: 9999000 } ],
|
65
|
+
[ { capacity: 4000 }, { eventsCapacity: 4000 } ],
|
66
|
+
[ { flush_interval: 46 }, { eventsFlushIntervalMillis: 46000 } ],
|
67
|
+
[ { inline_users_in_events: true }, { inlineUsersInEvents: true } ],
|
68
|
+
[ { poll_interval: 999 }, { pollingIntervalMillis: 999000 } ],
|
69
|
+
[ { read_timeout: 46 }, { socketTimeoutMillis: 46000 } ],
|
70
|
+
[ { stream: false }, { streamingDisabled: true } ],
|
71
|
+
[ { user_keys_capacity: 999 }, { userKeysCapacity: 999 } ],
|
72
|
+
[ { user_keys_flush_interval: 999 }, { userKeysFlushIntervalMillis: 999000 } ],
|
73
|
+
[ { use_ldd: true }, { usingRelayDaemon: true } ]
|
74
|
+
]
|
75
|
+
changes_and_expected.each do |config_values, expected_values|
|
76
|
+
config = Config.new(config_values)
|
77
|
+
event = default_acc.create_init_event(config)
|
78
|
+
expect(event[:configuration]).to eq expected_default_config.merge(expected_values)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "detects proxy" do
|
83
|
+
begin
|
84
|
+
ENV["http_proxy"] = 'http://my-proxy'
|
85
|
+
event = default_acc.create_init_event(Config.new)
|
86
|
+
expect(event[:configuration][:usingProxy]).to be true
|
87
|
+
ensure
|
88
|
+
ENV["http_proxy"] = nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it "has expected SDK data" do
|
93
|
+
event = default_acc.create_init_event(Config.new)
|
94
|
+
expect(event[:sdk]).to eq ({
|
95
|
+
name: 'ruby-server-sdk',
|
96
|
+
version: LaunchDarkly::VERSION
|
97
|
+
})
|
98
|
+
end
|
99
|
+
|
100
|
+
it "has expected SDK data with wrapper" do
|
101
|
+
event = default_acc.create_init_event(Config.new(wrapper_name: 'my-wrapper', wrapper_version: '2.0'))
|
102
|
+
expect(event[:sdk]).to eq ({
|
103
|
+
name: 'ruby-server-sdk',
|
104
|
+
version: LaunchDarkly::VERSION,
|
105
|
+
wrapperName: 'my-wrapper',
|
106
|
+
wrapperVersion: '2.0'
|
107
|
+
})
|
108
|
+
end
|
109
|
+
|
110
|
+
it "has expected platform data" do
|
111
|
+
event = default_acc.create_init_event(Config.new)
|
112
|
+
expect(event[:platform]).to include ({
|
113
|
+
name: 'ruby'
|
114
|
+
})
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "periodic event" do
|
119
|
+
it "has correct default values" do
|
120
|
+
acc = subject.new(default_id)
|
121
|
+
event = acc.create_periodic_event_and_reset(2, 3, 4)
|
122
|
+
expect(event).to include({
|
123
|
+
kind: 'diagnostic',
|
124
|
+
id: default_id,
|
125
|
+
droppedEvents: 2,
|
126
|
+
deduplicatedUsers: 3,
|
127
|
+
eventsInLastBatch: 4,
|
128
|
+
streamInits: []
|
129
|
+
})
|
130
|
+
expect(event[:creationDate]).not_to be_nil
|
131
|
+
expect(event[:dataSinceDate]).not_to be_nil
|
132
|
+
end
|
133
|
+
|
134
|
+
it "can add stream init" do
|
135
|
+
acc = subject.new(default_id)
|
136
|
+
acc.record_stream_init(1000, false, 2000)
|
137
|
+
event = acc.create_periodic_event_and_reset(0, 0, 0)
|
138
|
+
expect(event[:streamInits]).to eq [{ timestamp: 1000, failed: false, durationMillis: 2000 }]
|
139
|
+
end
|
140
|
+
|
141
|
+
it "resets fields after creating event" do
|
142
|
+
acc = subject.new(default_id)
|
143
|
+
acc.record_stream_init(1000, false, 2000)
|
144
|
+
event1 = acc.create_periodic_event_and_reset(2, 3, 4)
|
145
|
+
event2 = acc.create_periodic_event_and_reset(5, 6, 7)
|
146
|
+
expect(event1).to include ({
|
147
|
+
droppedEvents: 2,
|
148
|
+
deduplicatedUsers: 3,
|
149
|
+
eventsInLastBatch: 4,
|
150
|
+
streamInits: [{ timestamp: 1000, failed: false, durationMillis: 2000 }]
|
151
|
+
})
|
152
|
+
expect(event2).to include ({
|
153
|
+
dataSinceDate: event1[:creationDate],
|
154
|
+
droppedEvents: 5,
|
155
|
+
deduplicatedUsers: 6,
|
156
|
+
eventsInLastBatch: 7,
|
157
|
+
streamInits: []
|
158
|
+
})
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|