karafka-testing 2.5.5 → 2.5.6
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/.github/workflows/ci.yml +78 -32
- data/.github/workflows/push.yml +3 -3
- data/.github/workflows/verify-action-pins.yml +1 -1
- data/.gitignore +1 -0
- data/.rubocop.yml +32 -0
- data/.ruby-version +1 -1
- data/.yard-lint.yml +172 -71
- data/CHANGELOG.md +4 -0
- data/Gemfile +7 -6
- data/Gemfile.lint +14 -0
- data/Gemfile.lint.lock +108 -0
- data/Gemfile.lock +20 -15
- data/Rakefile +12 -2
- data/karafka-testing.gemspec +22 -22
- data/lib/karafka/testing/minitest/helpers.rb +43 -24
- data/lib/karafka/testing/rspec/helpers.rb +61 -23
- data/lib/karafka/testing/version.rb +1 -1
- data/lib/karafka/testing.rb +3 -3
- data/lib/karafka-testing.rb +1 -1
- data/package-lock.json +331 -0
- data/package.json +9 -0
- data/renovate.json +21 -1
- metadata +7 -4
- data/.coditsu/ci.yml +0 -3
- data/.rspec +0 -2
data/Gemfile.lint.lock
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: https://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
ast (2.4.3)
|
|
5
|
+
json (2.18.0)
|
|
6
|
+
language_server-protocol (3.17.0.5)
|
|
7
|
+
lint_roller (1.1.0)
|
|
8
|
+
parallel (1.27.0)
|
|
9
|
+
parser (3.3.10.1)
|
|
10
|
+
ast (~> 2.4.1)
|
|
11
|
+
racc
|
|
12
|
+
prism (1.8.0)
|
|
13
|
+
racc (1.8.1)
|
|
14
|
+
rainbow (3.1.1)
|
|
15
|
+
regexp_parser (2.11.3)
|
|
16
|
+
rubocop (1.82.1)
|
|
17
|
+
json (~> 2.3)
|
|
18
|
+
language_server-protocol (~> 3.17.0.2)
|
|
19
|
+
lint_roller (~> 1.1.0)
|
|
20
|
+
parallel (~> 1.10)
|
|
21
|
+
parser (>= 3.3.0.2)
|
|
22
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
23
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
24
|
+
rubocop-ast (>= 1.48.0, < 2.0)
|
|
25
|
+
ruby-progressbar (~> 1.7)
|
|
26
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
27
|
+
rubocop-ast (1.49.0)
|
|
28
|
+
parser (>= 3.3.7.2)
|
|
29
|
+
prism (~> 1.7)
|
|
30
|
+
rubocop-minitest (0.39.1)
|
|
31
|
+
lint_roller (~> 1.1)
|
|
32
|
+
rubocop (>= 1.75.0, < 2.0)
|
|
33
|
+
rubocop-ast (>= 1.38.0, < 2.0)
|
|
34
|
+
rubocop-performance (1.26.1)
|
|
35
|
+
lint_roller (~> 1.1)
|
|
36
|
+
rubocop (>= 1.75.0, < 2.0)
|
|
37
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
38
|
+
rubocop-thread_safety (0.7.3)
|
|
39
|
+
lint_roller (~> 1.1)
|
|
40
|
+
rubocop (~> 1.72, >= 1.72.1)
|
|
41
|
+
rubocop-ast (>= 1.44.0, < 2.0)
|
|
42
|
+
ruby-progressbar (1.13.0)
|
|
43
|
+
standard (1.53.0)
|
|
44
|
+
language_server-protocol (~> 3.17.0.2)
|
|
45
|
+
lint_roller (~> 1.0)
|
|
46
|
+
rubocop (~> 1.82.0)
|
|
47
|
+
standard-custom (~> 1.0.0)
|
|
48
|
+
standard-performance (~> 1.8)
|
|
49
|
+
standard-custom (1.0.2)
|
|
50
|
+
lint_roller (~> 1.0)
|
|
51
|
+
rubocop (~> 1.50)
|
|
52
|
+
standard-minitest (1.0.0)
|
|
53
|
+
lint_roller (~> 1.0)
|
|
54
|
+
rubocop-minitest
|
|
55
|
+
standard-performance (1.9.0)
|
|
56
|
+
lint_roller (~> 1.1)
|
|
57
|
+
rubocop-performance (~> 1.26.0)
|
|
58
|
+
unicode-display_width (3.2.0)
|
|
59
|
+
unicode-emoji (~> 4.1)
|
|
60
|
+
unicode-emoji (4.2.0)
|
|
61
|
+
yard (0.9.38)
|
|
62
|
+
yard-lint (1.4.0)
|
|
63
|
+
yard (~> 0.9)
|
|
64
|
+
zeitwerk (~> 2.6)
|
|
65
|
+
zeitwerk (2.7.4)
|
|
66
|
+
|
|
67
|
+
PLATFORMS
|
|
68
|
+
ruby
|
|
69
|
+
x86_64-linux
|
|
70
|
+
|
|
71
|
+
DEPENDENCIES
|
|
72
|
+
rubocop-minitest
|
|
73
|
+
rubocop-performance
|
|
74
|
+
rubocop-thread_safety
|
|
75
|
+
standard
|
|
76
|
+
standard-minitest
|
|
77
|
+
standard-performance
|
|
78
|
+
yard-lint
|
|
79
|
+
|
|
80
|
+
CHECKSUMS
|
|
81
|
+
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
|
|
82
|
+
json (2.18.0) sha256=b10506aee4183f5cf49e0efc48073d7b75843ce3782c68dbeb763351c08fd505
|
|
83
|
+
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
|
|
84
|
+
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
|
|
85
|
+
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
|
|
86
|
+
parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
|
|
87
|
+
prism (1.8.0) sha256=84453a16ef5530ea62c5f03ec16b52a459575ad4e7b9c2b360fd8ce2c39c1254
|
|
88
|
+
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
|
|
89
|
+
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
|
|
90
|
+
regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4
|
|
91
|
+
rubocop (1.82.1) sha256=09f1a6a654a960eda767aebea33e47603080f8e9c9a3f019bf9b94c9cab5e273
|
|
92
|
+
rubocop-ast (1.49.0) sha256=49c3676d3123a0923d333e20c6c2dbaaae2d2287b475273fddee0c61da9f71fd
|
|
93
|
+
rubocop-minitest (0.39.1) sha256=998398d6da4026d297f0f9bf709a1eac5f2b6947c24431f94af08138510cf7ed
|
|
94
|
+
rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834
|
|
95
|
+
rubocop-thread_safety (0.7.3) sha256=067cdd52fbf5deffc18995437e45b5194236eaff4f71de3375a1f6052e48f431
|
|
96
|
+
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
97
|
+
standard (1.53.0) sha256=f3c9493385db7079d0abce6f7582f553122156997b81258cd361d3480eeacf9c
|
|
98
|
+
standard-custom (1.0.2) sha256=424adc84179a074f1a2a309bb9cf7cd6bfdb2b6541f20c6bf9436c0ba22a652b
|
|
99
|
+
standard-minitest (1.0.0) sha256=450caa86a64a6e6f6f186cc88601dbb49b6cfaa3b0dce77a73b50ba8cdc15b2a
|
|
100
|
+
standard-performance (1.9.0) sha256=49483d31be448292951d80e5e67cdcb576c2502103c7b40aec6f1b6e9c88e3f2
|
|
101
|
+
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
|
|
102
|
+
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
|
|
103
|
+
yard (0.9.38) sha256=721fb82afb10532aa49860655f6cc2eaa7130889df291b052e1e6b268283010f
|
|
104
|
+
yard-lint (1.4.0) sha256=7dd88fbb08fd77cb840bea899d58812817b36d92291b5693dd0eeb3af9f91f0f
|
|
105
|
+
zeitwerk (2.7.4) sha256=2bef90f356bdafe9a6c2bd32bcd804f83a4f9b8bc27f3600fff051eb3edcec8b
|
|
106
|
+
|
|
107
|
+
BUNDLED WITH
|
|
108
|
+
4.0.3
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
karafka-testing (2.5.
|
|
4
|
+
karafka-testing (2.5.6)
|
|
5
5
|
karafka (>= 2.5.0, < 2.6.0)
|
|
6
6
|
waterdrop (>= 2.8.0)
|
|
7
7
|
|
|
@@ -11,34 +11,41 @@ GEM
|
|
|
11
11
|
base64 (0.3.0)
|
|
12
12
|
diff-lcs (1.6.2)
|
|
13
13
|
docile (1.4.1)
|
|
14
|
-
|
|
15
|
-
ffi (1.17.
|
|
16
|
-
|
|
14
|
+
drb (2.2.3)
|
|
15
|
+
ffi (1.17.3)
|
|
16
|
+
ffi (1.17.3-x86_64-linux-gnu)
|
|
17
|
+
json (2.19.2)
|
|
17
18
|
karafka (2.5.1)
|
|
18
19
|
base64 (~> 0.2)
|
|
19
20
|
karafka-core (>= 2.5.6, < 2.6.0)
|
|
20
21
|
karafka-rdkafka (>= 0.22.0)
|
|
21
22
|
waterdrop (>= 2.8.9, < 3.0.0)
|
|
22
23
|
zeitwerk (~> 2.3)
|
|
23
|
-
karafka-core (2.5.
|
|
24
|
+
karafka-core (2.5.10)
|
|
24
25
|
karafka-rdkafka (>= 0.20.0)
|
|
25
26
|
logger (>= 1.6.0)
|
|
26
|
-
karafka-rdkafka (0.
|
|
27
|
-
ffi (~> 1.
|
|
27
|
+
karafka-rdkafka (0.24.0)
|
|
28
|
+
ffi (~> 1.17.1)
|
|
28
29
|
json (> 2.0)
|
|
29
30
|
logger
|
|
30
31
|
mini_portile2 (~> 2.6)
|
|
31
32
|
rake (> 12)
|
|
32
|
-
karafka-rdkafka (0.
|
|
33
|
-
ffi (~> 1.
|
|
33
|
+
karafka-rdkafka (0.24.0-x86_64-linux-gnu)
|
|
34
|
+
ffi (~> 1.17.1)
|
|
34
35
|
json (> 2.0)
|
|
35
36
|
logger
|
|
36
37
|
mini_portile2 (~> 2.6)
|
|
37
38
|
rake (> 12)
|
|
38
39
|
logger (1.7.0)
|
|
39
40
|
mini_portile2 (2.8.9)
|
|
41
|
+
minitest (6.0.2)
|
|
42
|
+
drb (~> 2.0)
|
|
43
|
+
prism (~> 1.5)
|
|
44
|
+
mocha (3.1.0)
|
|
45
|
+
ruby2_keywords (>= 0.0.5)
|
|
40
46
|
ostruct (0.6.3)
|
|
41
|
-
|
|
47
|
+
prism (1.9.0)
|
|
48
|
+
rake (13.3.1)
|
|
42
49
|
rspec (3.13.2)
|
|
43
50
|
rspec-core (~> 3.13.0)
|
|
44
51
|
rspec-expectations (~> 3.13.0)
|
|
@@ -52,6 +59,7 @@ GEM
|
|
|
52
59
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
53
60
|
rspec-support (~> 3.13.0)
|
|
54
61
|
rspec-support (3.13.6)
|
|
62
|
+
ruby2_keywords (0.0.5)
|
|
55
63
|
simplecov (0.22.0)
|
|
56
64
|
docile (~> 1.1)
|
|
57
65
|
simplecov-html (~> 0.11)
|
|
@@ -63,10 +71,6 @@ GEM
|
|
|
63
71
|
karafka-core (>= 2.4.9, < 3.0.0)
|
|
64
72
|
karafka-rdkafka (>= 0.20.0)
|
|
65
73
|
zeitwerk (~> 2.3)
|
|
66
|
-
yard (0.9.37)
|
|
67
|
-
yard-lint (1.2.3)
|
|
68
|
-
yard (~> 0.9)
|
|
69
|
-
zeitwerk (~> 2.6)
|
|
70
74
|
zeitwerk (2.7.3)
|
|
71
75
|
|
|
72
76
|
PLATFORMS
|
|
@@ -75,11 +79,12 @@ PLATFORMS
|
|
|
75
79
|
|
|
76
80
|
DEPENDENCIES
|
|
77
81
|
karafka-testing!
|
|
82
|
+
minitest
|
|
83
|
+
mocha
|
|
78
84
|
ostruct
|
|
79
85
|
rspec
|
|
80
86
|
simplecov
|
|
81
87
|
warning
|
|
82
|
-
yard-lint
|
|
83
88
|
|
|
84
89
|
BUNDLED WITH
|
|
85
90
|
2.6.3
|
data/Rakefile
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "bundler/gem_tasks"
|
|
5
|
+
|
|
6
|
+
require "rake/testtask"
|
|
7
|
+
|
|
8
|
+
Rake::TestTask.new(:test) do |t|
|
|
9
|
+
t.libs << "test"
|
|
10
|
+
t.test_files = FileList["test/test_helper.rb", "test/**/*_test.rb"]
|
|
11
|
+
.exclude("test/integration/**/*")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
task default: :test
|
data/karafka-testing.gemspec
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
lib = File.expand_path(
|
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
5
|
|
|
6
|
-
require
|
|
6
|
+
require "karafka/testing/version"
|
|
7
7
|
|
|
8
8
|
Gem::Specification.new do |spec|
|
|
9
|
-
spec.name
|
|
10
|
-
spec.platform
|
|
11
|
-
spec.version
|
|
12
|
-
spec.authors
|
|
13
|
-
spec.email
|
|
14
|
-
spec.summary
|
|
15
|
-
spec.description
|
|
16
|
-
spec.homepage
|
|
17
|
-
spec.license
|
|
18
|
-
spec.files
|
|
19
|
-
spec.executables
|
|
9
|
+
spec.name = "karafka-testing"
|
|
10
|
+
spec.platform = Gem::Platform::RUBY
|
|
11
|
+
spec.version = Karafka::Testing::VERSION
|
|
12
|
+
spec.authors = ["Maciej Mensfeld"]
|
|
13
|
+
spec.email = %w[contact@karafka.io]
|
|
14
|
+
spec.summary = "Library which provides helpers for easier Karafka consumers tests"
|
|
15
|
+
spec.description = "Library which provides helpers for easier Karafka consumers tests"
|
|
16
|
+
spec.homepage = "https://karafka.io"
|
|
17
|
+
spec.license = "MIT"
|
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test)/}) }
|
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
20
20
|
spec.require_paths = %w[lib]
|
|
21
21
|
|
|
22
|
-
spec.add_dependency
|
|
23
|
-
spec.add_dependency
|
|
22
|
+
spec.add_dependency "karafka", ">= 2.5.0", "< 2.6.0"
|
|
23
|
+
spec.add_dependency "waterdrop", ">= 2.8.0"
|
|
24
24
|
|
|
25
|
-
spec.required_ruby_version =
|
|
25
|
+
spec.required_ruby_version = ">= 3.2.0"
|
|
26
26
|
|
|
27
27
|
spec.metadata = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
"homepage_uri" => "https://karafka.io",
|
|
29
|
+
"changelog_uri" => "https://karafka.io/docs/Changelog-Karafka-Testing",
|
|
30
|
+
"bug_tracker_uri" => "https://github.com/karafka/karafka-testing/issues",
|
|
31
|
+
"source_code_uri" => "https://github.com/karafka/karafka-testing",
|
|
32
|
+
"documentation_uri" => "https://karafka.io/docs",
|
|
33
|
+
"rubygems_mfa_required" => "true"
|
|
34
34
|
}
|
|
35
35
|
end
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
3
|
+
require "karafka/testing"
|
|
4
|
+
require "karafka/testing/errors"
|
|
5
|
+
require "karafka/testing/helpers"
|
|
6
|
+
require "karafka/testing/spec_consumer_client"
|
|
7
|
+
require "karafka/testing/spec_producer_client"
|
|
8
|
+
require "karafka/testing/minitest/proxy"
|
|
9
9
|
|
|
10
10
|
module Karafka
|
|
11
11
|
module Testing
|
|
@@ -42,14 +42,23 @@ module Karafka
|
|
|
42
42
|
Karafka.producer.stubs(:client).returns(@_karafka_producer_client)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
if base.to_s ==
|
|
45
|
+
if base.to_s == "Minitest::Spec"
|
|
46
46
|
base.class_eval do
|
|
47
47
|
before(&eval_flow)
|
|
48
48
|
end
|
|
49
|
-
|
|
49
|
+
elsif base.respond_to?(:setup) && base.method(:setup).arity != 0
|
|
50
50
|
base.class_eval do
|
|
51
51
|
setup(&eval_flow)
|
|
52
52
|
end
|
|
53
|
+
else
|
|
54
|
+
setup_mod = Module.new do
|
|
55
|
+
define_method(:setup) do
|
|
56
|
+
instance_exec(&eval_flow)
|
|
57
|
+
super()
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
base.prepend(setup_mod)
|
|
53
62
|
end
|
|
54
63
|
end
|
|
55
64
|
end
|
|
@@ -89,11 +98,13 @@ module Karafka
|
|
|
89
98
|
# @example Send a json message to consumer and simulate, that it is partition 6
|
|
90
99
|
# @karafka.produce({ 'hello' => 'world' }.to_json, 'partition' => 6)
|
|
91
100
|
def _karafka_add_message_to_consumer_if_needed(message)
|
|
92
|
-
consumer_obj = if
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
101
|
+
consumer_obj = if message[:consumer_group]
|
|
102
|
+
_karafka_find_consumer_for_message(message)
|
|
103
|
+
elsif defined?(@consumer)
|
|
104
|
+
@consumer
|
|
105
|
+
else
|
|
106
|
+
_karafka_find_consumer_for_message(message)
|
|
107
|
+
end
|
|
97
108
|
# Consumer needs to be defined in order to pass messages to it
|
|
98
109
|
return unless defined?(consumer_obj)
|
|
99
110
|
# We're interested in adding message to consumer only when it is a Karafka consumer
|
|
@@ -105,7 +116,7 @@ module Karafka
|
|
|
105
116
|
return unless message[:topic] == consumer_obj.topic.name
|
|
106
117
|
# If consumer_group is explicitly specified, verify it matches
|
|
107
118
|
return if message[:consumer_group] &&
|
|
108
|
-
|
|
119
|
+
message[:consumer_group].to_s != consumer_obj.topic.consumer_group.name
|
|
109
120
|
|
|
110
121
|
# Build message metadata and copy any metadata that would come from the message
|
|
111
122
|
metadata = _karafka_message_metadata_defaults(consumer_obj)
|
|
@@ -140,22 +151,30 @@ module Karafka
|
|
|
140
151
|
|
|
141
152
|
# Produces message with a given payload to the consumer matching topic
|
|
142
153
|
# @param payload [String] payload we want to dispatch
|
|
143
|
-
# @param metadata [Hash] any metadata we want to dispatch alongside the payload
|
|
154
|
+
# @param metadata [Hash] any metadata we want to dispatch alongside the payload.
|
|
155
|
+
# Supports an `offset` key to set a custom offset for the message (otherwise
|
|
156
|
+
# offsets auto-increment from 0).
|
|
144
157
|
def _karafka_produce(payload, metadata = {})
|
|
158
|
+
# Extract offset before passing to WaterDrop since it is not a valid
|
|
159
|
+
# WaterDrop message attribute (Kafka assigns offsets, not producers)
|
|
160
|
+
@_karafka_next_offset = metadata.delete(:offset)
|
|
161
|
+
|
|
145
162
|
topic = if metadata[:topic]
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
163
|
+
metadata[:topic]
|
|
164
|
+
elsif defined?(@consumer)
|
|
165
|
+
@consumer.topic.name
|
|
166
|
+
else
|
|
167
|
+
last_consumer = @_karafka_consumer_mappings&.values&.last
|
|
168
|
+
last_consumer&.topic&.name
|
|
169
|
+
end
|
|
153
170
|
Karafka.producer.produce_sync(
|
|
154
171
|
{
|
|
155
172
|
topic: topic,
|
|
156
173
|
payload: payload
|
|
157
174
|
}.merge(metadata)
|
|
158
175
|
)
|
|
176
|
+
ensure
|
|
177
|
+
@_karafka_next_offset = nil
|
|
159
178
|
end
|
|
160
179
|
|
|
161
180
|
# @return [Array<Hash>] messages that were produced
|
|
@@ -211,7 +230,7 @@ module Karafka
|
|
|
211
230
|
# No consumer group specified - find all consumers for this topic
|
|
212
231
|
matching = @_karafka_consumer_mappings.values.select { |c| c.topic.name == topic_name }
|
|
213
232
|
# If exactly one consumer matches, use it (backward compatible)
|
|
214
|
-
matching.size == 1 ? matching.first : nil
|
|
233
|
+
(matching.size == 1) ? matching.first : nil
|
|
215
234
|
end
|
|
216
235
|
end
|
|
217
236
|
|
|
@@ -223,7 +242,7 @@ module Karafka
|
|
|
223
242
|
timestamp: Time.now,
|
|
224
243
|
raw_headers: {},
|
|
225
244
|
raw_key: nil,
|
|
226
|
-
offset: @_karafka_consumer_messages.size,
|
|
245
|
+
offset: @_karafka_next_offset.nil? ? @_karafka_consumer_messages.size : @_karafka_next_offset,
|
|
227
246
|
partition: 0,
|
|
228
247
|
received_at: Time.now,
|
|
229
248
|
topic: consumer_obj.topic.name
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
9
|
-
require
|
|
3
|
+
require "waterdrop"
|
|
4
|
+
require "karafka/testing"
|
|
5
|
+
require "karafka/testing/errors"
|
|
6
|
+
require "karafka/testing/helpers"
|
|
7
|
+
require "karafka/testing/spec_consumer_client"
|
|
8
|
+
require "karafka/testing/spec_producer_client"
|
|
9
|
+
require "karafka/testing/rspec/proxy"
|
|
10
10
|
|
|
11
11
|
module Karafka
|
|
12
12
|
module Testing
|
|
@@ -55,7 +55,7 @@ module Karafka
|
|
|
55
55
|
# that patches are available because some users have Mocha as part of their
|
|
56
56
|
# supply chain, but do not use it when running Karafka specs. In such cases, without
|
|
57
57
|
# such check `karafka-testing` would falsely assume, that Mocha is in use.
|
|
58
|
-
if Object.const_defined?(
|
|
58
|
+
if Object.const_defined?("Mocha", false) && Karafka.producer.respond_to?(:stubs)
|
|
59
59
|
Karafka.producer.stubs(:client).returns(_karafka_producer_client)
|
|
60
60
|
else
|
|
61
61
|
allow(Karafka.producer).to receive(:client).and_return(_karafka_producer_client)
|
|
@@ -105,10 +105,12 @@ module Karafka
|
|
|
105
105
|
# end
|
|
106
106
|
def _karafka_add_message_to_consumer_if_needed(message)
|
|
107
107
|
consumer_obj = if defined?(consumer)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
consumer
|
|
109
|
+
elsif _karafka_described_class_is_consumer?
|
|
110
|
+
_karafka_resolve_subject_consumer || _karafka_find_consumer_for_message(message)
|
|
111
|
+
else
|
|
112
|
+
_karafka_find_consumer_for_message(message)
|
|
113
|
+
end
|
|
112
114
|
# Consumer needs to be defined in order to pass messages to it
|
|
113
115
|
return unless consumer_obj
|
|
114
116
|
# We're interested in adding message to consumer only when it is a Karafka consumer
|
|
@@ -120,7 +122,7 @@ module Karafka
|
|
|
120
122
|
return unless message[:topic] == consumer_obj.topic.name
|
|
121
123
|
# If consumer_group is explicitly specified, verify it matches
|
|
122
124
|
return if message[:consumer_group] &&
|
|
123
|
-
|
|
125
|
+
message[:consumer_group].to_s != consumer_obj.topic.consumer_group.name
|
|
124
126
|
|
|
125
127
|
# Build message metadata and copy any metadata that would come from the message
|
|
126
128
|
metadata = _karafka_message_metadata_defaults(consumer_obj)
|
|
@@ -156,22 +158,32 @@ module Karafka
|
|
|
156
158
|
|
|
157
159
|
# Produces message with a given payload to the consumer matching topic
|
|
158
160
|
# @param payload [String] payload we want to dispatch
|
|
159
|
-
# @param metadata [Hash] any metadata we want to dispatch alongside the payload
|
|
161
|
+
# @param metadata [Hash] any metadata we want to dispatch alongside the payload.
|
|
162
|
+
# Supports an `offset` key to set a custom offset for the message (otherwise
|
|
163
|
+
# offsets auto-increment from 0).
|
|
160
164
|
def _karafka_produce(payload, metadata = {})
|
|
165
|
+
# Extract offset before passing to WaterDrop since it is not a valid
|
|
166
|
+
# WaterDrop message attribute (Kafka assigns offsets, not producers)
|
|
167
|
+
@_karafka_next_offset = metadata.delete(:offset)
|
|
168
|
+
|
|
161
169
|
topic = if metadata[:topic]
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
170
|
+
metadata[:topic]
|
|
171
|
+
elsif defined?(consumer)
|
|
172
|
+
consumer.topic.name
|
|
173
|
+
elsif _karafka_described_class_is_consumer? && (sub = _karafka_resolve_subject_consumer)
|
|
174
|
+
sub.topic.name
|
|
175
|
+
else
|
|
176
|
+
last_consumer = @_karafka_consumer_mappings&.values&.last
|
|
177
|
+
last_consumer&.topic&.name
|
|
178
|
+
end
|
|
169
179
|
Karafka.producer.produce_sync(
|
|
170
180
|
{
|
|
171
181
|
topic: topic,
|
|
172
182
|
payload: payload
|
|
173
183
|
}.merge(metadata)
|
|
174
184
|
)
|
|
185
|
+
ensure
|
|
186
|
+
@_karafka_next_offset = nil
|
|
175
187
|
end
|
|
176
188
|
|
|
177
189
|
# @return [Array<Hash>] messages that were produced
|
|
@@ -206,6 +218,32 @@ module Karafka
|
|
|
206
218
|
|
|
207
219
|
private
|
|
208
220
|
|
|
221
|
+
# Checks if the RSpec described_class is a Karafka consumer class.
|
|
222
|
+
# When true, the implicit RSpec subject can be used as a consumer fallback.
|
|
223
|
+
#
|
|
224
|
+
# @return [Boolean] true if described_class inherits from Karafka::BaseConsumer
|
|
225
|
+
def _karafka_described_class_is_consumer?
|
|
226
|
+
respond_to?(:described_class) &&
|
|
227
|
+
described_class.is_a?(Class) &&
|
|
228
|
+
described_class < Karafka::BaseConsumer
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Resolves the RSpec implicit subject as a usable Karafka consumer instance.
|
|
232
|
+
# Returns nil if subject is not a properly configured consumer (e.g. a default
|
|
233
|
+
# described_class.new without topic setup via karafka.consumer_for).
|
|
234
|
+
#
|
|
235
|
+
# @return [Karafka::BaseConsumer, nil] the subject if it is a configured consumer
|
|
236
|
+
def _karafka_resolve_subject_consumer
|
|
237
|
+
candidate = subject
|
|
238
|
+
|
|
239
|
+
return nil unless candidate.is_a?(Karafka::BaseConsumer)
|
|
240
|
+
# Unconfigured consumers (default subject = described_class.new) have nil
|
|
241
|
+
# coordinator, so topic delegation would fail. Check coordinator presence first.
|
|
242
|
+
return nil unless candidate.coordinator
|
|
243
|
+
|
|
244
|
+
candidate.topic&.name ? candidate : nil
|
|
245
|
+
end
|
|
246
|
+
|
|
209
247
|
# Finds a consumer for the given message with backward-compatible fallback
|
|
210
248
|
# @param message [Hash] the message being routed
|
|
211
249
|
# @return [Object, nil] the consumer instance or nil
|
|
@@ -224,7 +262,7 @@ module Karafka
|
|
|
224
262
|
# No consumer group specified - find all consumers for this topic
|
|
225
263
|
matching = @_karafka_consumer_mappings.values.select { |c| c.topic.name == topic_name }
|
|
226
264
|
# If exactly one consumer matches, use it (backward compatible)
|
|
227
|
-
matching.size == 1 ? matching.first : nil
|
|
265
|
+
(matching.size == 1) ? matching.first : nil
|
|
228
266
|
end
|
|
229
267
|
end
|
|
230
268
|
|
|
@@ -236,7 +274,7 @@ module Karafka
|
|
|
236
274
|
timestamp: Time.now,
|
|
237
275
|
raw_headers: {},
|
|
238
276
|
raw_key: nil,
|
|
239
|
-
offset: _karafka_consumer_messages.size,
|
|
277
|
+
offset: @_karafka_next_offset.nil? ? _karafka_consumer_messages.size : @_karafka_next_offset,
|
|
240
278
|
partition: 0,
|
|
241
279
|
received_at: Time.now,
|
|
242
280
|
topic: consumer_obj.topic.name
|
data/lib/karafka/testing.rb
CHANGED
|
@@ -10,11 +10,11 @@ module Karafka
|
|
|
10
10
|
# You should never use karafka-testing primitives when framework is not loaded because
|
|
11
11
|
# testing lib stubs certain pieces of Karafka that need to be initialized.
|
|
12
12
|
def ensure_karafka_loaded!
|
|
13
|
-
return if ::Karafka.const_defined?(
|
|
13
|
+
return if ::Karafka.const_defined?("App", false)
|
|
14
14
|
|
|
15
15
|
raise(
|
|
16
16
|
Karafka::Testing::Errors::KarafkaNotLoadedError,
|
|
17
|
-
|
|
17
|
+
"Make sure to load Karafka framework prior to usage of the testing components."
|
|
18
18
|
)
|
|
19
19
|
end
|
|
20
20
|
|
|
@@ -27,7 +27,7 @@ module Karafka
|
|
|
27
27
|
|
|
28
28
|
raise(
|
|
29
29
|
Karafka::Testing::Errors::KarafkaNotInitializedError,
|
|
30
|
-
|
|
30
|
+
"Make sure to initialize Karafka framework prior to usage of the testing components."
|
|
31
31
|
)
|
|
32
32
|
end
|
|
33
33
|
end
|
data/lib/karafka-testing.rb
CHANGED