karafka-core 2.5.10 → 2.5.12

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +8 -8
  3. data/.github/workflows/push.yml +2 -2
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +16 -0
  6. data/Gemfile.lock +1 -1
  7. data/karafka-core.gemspec +1 -1
  8. data/lib/karafka/core/configurable/node.rb +8 -6
  9. data/lib/karafka/core/contractable/contract.rb +35 -9
  10. data/lib/karafka/core/contractable/result.rb +9 -0
  11. data/lib/karafka/core/instrumentation/callbacks_manager.rb +6 -1
  12. data/lib/karafka/core/monitoring/event.rb +21 -4
  13. data/lib/karafka/core/monitoring/notifications.rb +5 -16
  14. data/lib/karafka/core/monitoring/statistics_decorator.rb +192 -39
  15. data/lib/karafka/core/version.rb +1 -1
  16. metadata +2 -26
  17. data/test/lib/karafka/core/configurable/leaf_test.rb +0 -3
  18. data/test/lib/karafka/core/configurable/node_test.rb +0 -3
  19. data/test/lib/karafka/core/configurable_test.rb +0 -504
  20. data/test/lib/karafka/core/contractable/contract_test.rb +0 -241
  21. data/test/lib/karafka/core/contractable/result_test.rb +0 -106
  22. data/test/lib/karafka/core/contractable/rule_test.rb +0 -5
  23. data/test/lib/karafka/core/contractable_test.rb +0 -3
  24. data/test/lib/karafka/core/helpers/time_test.rb +0 -29
  25. data/test/lib/karafka/core/instrumentation/callbacks_manager_test.rb +0 -81
  26. data/test/lib/karafka/core/instrumentation_test.rb +0 -35
  27. data/test/lib/karafka/core/monitoring/event_test.rb +0 -25
  28. data/test/lib/karafka/core/monitoring/monitor_test.rb +0 -237
  29. data/test/lib/karafka/core/monitoring/notifications_test.rb +0 -275
  30. data/test/lib/karafka/core/monitoring/statistics_decorator_test.rb +0 -284
  31. data/test/lib/karafka/core/monitoring_test.rb +0 -3
  32. data/test/lib/karafka/core/patches/rdkafka/bindings_test.rb +0 -25
  33. data/test/lib/karafka/core/taggable/tags_test.rb +0 -66
  34. data/test/lib/karafka/core/taggable_test.rb +0 -36
  35. data/test/lib/karafka/core/version_test.rb +0 -5
  36. data/test/lib/karafka/core_test.rb +0 -13
  37. data/test/lib/karafka-core_test.rb +0 -3
  38. data/test/support/class_builder.rb +0 -24
  39. data/test/support/describe_current_helper.rb +0 -41
  40. data/test/test_helper.rb +0 -55
@@ -1,241 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe_current do
4
- subject(:validator_class) do
5
- Class.new(described_class) do
6
- configure do |config|
7
- config.error_messages = YAML.safe_load_file(
8
- File.join(Karafka::Core.gem_root, "config", "locales", "errors.yml")
9
- ).fetch("en").fetch("validations").fetch("config")
10
- end
11
-
12
- required(:id) { |id| id.is_a?(String) }
13
-
14
- optional(:test) { |test| test == 5 }
15
- optional(:name) { |name| name == "name" }
16
- end
17
- end
18
-
19
- describe "#validate!" do
20
- subject(:validation) { validator_class.new.validate!(data, ArgumentError) }
21
-
22
- context "when data is valid" do
23
- let(:data) { { id: "1" } }
24
-
25
- it { validation }
26
- end
27
-
28
- context "when data is not valid" do
29
- let(:data) { { id: 1 } }
30
-
31
- it { assert_raises(ArgumentError) { validation } }
32
- end
33
-
34
- context "when optional data is not valid" do
35
- let(:data) { { id: 1, test: Time.now } }
36
-
37
- it { assert_raises(ArgumentError) { validation } }
38
- end
39
-
40
- context "when optional name is not valid" do
41
- let(:data) { { id: 1, name: Time.now } }
42
-
43
- it { assert_raises(ArgumentError) { validation } }
44
- end
45
-
46
- context "when optional name is valid" do
47
- let(:data) { { id: "1", name: "name" } }
48
-
49
- it { validation }
50
- end
51
-
52
- context "when optional data is valid" do
53
- let(:data) { { id: 1, test: nil } }
54
-
55
- it { assert_raises(ArgumentError) { validation } }
56
- end
57
-
58
- context "when validating with extra scope details" do
59
- subject(:validation) do
60
- validator_class.new.validate!(data, ArgumentError, scope: [rand.to_s, rand.to_s])
61
- end
62
-
63
- context "when data is valid" do
64
- let(:data) { { id: "1" } }
65
-
66
- it { validation }
67
- end
68
-
69
- context "when data is not valid" do
70
- let(:data) { { id: 1 } }
71
-
72
- it { assert_raises(ArgumentError) { validation } }
73
- end
74
-
75
- context "when optional data is not valid" do
76
- let(:data) { { id: 1, test: Time.now } }
77
-
78
- it { assert_raises(ArgumentError) { validation } }
79
- end
80
-
81
- context "when optional name is not valid" do
82
- let(:data) { { id: 1, name: Time.now } }
83
-
84
- it { assert_raises(ArgumentError) { validation } }
85
- end
86
-
87
- context "when optional name is valid" do
88
- let(:data) { { id: "1", name: "name" } }
89
-
90
- it { validation }
91
- end
92
-
93
- context "when optional data is valid" do
94
- let(:data) { { id: 1, test: nil } }
95
-
96
- it { assert_raises(ArgumentError) { validation } }
97
- end
98
- end
99
-
100
- context "when error key is not available on error" do
101
- subject(:validator_class) do
102
- Class.new(described_class) do
103
- configure do |config|
104
- config.error_messages = YAML.safe_load_file(
105
- File.join(Karafka::Core.gem_root, "config", "locales", "errors.yml")
106
- ).fetch("en").fetch("validations").fetch("config")
107
- end
108
-
109
- required(:na_id) { |id| id.is_a?(String) }
110
- end
111
- end
112
-
113
- let(:data) { { na_id: 1 } }
114
-
115
- it { assert_raises(KeyError) { validation } }
116
- end
117
- end
118
-
119
- describe "#call" do
120
- context "when interested in the errors and not raising" do
121
- subject(:validation) do
122
- validator_class.new.call(data, scope: scope)
123
- end
124
-
125
- let(:scope) { [rand.to_s, rand.to_s] }
126
-
127
- context "when data is valid" do
128
- let(:data) { { id: "1" } }
129
-
130
- it { assert_equal({}, validation.errors) }
131
- end
132
-
133
- context "when data is not valid" do
134
- let(:data) { { id: 1 } }
135
-
136
- it "expect to have the path key nested with the scope" do
137
- assert_includes validation.errors.keys, :"#{scope.join(".")}.id"
138
- end
139
- end
140
- end
141
- end
142
-
143
- context "when there are nested values in a contract" do
144
- let(:validator_class) do
145
- Class.new(described_class) do
146
- configure do |config|
147
- config.error_messages = YAML.safe_load_file(
148
- File.join(Karafka::Core.gem_root, "config", "locales", "errors.yml")
149
- ).fetch("en").fetch("validations").fetch("test")
150
- end
151
-
152
- nested(:nested) do
153
- required(:id) { |id| id.is_a?(String) }
154
- optional(:id2) { |id| id.is_a?(String) }
155
- end
156
- end
157
- end
158
-
159
- describe "#validate!" do
160
- subject(:validation) { validator_class.new.validate!(data, ArgumentError) }
161
-
162
- context "when data is valid without optional" do
163
- let(:data) { { nested: { id: "1" } } }
164
-
165
- it { validation }
166
- end
167
-
168
- context "when data is valid with optional" do
169
- let(:data) { { nested: { id: "1", id2: "2" } } }
170
-
171
- it { validation }
172
- end
173
-
174
- context "when data is not valid with invalid optional" do
175
- let(:data) { { nested: { id: "1", id2: 2 } } }
176
-
177
- it { assert_raises(ArgumentError) { validation } }
178
- end
179
-
180
- context "when data is not valid" do
181
- let(:data) { { id: 1 } }
182
-
183
- it { assert_raises(ArgumentError) { validation } }
184
- end
185
- end
186
- end
187
-
188
- context "when contract has its own error reported" do
189
- let(:validator_class) do
190
- Class.new(described_class) do
191
- virtual do
192
- [[%i[id], "String error"]]
193
- end
194
- end
195
- end
196
-
197
- subject(:validation) { validator_class.new.validate!(data, ArgumentError) }
198
-
199
- context "when data is valid without optional" do
200
- let(:data) { { nested: { id: "1" } } }
201
-
202
- it { assert_raises(ArgumentError) { validation } }
203
- end
204
- end
205
-
206
- context "when contract has multiple nestings" do
207
- subject(:validator_class) do
208
- Class.new(described_class) do
209
- configure do |config|
210
- config.error_messages = YAML.safe_load_file(
211
- File.join(Karafka::Core.gem_root, "config", "locales", "errors.yml")
212
- ).fetch("en").fetch("validations").fetch("config")
213
- end
214
-
215
- nested(:a) do
216
- nested(:b) do
217
- nested(:c) do
218
- required(:id) { |id| id.is_a?(String) }
219
- end
220
- end
221
- end
222
- end
223
- end
224
-
225
- describe "#validate!" do
226
- subject(:validation) { validator_class.new.validate!(data, ArgumentError) }
227
-
228
- context "when data is valid" do
229
- let(:data) { { a: { b: { c: { id: "1" } } } } }
230
-
231
- it { validation }
232
- end
233
-
234
- context "when data is not valid" do
235
- let(:data) { { id: 1 } }
236
-
237
- it { assert_raises(ArgumentError) { validation } }
238
- end
239
- end
240
- end
241
- end
@@ -1,106 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe_current do
4
- subject(:contract_class) do
5
- Class.new(Karafka::Core::Contractable::Contract) do
6
- configure do |config|
7
- config.error_messages = YAML.safe_load_file(
8
- File.join(Karafka::Core.gem_root, "config", "locales", "errors.yml")
9
- ).fetch("en").fetch("validations").fetch("test")
10
- end
11
-
12
- required(:id) { |id| id.is_a?(String) }
13
-
14
- optional(:test) { |test| test == 5 }
15
- end
16
- end
17
-
18
- let(:contract) { contract_class.new }
19
-
20
- context "when there are no errors" do
21
- let(:data) { { id: "123", test: 5 } }
22
- let(:result) { contract.call(data) }
23
-
24
- it "returns success" do
25
- assert_predicate result, :success?
26
- end
27
-
28
- it "has no errors" do
29
- assert_empty result.errors
30
- end
31
- end
32
-
33
- context "when there are errors and all keys can be mapped to messages" do
34
- let(:data) { { id: 123, test: 4 } }
35
- let(:result) { contract.call(data) }
36
-
37
- it "does not return success" do
38
- refute_predicate result, :success?
39
- end
40
-
41
- it "maps errors to messages" do
42
- assert_equal(
43
- { id: "needs to be a String", test: "needs to be 5" },
44
- result.errors
45
- )
46
- end
47
- end
48
-
49
- context "when there are errors with nested keys" do
50
- subject(:contract_class) do
51
- Class.new(Karafka::Core::Contractable::Contract) do
52
- configure do |config|
53
- config.error_messages = YAML.safe_load_file(
54
- File.join(Karafka::Core.gem_root, "config", "locales", "errors.yml")
55
- ).fetch("en").fetch("validations").fetch("test")
56
- end
57
-
58
- nested(:details) do
59
- required(:id) { |id| id.is_a?(String) }
60
- end
61
- end
62
- end
63
-
64
- let(:data) { { details: { id: 123 } } }
65
- let(:result) { contract.call(data) }
66
-
67
- it "does not return success" do
68
- refute_predicate result, :success?
69
- end
70
-
71
- it "maps nested errors to messages with dot notation" do
72
- assert_equal(
73
- { "details.id": "needs to be a String" },
74
- result.errors
75
- )
76
- end
77
- end
78
-
79
- context "when there are errors and key cannot be mapped to a message" do
80
- subject(:contract_class) do
81
- Class.new(Karafka::Core::Contractable::Contract) do
82
- configure do |config|
83
- config.error_messages = YAML.safe_load_file(
84
- File.join(Karafka::Core.gem_root, "config", "locales", "errors.yml")
85
- ).fetch("en").fetch("validations").fetch("test")
86
- end
87
-
88
- required(:id) { |id| id.is_a?(String) }
89
- end
90
- end
91
-
92
- let(:data) { { id: 123 } }
93
- let(:result) { contract.call(data) }
94
-
95
- it "does not return success" do
96
- refute_predicate result, :success?
97
- end
98
-
99
- it "falls back to a generic error message" do
100
- assert_equal(
101
- { id: "needs to be a String" },
102
- result.errors
103
- )
104
- end
105
- end
106
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe_current do
4
- it { assert_operator described_class, :<, Struct }
5
- end
@@ -1,3 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Each component is tested in its own spec file.
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe_current do
4
- let(:timed) do
5
- current = described_class
6
-
7
- Class.new do
8
- extend current
9
- end
10
- end
11
-
12
- describe "#monotonic_now" do
13
- it "expect to return monotonic in ms" do
14
- pre = timed.monotonic_now
15
- sleep(0.5)
16
-
17
- assert_in_delta 500, timed.monotonic_now - pre, 500
18
- end
19
- end
20
-
21
- describe "#float_now" do
22
- it "expect to return float time in ms" do
23
- pre = timed.float_now
24
- sleep(0.5)
25
-
26
- assert_in_delta 500, timed.float_now - pre, 500
27
- end
28
- end
29
- end
@@ -1,81 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe_current do
4
- subject(:manager) { described_class.new }
5
-
6
- let(:id) { SecureRandom.uuid }
7
- let(:changed) { [] }
8
-
9
- describe "#call" do
10
- context "when there are no callbacks added" do
11
- it { manager.call }
12
- end
13
-
14
- context "when there are callbacks added" do
15
- let(:changed) { [] }
16
- let(:start) { [rand, rand, rand] }
17
-
18
- before do
19
- manager.add("1", ->(val1, _, _) { changed << (val1 + 1) })
20
- manager.add("2", ->(_, val2, _) { changed << (val2 + 2) })
21
- manager.add("3", ->(_, _, val3) { changed << (val3 + 3) })
22
- end
23
-
24
- it "expect to run each of them and pass the args" do
25
- manager.call(*start)
26
-
27
- assert_equal [start[0] + 1, start[1] + 2, start[2] + 3], changed
28
- end
29
- end
30
- end
31
-
32
- describe "#add" do
33
- it "expect after adding to be used" do
34
- manager.add(id, -> { changed << true })
35
- manager.call
36
-
37
- assert_equal [true], changed
38
- end
39
-
40
- context "when we are adding a callback but at the same time, we call callbacks" do
41
- let(:added_id) { SecureRandom.uuid }
42
- let(:callable) do
43
- lambda do
44
- changed << true
45
- sleep(10)
46
- end
47
- end
48
-
49
- before do
50
- # This will simulate a long running callback when manager is called, so when we add new one
51
- # The previous one is still running in a thread
52
- manager.add(id, callable)
53
- Thread.new { manager.call }
54
- # This makes sure, that we wait until the thread kicks in
55
- sleep(0.001) while changed.empty?
56
- end
57
-
58
- it { manager.add(added_id, callable) }
59
-
60
- it "expect to register the new callback" do
61
- manager.delete(id)
62
- manager.add(added_id, -> { changed << true })
63
-
64
- manager.call
65
-
66
- assert_equal [true, true], changed
67
- end
68
- end
69
- end
70
-
71
- describe "#delete" do
72
- before { manager.add(id, -> { changed << true }) }
73
-
74
- it "expect after removal not to be used" do
75
- manager.delete(id)
76
- manager.call
77
-
78
- assert_empty changed
79
- end
80
- end
81
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe_current do
4
- subject(:instrumentation) { described_class }
5
-
6
- describe "#statistics_callbacks" do
7
- it { assert_kind_of described_class::CallbacksManager, instrumentation.statistics_callbacks }
8
- end
9
-
10
- describe "#error_callbacks" do
11
- it { assert_kind_of described_class::CallbacksManager, instrumentation.error_callbacks }
12
- end
13
-
14
- describe "#oauthbearer_token_refresh_callbacks" do
15
- it do
16
- assert_kind_of described_class::CallbacksManager,
17
- instrumentation.oauthbearer_token_refresh_callbacks
18
- end
19
- end
20
-
21
- it "expect statistics_callbacks to differ from error_callbacks" do
22
- refute_equal instrumentation.error_callbacks,
23
- instrumentation.statistics_callbacks
24
- end
25
-
26
- it "expect error_callbacks to differ from oauthbearer_token_refresh_callbacks" do
27
- refute_equal instrumentation.oauthbearer_token_refresh_callbacks,
28
- instrumentation.error_callbacks
29
- end
30
-
31
- it "expect statistics_callbacks to differ from oauthbearer_token_refresh_callbacks" do
32
- refute_equal instrumentation.oauthbearer_token_refresh_callbacks,
33
- instrumentation.statistics_callbacks
34
- end
35
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe_current do
4
- subject(:event) { described_class.new(id, payload) }
5
-
6
- let(:id) { rand.to_s }
7
- let(:payload) { { rand => rand } }
8
-
9
- it { assert_equal id, event.id }
10
- it { assert_equal payload, event.payload }
11
-
12
- describe "#[]" do
13
- context "when key is present" do
14
- let(:payload) { { test: 1 } }
15
-
16
- it "expect to return it" do
17
- assert_equal 1, event[:test]
18
- end
19
- end
20
-
21
- context "when key is missing" do
22
- it { assert_raises(KeyError) { event[:test] } }
23
- end
24
- end
25
- end