launchdarkly-server-sdk 5.6.2 → 5.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|