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,120 +0,0 @@
1
-
2
- module LaunchDarkly
3
- module Impl
4
- # Event constructors are centralized here to avoid mistakes and repetitive logic.
5
- # The LDClient owns two instances of EventFactory: one that always embeds evaluation reasons
6
- # in the events (for when variation_detail is called) and one that doesn't.
7
- #
8
- # Note that these methods do not set the "creationDate" property, because in the Ruby client,
9
- # that is done by EventProcessor.add_event().
10
- class EventFactory
11
- def initialize(with_reasons)
12
- @with_reasons = with_reasons
13
- end
14
-
15
- def new_eval_event(flag, user, detail, default_value, prereq_of_flag = nil)
16
- add_experiment_data = is_experiment(flag, detail.reason)
17
- e = {
18
- kind: 'feature',
19
- key: flag[:key],
20
- user: user,
21
- variation: detail.variation_index,
22
- value: detail.value,
23
- default: default_value,
24
- version: flag[:version]
25
- }
26
- # the following properties are handled separately so we don't waste bandwidth on unused keys
27
- e[:trackEvents] = true if add_experiment_data || flag[:trackEvents]
28
- e[:debugEventsUntilDate] = flag[:debugEventsUntilDate] if flag[:debugEventsUntilDate]
29
- e[:prereqOf] = prereq_of_flag[:key] if !prereq_of_flag.nil?
30
- e[:reason] = detail.reason if add_experiment_data || @with_reasons
31
- e[:contextKind] = context_to_context_kind(user) if !user.nil? && user[:anonymous]
32
- e
33
- end
34
-
35
- def new_default_event(flag, user, default_value, reason)
36
- e = {
37
- kind: 'feature',
38
- key: flag[:key],
39
- user: user,
40
- value: default_value,
41
- default: default_value,
42
- version: flag[:version]
43
- }
44
- e[:trackEvents] = true if flag[:trackEvents]
45
- e[:debugEventsUntilDate] = flag[:debugEventsUntilDate] if flag[:debugEventsUntilDate]
46
- e[:reason] = reason if @with_reasons
47
- e[:contextKind] = context_to_context_kind(user) if !user.nil? && user[:anonymous]
48
- e
49
- end
50
-
51
- def new_unknown_flag_event(key, user, default_value, reason)
52
- e = {
53
- kind: 'feature',
54
- key: key,
55
- user: user,
56
- value: default_value,
57
- default: default_value
58
- }
59
- e[:reason] = reason if @with_reasons
60
- e[:contextKind] = context_to_context_kind(user) if !user.nil? && user[:anonymous]
61
- e
62
- end
63
-
64
- def new_identify_event(user)
65
- {
66
- kind: 'identify',
67
- key: user[:key],
68
- user: user
69
- }
70
- end
71
-
72
- def new_alias_event(current_context, previous_context)
73
- {
74
- kind: 'alias',
75
- key: current_context[:key],
76
- contextKind: context_to_context_kind(current_context),
77
- previousKey: previous_context[:key],
78
- previousContextKind: context_to_context_kind(previous_context)
79
- }
80
- end
81
-
82
- def new_custom_event(event_name, user, data, metric_value)
83
- e = {
84
- kind: 'custom',
85
- key: event_name,
86
- user: user
87
- }
88
- e[:data] = data if !data.nil?
89
- e[:metricValue] = metric_value if !metric_value.nil?
90
- e[:contextKind] = context_to_context_kind(user) if !user.nil? && user[:anonymous]
91
- e
92
- end
93
-
94
- private
95
-
96
- def context_to_context_kind(user)
97
- if !user.nil? && user[:anonymous]
98
- return "anonymousUser"
99
- else
100
- return "user"
101
- end
102
- end
103
-
104
- def is_experiment(flag, reason)
105
- return false if !reason
106
- case reason[:kind]
107
- when 'RULE_MATCH'
108
- index = reason[:ruleIndex]
109
- if !index.nil?
110
- rules = flag[:rules] || []
111
- return index >= 0 && index < rules.length && rules[index][:trackEvents]
112
- end
113
- when 'FALLTHROUGH'
114
- return !!flag[:trackEventsFallthrough]
115
- end
116
- false
117
- end
118
- end
119
- end
120
- end
data/spec/config_spec.rb DELETED
@@ -1,63 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe LaunchDarkly::Config do
4
- subject { LaunchDarkly::Config }
5
- describe ".initialize" do
6
- it "can be initialized with default settings" do
7
- expect(subject).to receive(:default_capacity).and_return 1234
8
- expect(subject.new.capacity).to eq 1234
9
- end
10
- it "accepts custom arguments" do
11
- expect(subject).to_not receive(:default_capacity)
12
- expect(subject.new(capacity: 50).capacity).to eq 50
13
- end
14
- it "will chomp base_url and stream_uri" do
15
- uri = "https://test.launchdarkly.com"
16
- config = subject.new(base_uri: uri + "/")
17
- expect(config.base_uri).to eq uri
18
- end
19
- end
20
- describe "@base_uri" do
21
- it "can be read" do
22
- expect(subject.new.base_uri).to eq subject.default_base_uri
23
- end
24
- end
25
- describe "@events_uri" do
26
- it "can be read" do
27
- expect(subject.new.events_uri).to eq subject.default_events_uri
28
- end
29
- end
30
- describe "@stream_uri" do
31
- it "can be read" do
32
- expect(subject.new.stream_uri).to eq subject.default_stream_uri
33
- end
34
- end
35
- describe ".default_cache_store" do
36
- it "uses Rails cache if it is available" do
37
- rails = instance_double("Rails", cache: :cache)
38
- stub_const("Rails", rails)
39
- expect(subject.default_cache_store).to eq :cache
40
- end
41
- it "uses memory store if Rails is not available" do
42
- expect(subject.default_cache_store).to be_an_instance_of LaunchDarkly::ThreadSafeMemoryStore
43
- end
44
- end
45
- describe ".default_logger" do
46
- it "uses Rails logger if it is available" do
47
- rails = instance_double("Rails", logger: :logger)
48
- stub_const("Rails", rails)
49
- expect(subject.default_logger).to eq :logger
50
- end
51
- it "Uses logger if Rails is not available" do
52
- expect(subject.default_logger).to be_an_instance_of Logger
53
- end
54
- end
55
- describe ".poll_interval" do
56
- it "can be set to greater than the default" do
57
- expect(subject.new(poll_interval: 31).poll_interval).to eq 31
58
- end
59
- it "cannot be set to less than the default" do
60
- expect(subject.new(poll_interval: 29).poll_interval).to eq 30
61
- end
62
- end
63
- end
@@ -1,163 +0,0 @@
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
@@ -1,135 +0,0 @@
1
- require "spec_helper"
2
-
3
- module LaunchDarkly
4
- describe "EvaluationDetail" do
5
- subject { EvaluationDetail }
6
-
7
- it "sets properties" do
8
- expect(EvaluationDetail.new("x", 0, EvaluationReason::off).value).to eq "x"
9
- expect(EvaluationDetail.new("x", 0, EvaluationReason::off).variation_index).to eq 0
10
- expect(EvaluationDetail.new("x", 0, EvaluationReason::off).reason).to eq EvaluationReason::off
11
- end
12
-
13
- it "checks parameter types" do
14
- expect { EvaluationDetail.new(nil, nil, EvaluationReason::off) }.not_to raise_error
15
- expect { EvaluationDetail.new(nil, 0, EvaluationReason::off) }.not_to raise_error
16
- expect { EvaluationDetail.new(nil, "x", EvaluationReason::off) }.to raise_error(ArgumentError)
17
- expect { EvaluationDetail.new(nil, 0, { kind: "OFF" }) }.to raise_error(ArgumentError)
18
- expect { EvaluationDetail.new(nil, 0, nil) }.to raise_error(ArgumentError)
19
- end
20
-
21
- it "equality test" do
22
- expect(EvaluationDetail.new("x", 0, EvaluationReason::off)).to eq EvaluationDetail.new("x", 0, EvaluationReason::off)
23
- expect(EvaluationDetail.new("x", 0, EvaluationReason::off)).not_to eq EvaluationDetail.new("y", 0, EvaluationReason::off)
24
- expect(EvaluationDetail.new("x", 0, EvaluationReason::off)).not_to eq EvaluationDetail.new("x", 1, EvaluationReason::off)
25
- expect(EvaluationDetail.new("x", 0, EvaluationReason::off)).not_to eq EvaluationDetail.new("x", 0, EvaluationReason::fallthrough)
26
- end
27
- end
28
-
29
- describe "EvaluationReason" do
30
- subject { EvaluationReason }
31
-
32
- values = [
33
- [ EvaluationReason::off, EvaluationReason::OFF, { "kind" => "OFF" }, "OFF", nil ],
34
- [ EvaluationReason::fallthrough, EvaluationReason::FALLTHROUGH,
35
- { "kind" => "FALLTHROUGH" }, "FALLTHROUGH", nil ],
36
- [ EvaluationReason::target_match, EvaluationReason::TARGET_MATCH,
37
- { "kind" => "TARGET_MATCH" }, "TARGET_MATCH", nil ],
38
- [ EvaluationReason::rule_match(1, "x"), EvaluationReason::RULE_MATCH,
39
- { "kind" => "RULE_MATCH", "ruleIndex" => 1, "ruleId" => "x" }, "RULE_MATCH(1,x)",
40
- [ EvaluationReason::rule_match(2, "x"), EvaluationReason::rule_match(1, "y") ] ],
41
- [ EvaluationReason::prerequisite_failed("x"), EvaluationReason::PREREQUISITE_FAILED,
42
- { "kind" => "PREREQUISITE_FAILED", "prerequisiteKey" => "x" }, "PREREQUISITE_FAILED(x)" ],
43
- [ EvaluationReason::error(EvaluationReason::ERROR_FLAG_NOT_FOUND), EvaluationReason::ERROR,
44
- { "kind" => "ERROR", "errorKind" => "FLAG_NOT_FOUND" }, "ERROR(FLAG_NOT_FOUND)" ]
45
- ]
46
- values.each_index do |i|
47
- params = values[i]
48
- reason = params[0]
49
- kind = params[1]
50
- json_rep = params[2]
51
- brief_str = params[3]
52
- unequal_values = params[4]
53
-
54
- describe "reason #{reason.kind}" do
55
- it "has correct kind" do
56
- expect(reason.kind).to eq kind
57
- end
58
-
59
- it "equality to self" do
60
- expect(reason).to eq reason
61
- end
62
-
63
- it "inequality to others" do
64
- values.each_index do |j|
65
- if i != j
66
- expect(reason).not_to eq values[j][0]
67
- end
68
- end
69
- if !unequal_values.nil?
70
- unequal_values.each do |v|
71
- expect(reason).not_to eq v
72
- end
73
- end
74
- end
75
-
76
- it "JSON representation" do
77
- expect(JSON.parse(reason.as_json.to_json)).to eq json_rep
78
- expect(JSON.parse(reason.to_json)).to eq json_rep
79
- end
80
-
81
- it "brief representation" do
82
- expect(reason.inspect).to eq brief_str
83
- expect(reason.to_s).to eq brief_str
84
- end
85
- end
86
- end
87
-
88
- it "reuses singleton reasons" do
89
- expect(EvaluationReason::off).to be EvaluationReason::off
90
- expect(EvaluationReason::fallthrough).to be EvaluationReason::fallthrough
91
- expect(EvaluationReason::target_match).to be EvaluationReason::target_match
92
- expect(EvaluationReason::rule_match(1, 'x')).not_to be EvaluationReason::rule_match(1, 'x')
93
- expect(EvaluationReason::prerequisite_failed('x')).not_to be EvaluationReason::prerequisite_failed('x')
94
- errors = [ EvaluationReason::ERROR_CLIENT_NOT_READY, EvaluationReason::ERROR_FLAG_NOT_FOUND,
95
- EvaluationReason::ERROR_MALFORMED_FLAG, EvaluationReason::ERROR_USER_NOT_SPECIFIED, EvaluationReason::ERROR_EXCEPTION ]
96
- errors.each do |e|
97
- expect(EvaluationReason::error(e)).to be EvaluationReason::error(e)
98
- end
99
- end
100
-
101
- it "supports [] with JSON property names" do
102
- expect(EvaluationReason::off[:kind]).to eq "OFF"
103
- expect(EvaluationReason::off[:ruleIndex]).to be nil
104
- expect(EvaluationReason::off[:ruleId]).to be nil
105
- expect(EvaluationReason::off[:prerequisiteKey]).to be nil
106
- expect(EvaluationReason::off[:errorKind]).to be nil
107
- expect(EvaluationReason::rule_match(1, "x")[:ruleIndex]).to eq 1
108
- expect(EvaluationReason::rule_match(1, "x")[:ruleId]).to eq "x"
109
- expect(EvaluationReason::prerequisite_failed("x")[:prerequisiteKey]).to eq "x"
110
- expect(EvaluationReason::error(EvaluationReason::ERROR_FLAG_NOT_FOUND)[:errorKind]).to eq "FLAG_NOT_FOUND"
111
- end
112
-
113
- it "freezes string properties" do
114
- rm = EvaluationReason::rule_match(1, "x")
115
- expect { rm.rule_id.upcase! }.to raise_error(RuntimeError)
116
- pf = EvaluationReason::prerequisite_failed("x")
117
- expect { pf.prerequisite_key.upcase! }.to raise_error(RuntimeError)
118
- end
119
-
120
- it "checks parameter types" do
121
- expect { EvaluationReason::rule_match(nil, "x") }.to raise_error(ArgumentError)
122
- expect { EvaluationReason::rule_match(true, "x") }.to raise_error(ArgumentError)
123
- expect { EvaluationReason::rule_match(1, nil) }.not_to raise_error # we allow nil rule_id for backward compatibility
124
- expect { EvaluationReason::rule_match(1, 9) }.to raise_error(ArgumentError)
125
- expect { EvaluationReason::prerequisite_failed(nil) }.to raise_error(ArgumentError)
126
- expect { EvaluationReason::prerequisite_failed(9) }.to raise_error(ArgumentError)
127
- expect { EvaluationReason::error(nil) }.to raise_error(ArgumentError)
128
- expect { EvaluationReason::error(9) }.to raise_error(ArgumentError)
129
- end
130
-
131
- it "does not allow direct access to constructor" do
132
- expect { EvaluationReason.new(:off, nil, nil, nil, nil) }.to raise_error(NoMethodError)
133
- end
134
- end
135
- end
@@ -1,197 +0,0 @@
1
- require "ldclient-rb/impl/event_sender"
2
-
3
- require "http_util"
4
- require "spec_helper"
5
-
6
- require "time"
7
-
8
- module LaunchDarkly
9
- module Impl
10
- describe EventSender do
11
- subject { EventSender }
12
-
13
- let(:sdk_key) { "sdk_key" }
14
- let(:fake_data) { '{"things":[]}' }
15
-
16
- def make_sender(server)
17
- subject.new(sdk_key, Config.new(events_uri: server.base_uri.to_s, logger: $null_log), nil, 0.1)
18
- end
19
-
20
- def with_sender_and_server
21
- with_server do |server|
22
- yield make_sender(server), server
23
- end
24
- end
25
-
26
- it "sends analytics event data" do
27
- with_sender_and_server do |es, server|
28
- server.setup_ok_response("/bulk", "")
29
-
30
- result = es.send_event_data(fake_data, "", false)
31
-
32
- expect(result.success).to be true
33
- expect(result.must_shutdown).to be false
34
- expect(result.time_from_server).not_to be_nil
35
-
36
- req = server.await_request
37
- expect(req.body).to eq fake_data
38
- expect(req.header).to include({
39
- "authorization" => [ sdk_key ],
40
- "content-type" => [ "application/json" ],
41
- "user-agent" => [ "RubyClient/" + LaunchDarkly::VERSION ],
42
- "x-launchdarkly-event-schema" => [ "3" ],
43
- "connection" => [ "Keep-Alive" ]
44
- })
45
- expect(req.header['x-launchdarkly-payload-id']).not_to eq []
46
- end
47
- end
48
-
49
- it "can use a socket factory" do
50
- with_server do |server|
51
- server.setup_ok_response("/bulk", "")
52
-
53
- config = Config.new(events_uri: "http://events.com/bulk", socket_factory: SocketFactoryFromHash.new({"events.com" => server.port}), logger: $null_log)
54
- es = subject.new(sdk_key, config, nil, 0.1)
55
-
56
- result = es.send_event_data(fake_data, "", false)
57
-
58
- expect(result.success).to be true
59
- req = server.await_request
60
- expect(req.body).to eq fake_data
61
- expect(req.host).to eq "events.com"
62
- end
63
- end
64
-
65
- it "generates a new payload ID for each payload" do
66
- with_sender_and_server do |es, server|
67
- server.setup_ok_response("/bulk", "")
68
-
69
- result1 = es.send_event_data(fake_data, "", false)
70
- result2 = es.send_event_data(fake_data, "", false)
71
- expect(result1.success).to be true
72
- expect(result2.success).to be true
73
-
74
- req1, body1 = server.await_request_with_body
75
- req2, body2 = server.await_request_with_body
76
- expect(body1).to eq fake_data
77
- expect(body2).to eq fake_data
78
- expect(req1.header['x-launchdarkly-payload-id']).not_to eq req2.header['x-launchdarkly-payload-id']
79
- end
80
- end
81
-
82
- it "sends diagnostic event data" do
83
- with_sender_and_server do |es, server|
84
- server.setup_ok_response("/diagnostic", "")
85
-
86
- result = es.send_event_data(fake_data, "", true)
87
-
88
- expect(result.success).to be true
89
- expect(result.must_shutdown).to be false
90
- expect(result.time_from_server).not_to be_nil
91
-
92
- req, body = server.await_request_with_body
93
- expect(body).to eq fake_data
94
- expect(req.header).to include({
95
- "authorization" => [ sdk_key ],
96
- "content-type" => [ "application/json" ],
97
- "user-agent" => [ "RubyClient/" + LaunchDarkly::VERSION ],
98
- "connection" => [ "Keep-Alive" ]
99
- })
100
- expect(req.header['x-launchdarkly-event-schema']).to eq []
101
- expect(req.header['x-launchdarkly-payload-id']).to eq []
102
- end
103
- end
104
-
105
- it "can use a proxy server" do
106
- with_server do |server|
107
- server.setup_ok_response("/bulk", "")
108
-
109
- with_server(StubProxyServer.new) do |proxy|
110
- begin
111
- ENV["http_proxy"] = proxy.base_uri.to_s
112
-
113
- es = make_sender(server)
114
-
115
- result = es.send_event_data(fake_data, "", false)
116
-
117
- expect(result.success).to be true
118
-
119
- req, body = server.await_request_with_body
120
- expect(body).to eq fake_data
121
- ensure
122
- ENV["http_proxy"] = nil
123
- end
124
- end
125
- end
126
- end
127
-
128
- [400, 408, 429, 500].each do |status|
129
- it "handles recoverable error #{status}" do
130
- with_sender_and_server do |es, server|
131
- req_count = 0
132
- server.setup_response("/bulk") do |req, res|
133
- req_count = req_count + 1
134
- res.status = req_count == 2 ? 200 : status
135
- end
136
-
137
- result = es.send_event_data(fake_data, "", false)
138
-
139
- expect(result.success).to be true
140
- expect(result.must_shutdown).to be false
141
- expect(result.time_from_server).not_to be_nil
142
-
143
- expect(server.requests.count).to eq 2
144
- req1, body1 = server.await_request_with_body
145
- req2, body2 = server.await_request_with_body
146
- expect(body1).to eq fake_data
147
- expect(body2).to eq fake_data
148
- expect(req1.header['x-launchdarkly-payload-id']).to eq req2.header['x-launchdarkly-payload-id']
149
- end
150
- end
151
- end
152
-
153
- [400, 408, 429, 500].each do |status|
154
- it "only retries error #{status} once" do
155
- with_sender_and_server do |es, server|
156
- req_count = 0
157
- server.setup_response("/bulk") do |req, res|
158
- req_count = req_count + 1
159
- res.status = req_count == 3 ? 200 : status
160
- end
161
-
162
- result = es.send_event_data(fake_data, "", false)
163
-
164
- expect(result.success).to be false
165
- expect(result.must_shutdown).to be false
166
- expect(result.time_from_server).to be_nil
167
-
168
- expect(server.requests.count).to eq 2
169
- req1, body1 = server.await_request_with_body
170
- req2, body2 = server.await_request_with_body
171
- expect(body1).to eq fake_data
172
- expect(body2).to eq fake_data
173
- expect(req1.header['x-launchdarkly-payload-id']).to eq req2.header['x-launchdarkly-payload-id']
174
- end
175
- end
176
- end
177
-
178
- [401, 403].each do |status|
179
- it "gives up after unrecoverable error #{status}" do
180
- with_sender_and_server do |es, server|
181
- server.setup_response("/bulk") do |req, res|
182
- res.status = status
183
- end
184
-
185
- result = es.send_event_data(fake_data, "", false)
186
-
187
- expect(result.success).to be false
188
- expect(result.must_shutdown).to be true
189
- expect(result.time_from_server).to be_nil
190
-
191
- expect(server.requests.count).to eq 1
192
- end
193
- end
194
- end
195
- end
196
- end
197
- end