karafka-testing 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f33b3c0d37943ef7206980ea05069b8d9ef4ae6e508c3f9c57dadf558d63ee20
4
- data.tar.gz: 8a444eadd58ce1d17f8d64e5ba59cc652a0191eee11bc35939aacc6f788604c0
3
+ metadata.gz: 9112bdf5ca189a7f448c2b5768aa2694a5958a96f591f8d8bad8cc204708f1a3
4
+ data.tar.gz: 61ae2749b2bac651143bca2b8cdb470900b87eccc058c13cbaa4644e1be1435e
5
5
  SHA512:
6
- metadata.gz: 204fed8eb5eae6774efa394570897b33d907f7b36899225c1842f06080f43dc96d12c1cab1c1f01185dcad24c9c70911559d27ee80c6ba120b4e0fbd0e28d43f
7
- data.tar.gz: 93e60baaf6617e479690798c54e1cb11359bac852d961e1cf23b57771767407c17fcfe0048e2659abd8607c022e1b3547e21f79e6f187c811305c9e60d0be04b
6
+ metadata.gz: adff2729f366403cc7e01a18135f972b05b9dd9faa8408a8cda7f75cf6425c9e676060815037fc78acaecfc4efa37be122e7b8d15623c6c31b7263fb2856bdc1
7
+ data.tar.gz: 29da133e08e85e5d1efa24156c1eab91aa858387bc341070cc4ae059d073e721e6955808f6b6923b39b102a3e713067e6cf856a889d0d9d5568674a27245926e
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Karafka Test gem changelog
2
2
 
3
+ ## 2.0.2 (2022-09-29)
4
+ - Provide multi-consumer group testing support (#92)
5
+ - Fail fast if requested topic is present in multiple consumer groups but consumer group is not specified.
6
+ - Allow for usage of `Karafka.producer` directly and make it buffered.
7
+ - Rename `karafka.publish` to `karafka.produce` to align naming conventions.
8
+
3
9
  ## 2.0.1 (2022-08-05)
4
10
  - Require non rc version of Karafka.
5
11
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka-testing (2.0.1)
4
+ karafka-testing (2.0.2)
5
5
  karafka (>= 2.0, < 3.0.0)
6
6
 
7
7
  GEM
@@ -9,7 +9,7 @@ GEM
9
9
  specs:
10
10
  concurrent-ruby (1.1.10)
11
11
  ffi (1.15.5)
12
- karafka (2.0.0)
12
+ karafka (2.0.10)
13
13
  karafka-core (>= 2.0.2, < 3.0.0)
14
14
  rdkafka (>= 0.12)
15
15
  thor (>= 0.20)
@@ -37,4 +37,4 @@ DEPENDENCIES
37
37
  karafka-testing!
38
38
 
39
39
  BUNDLED WITH
40
- 2.3.15
40
+ 2.3.22
data/README.md CHANGED
@@ -1,14 +1,10 @@
1
1
  # Karafka Testing library
2
2
 
3
- **Note**: Documentation presented below works with Karafka `2.0.0.alpha3` and higher.
4
-
5
- Please refer to [this](https://github.com/karafka/testing/tree/1.4) branch and its documentation for details about usage with Karafka `1.4`.
6
-
7
3
  [![Build Status](https://github.com/karafka/karafka-testing/workflows/ci/badge.svg)](https://github.com/karafka/karafka-testing/actions?query=workflow%3Aci)
8
4
  [![Gem Version](https://badge.fury.io/rb/karafka-testing.svg)](http://badge.fury.io/rb/karafka-testing)
9
5
  [![Join the chat at https://slack.karafka.io](https://raw.githubusercontent.com/karafka/misc/master/slack.svg)](https://slack.karafka.io)
10
6
 
11
- Karafka-Testing is a library that provides RSpec helpers, to make testing of Karafka consumers much easier.
7
+ Karafka-Testing is a library that provides RSpec helpers, to make testing of Karafka consumers and producer much easier.
12
8
 
13
9
  ## Installation
14
10
 
@@ -32,17 +28,22 @@ end
32
28
 
33
29
  ## Usage
34
30
 
35
- Once included into your RSpec setup, this library will provide you with a special object `#karafka` that includes two methods that you can use with your specs:
31
+ Once included in your RSpec setup, this library will provide you with a special `#karafka` object that contains three methods that you can use within your specs:
36
32
 
37
33
  - `#consumer_for` - creates a consumer instance for the desired topic. It **needs** to be set as the spec subject.
38
- - `#publish` - "sends" message to the consumer instance.
34
+ - `#produce` - "sends" message to the consumer instance.
35
+ - `#produced_messages` - contains all the messages "sent" to Kafka during spec execution.
36
+
37
+ **Note:** Messages sent using the `#produce` method and directly from `Karafka.producer` won't be sent to Kafka. They will be buffered and accessible in a per-spec buffer in case you want to test messages production.
39
38
 
40
- **Note:** Messages sent using the `#publish` method won't be sent to Kafka. They will be "virtually" delegated to the created consumer instance so your specs can run without Kafka setup.
39
+ Messages that target the topic built using the `karafka#consumer_for` method will additionally be delivered to the consumer you want to test.
40
+
41
+ ### Testing messages consumption (consumers)
41
42
 
42
43
  ```ruby
43
44
  RSpec.describe InlineBatchConsumer do
44
45
  # This will create a consumer instance with all the settings defined for the given topic
45
- subject(:consumer) { karafka.consumer_for(:inline_batch_data) }
46
+ subject(:consumer) { karafka.consumer_for('inline_batch_data') }
46
47
 
47
48
  let(:nr1_value) { rand }
48
49
  let(:nr2_value) { rand }
@@ -50,9 +51,11 @@ RSpec.describe InlineBatchConsumer do
50
51
 
51
52
  before do
52
53
  # Sends first message to Karafka consumer
53
- karafka.publish({ 'number' => nr1_value }.to_json)
54
+ karafka.produce({ 'number' => nr1_value }.to_json)
55
+
54
56
  # Sends second message to Karafka consumer
55
- karafka.publish({ 'number' => nr2_value }.to_json, partition: 2)
57
+ karafka.produce({ 'number' => nr2_value }.to_json, partition: 2)
58
+
56
59
  allow(Karafka.logger).to receive(:info)
57
60
  end
58
61
 
@@ -63,22 +66,53 @@ RSpec.describe InlineBatchConsumer do
63
66
  end
64
67
  ```
65
68
 
66
- If your consumers use `producer` to dispatch messages, you can set up your expectations against it as well:
69
+ If your consumers use `producer` to dispatch messages, you can check its operations as well:
67
70
 
68
71
  ```ruby
69
72
  RSpec.describe InlineBatchConsumer do
70
73
  subject(:consumer) { karafka.consumer_for(:inline_batch_data) }
71
74
 
72
- before { karafka.publish({ 'number' => 1 }.to_json) }
75
+ before { karafka.produce({ 'number' => 1 }.to_json) }
73
76
 
74
77
  it 'expects to dispatch async message to messages topic with value bigger by 1' do
75
- expect(consumer.producer)
76
- .to receive(:produce_async)
77
- .with(topic: 'messages', payload: { number: 2 }.to_json)
78
-
79
78
  consumer.consume
79
+
80
+ expect(karafka.produced_messages.last.payload).to eq({ number: 2 }.to_json)
81
+ end
82
+ end
83
+ ```
84
+
85
+ ### Testing messages production (producer)
86
+
87
+ When running RSpec, Karafka will not dispatch messages to Kafka using `Karafka.producer` but will buffer them internally.
88
+
89
+ This means you can check your application flow, making sure your logic acts as expected:
90
+
91
+ ```ruby
92
+ # Example class in which there is a message production
93
+ class UsersBuilder
94
+ def create(user_details)
95
+ user = ::User.create!(user_details)
96
+
97
+ Karafka.producer.produce_sync(
98
+ topic: 'users_changes',
99
+ payload: { user_id: user.id, type: 'user.created' },
100
+ key: user.id.to_s
101
+ )
102
+
103
+ user
80
104
  end
81
105
  end
106
+
107
+ RSpec.describe InlineBatchConsumer do
108
+ let(:created_user) { UsersBuilder.new.create(user_details) }
109
+
110
+ before { created_user }
111
+
112
+ it { expect(karafka.produced_messages.size).to eq(1) }
113
+ it { expect(karafka.produced_messages.first[:topic]).to eq('user.created') }
114
+ it { expect(karafka.produced_messages.first[:key]).to eq(created_user.id.to_s) }
115
+ end
82
116
  ```
83
117
 
84
118
  ## Note on contributions
@@ -0,0 +1,26 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEcDCCAtigAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MRAwDgYDVQQDDAdjb250
3
+ YWN0MRcwFQYKCZImiZPyLGQBGRYHa2FyYWZrYTESMBAGCgmSJomT8ixkARkWAmlv
4
+ MB4XDTIyMDgxOTE3MjEzN1oXDTIzMDgxOTE3MjEzN1owPzEQMA4GA1UEAwwHY29u
5
+ dGFjdDEXMBUGCgmSJomT8ixkARkWB2thcmFma2ExEjAQBgoJkiaJk/IsZAEZFgJp
6
+ bzCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAODzeO3L6lxdATzMHKNW
7
+ jFA/GGunoPuylO/BMzy8RiQHh7VIvysAKs0tHhTx3g2D0STDpF+hcQcPELFikiT2
8
+ F+1wOHj/SsrK7VKqfA8+gq04hKc5sQoX2Egf9k3V0YJ3eZ6R/koHkQ8A0TVt0w6F
9
+ ZQckoV4MqnEAx0g/FZN3mnHTlJ3VFLSBqJEIe+S6FZMl92mSv+hTrlUG8VaYxSfN
10
+ lTCvnKk284F6QZq5XIENLRmcDd/3aPBLnLwNnyMyhB+6gK8cUO+CFlDO5tjo/aBA
11
+ rUnl++wGG0JooF1ed0v+evOn9KoMBG6rHewcf79qJbVOscbD8qSAmo+sCXtcFryr
12
+ KRMTB8gNbowJkFRJDEe8tfRy11u1fYzFg/qNO82FJd62rKAw2wN0C29yCeQOPRb1
13
+ Cw9Y4ZwK9VFNEcV9L+3pHTHn2XfuZHtDaG198VweiF6raFO4yiEYccodH/USP0L5
14
+ cbcCFtmu/4HDSxL1ByQXO84A0ybJuk3/+aPUSXe9C9U8fwIDAQABo3cwdTAJBgNV
15
+ HRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUSlcEakb7gfn/5E2WY6z73BF/
16
+ iZkwHQYDVR0RBBYwFIESY29udGFjdEBrYXJhZmthLmlvMB0GA1UdEgQWMBSBEmNv
17
+ bnRhY3RAa2FyYWZrYS5pbzANBgkqhkiG9w0BAQsFAAOCAYEA1aS+E7RXJ1w9g9mJ
18
+ G0NzFxe64OEuENosNlvYQCbRKGCXAU1qqelYkBQHseRgRKxLICrnypRo9IEobyHa
19
+ vDnJ4r7Tsb34dleqQW2zY/obG+cia3Ym2JsegXWF7dDOzCXJ4FN8MFoT2jHlqLLw
20
+ yrap0YO5zx0GSQ0Dwy8h2n2v2vanMEeCx7iNm3ERgR5WuN5sjzWoz2A/JLEEcK0C
21
+ EnAGKCWAd1fuG8IemDjT1edsd5FyYR4bIX0m+99oDuFZyPiiIbalmyYiSBBp59Yb
22
+ Q0P8zeBi4OfwCZNcxqz0KONmw9JLNv6DgyEAH5xe/4JzhMEgvIRiPj0pHfA7oqQF
23
+ KUNqvD1KlxbEC+bZfE5IZhnqYLdld/Ksqd22FI1RBhiS1Ejfsj99LVIm9cBuZEY2
24
+ Qf04B9ceLUaC4fPVEz10FyobjaFoY4i32xRto3XnrzeAgfEe4swLq8bQsR3w/EF3
25
+ MGU0FeSV2Yj7Xc2x/7BzLK8xQn5l7Yy75iPF+KP3vVmDHnNl
26
+ -----END CERTIFICATE-----
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.platform = Gem::Platform::RUBY
11
11
  spec.version = Karafka::Testing::VERSION
12
12
  spec.authors = ['Maciej Mensfeld']
13
- spec.email = %w[maciej@mensfeld.pl]
13
+ spec.email = %w[contact@karafka.io]
14
14
  spec.summary = 'Library which provides helpers for easier Karafka consumers tests'
15
15
  spec.description = 'Library which provides helpers for easier Karafka consumers tests'
16
16
  spec.homepage = 'https://karafka.io'
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
19
19
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
20
  spec.require_paths = %w[lib]
21
- spec.cert_chain = %w[certs/mensfeld.pem]
21
+ spec.cert_chain = %w[certs/cert_chain.pem]
22
22
 
23
23
  spec.required_ruby_version = '>= 2.7'
24
24
 
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_dependency 'karafka', '>= 2.0', '< 3.0.0'
30
30
 
31
31
  spec.metadata = {
32
- 'source_code_uri' => 'https://github.com/karafka/karafka',
32
+ 'source_code_uri' => 'https://github.com/karafka/karafka-testing',
33
33
  'rubygems_mfa_required' => 'true'
34
34
  }
35
35
  end
@@ -7,8 +7,12 @@ module Karafka
7
7
  module Errors
8
8
  # Base error for all the internal errors
9
9
  BaseError = Class.new(StandardError)
10
+
10
11
  # Raised when we want to build a consumer for a topic that does not exist
11
12
  TopicNotFoundError = Class.new(BaseError)
13
+
14
+ # Raised when topic is in many consumer groups and not limited by consumer group expectation
15
+ TopicInManyConsumerGroupsError = Class.new(BaseError)
12
16
  end
13
17
  end
14
18
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'waterdrop'
3
4
  require 'karafka/testing/errors'
4
- require 'karafka/testing/dummy_client'
5
+ require 'karafka/testing/spec_consumer_client'
6
+ require 'karafka/testing/spec_producer_client'
5
7
  require 'karafka/testing/rspec/proxy'
6
8
 
7
9
  module Karafka
@@ -15,12 +17,24 @@ module Karafka
15
17
  # Adds all the needed extra functionalities to the rspec group
16
18
  # @param base [Class] RSpec example group we want to extend
17
19
  def included(base)
18
- # This is an internal buffer for keeping "to be sent" messages before
19
- # we run the consume
20
- base.let(:_karafka_messages) { [] }
20
+ # RSpec local reference to Karafka proxy that allows us to build the consumer instance
21
21
  base.let(:karafka) { Karafka::Testing::RSpec::Proxy.new(self) }
22
- # Clear the messages buffer after each spec, so nothing leaks in between them
23
- base.after { _karafka_messages.clear }
22
+
23
+ # Messages that are targeted to the consumer
24
+ # You can produce many messages from Karafka during specs and not all should go to the
25
+ # consumer for processing. This buffer holds only those that should go to consumer
26
+ base.let(:_karafka_consumer_messages) { [] }
27
+ # Consumer fake client to mock communication with Kafka
28
+ base.let(:_karafka_consumer_client) { Karafka::Testing::SpecConsumerClient.new }
29
+ # Producer fake client to mock communication with Kafka
30
+ base.let(:_karafka_producer_client) { Karafka::Testing::SpecProducerClient.new(self) }
31
+
32
+ base.before do
33
+ _karafka_consumer_messages.clear
34
+ _karafka_producer_client.reset
35
+
36
+ allow(Karafka.producer).to receive(:client).and_return(_karafka_producer_client)
37
+ end
24
38
  end
25
39
  end
26
40
 
@@ -28,6 +42,8 @@ module Karafka
28
42
  #
29
43
  # @param requested_topic [String, Symbol] name of the topic for which we want to
30
44
  # create a consumer instance
45
+ # @param requested_consumer_group [String, Symbol, nil] optional name of the consumer group
46
+ # if we have multiple consumer groups listening on the same topic
31
47
  # @return [Object] described_class instance
32
48
  # @raise [Karafka::Testing::Errors::TopicNotFoundError] raised when we're unable to find
33
49
  # topic that was requested
@@ -36,78 +52,119 @@ module Karafka
36
52
  # RSpec.describe MyConsumer do
37
53
  # subject(:consumer) { karafka.consumer_for(:my_requested_topic) }
38
54
  # end
39
- def karafka_consumer_for(requested_topic)
40
- selected_topic = nil
55
+ def _karafka_consumer_for(requested_topic, requested_consumer_group = nil)
56
+ all_topics = ::Karafka::App.consumer_groups.map(&:topics).flat_map(&:to_a)
41
57
 
42
- # @note Remove in 2.1. This won't work without the global state
43
- ::Karafka::App.consumer_groups.each do |consumer_group|
44
- consumer_group.topics.each do |topic|
45
- selected_topic = topic if topic.name == requested_topic.to_s
46
- end
58
+ # First select topics that match what we are looking for
59
+ selected_topics = all_topics.select do |topic|
60
+ topic.name == requested_topic.to_s
47
61
  end
48
62
 
49
- raise Karafka::Testing::Errors::TopicNotFoundError, requested_topic unless selected_topic
63
+ # And then narrow it down based on the consumer group criteria (if present)
64
+ selected_topics.delete_if do |topic|
65
+ requested_consumer_group && topic.consumer_group.name != requested_consumer_group.to_s
66
+ end
50
67
 
51
- coordinators = Karafka::Processing::CoordinatorsBuffer.new
68
+ raise Errors::TopicInManyConsumerGroupsError, requested_topic if selected_topics.size > 1
69
+ raise Errors::TopicNotFoundError, requested_topic if selected_topics.empty?
52
70
 
53
- consumer = described_class.new
54
- consumer.topic = selected_topic
55
- consumer.producer = Karafka::App.producer
56
- consumer.client = Karafka::Testing::DummyClient.new
57
- consumer.coordinator = coordinators.find_or_create(requested_topic, 0)
58
- consumer
71
+ _karafka_build_consumer_for(selected_topics.first)
59
72
  end
60
73
 
61
- # Adds a new Karafka message instance with given payload and options into an internal
62
- # buffer that will be used to simulate messages delivery to the consumer
63
- #
64
- # @param payload [String] anything you want to send
65
- # @param opts [Hash] additional options with which you want to overwrite the
66
- # message defaults (key, offset, etc)
74
+ # Adds a new Karafka message instance if needed with given payload and options into an
75
+ # internal consumer buffer that will be used to simulate messages delivery to the consumer
67
76
  #
77
+ # @param message [Hash] message that was sent to Kafka
68
78
  # @example Send a json message to consumer
69
79
  # before do
70
- # karafka.publish({ 'hello' => 'world' }.to_json)
80
+ # karafka.produce({ 'hello' => 'world' }.to_json)
71
81
  # end
72
82
  #
73
83
  # @example Send a json message to consumer and simulate, that it is partition 6
74
84
  # before do
75
- # karafka.publish({ 'hello' => 'world' }.to_json, 'partition' => 6)
85
+ # karafka.produce({ 'hello' => 'world' }.to_json, 'partition' => 6)
76
86
  # end
77
- def karafka_publish(payload, opts = {})
78
- metadata = Karafka::Messages::Metadata.new(
79
- **karafka_message_metadata_defaults.merge(opts)
80
- ).freeze
87
+ def _karafka_add_message_to_consumer_if_needed(message)
88
+ # We target to the consumer only messages that were produced to it, since specs may also
89
+ # produce other messages targeting other topics
90
+ return unless message[:topic] == consumer.topic.name
91
+
92
+ # Build message metadata and copy any metadata that would come from the message
93
+ metadata = _karafka_message_metadata_defaults
94
+
95
+ metadata.keys.each do |key|
96
+ next unless message.key?(key)
97
+
98
+ metadata[key] = message.fetch(key)
99
+ end
81
100
 
82
- # Add this message to previously published messages
83
- _karafka_messages << Karafka::Messages::Message.new(payload, metadata)
101
+ # Add this message to previously produced messages
102
+ _karafka_consumer_messages << Karafka::Messages::Message.new(
103
+ message[:payload],
104
+ Karafka::Messages::Metadata.new(metadata).freeze
105
+ )
84
106
 
85
107
  # Update batch metadata
86
108
  batch_metadata = Karafka::Messages::Builders::BatchMetadata.call(
87
- _karafka_messages,
109
+ _karafka_consumer_messages,
88
110
  subject.topic,
89
111
  Time.now
90
112
  )
91
113
 
92
114
  # Update consumer messages batch
93
- subject.messages = Karafka::Messages::Messages.new(_karafka_messages, batch_metadata)
115
+ subject.messages = Karafka::Messages::Messages.new(
116
+ _karafka_consumer_messages,
117
+ batch_metadata
118
+ )
119
+ end
120
+
121
+ # Produces message with a given payload to the consumer matching topic
122
+ # @param payload [String] payload we want to dispatch
123
+ # @param metadata [Hash] any metadata we want to dispatch alongside the payload
124
+ def _karafka_produce(payload, metadata = {})
125
+ Karafka.producer.produce_sync(
126
+ {
127
+ topic: subject.topic.name,
128
+ payload: payload
129
+ }.merge(metadata)
130
+ )
131
+ end
132
+
133
+ # @return [Array<Hash>] messages that were produced
134
+ def _karafka_produced_messages
135
+ _karafka_producer_client.messages
94
136
  end
95
137
 
96
138
  private
97
139
 
98
140
  # @return [Hash] message default options
99
- def karafka_message_metadata_defaults
141
+ def _karafka_message_metadata_defaults
100
142
  {
101
143
  deserializer: subject.topic.deserializer,
102
144
  timestamp: Time.now,
103
145
  headers: {},
104
146
  key: nil,
105
- offset: _karafka_messages.size,
147
+ offset: _karafka_consumer_messages.size,
106
148
  partition: 0,
107
149
  received_at: Time.now,
108
150
  topic: subject.topic.name
109
151
  }
110
152
  end
153
+
154
+ # Builds the consumer instance based on the provided topic
155
+ #
156
+ # @param topic [Karafka::Routing::Topic] topic for which we want to build the consumer
157
+ # @return [Object] karafka consumer
158
+ def _karafka_build_consumer_for(topic)
159
+ coordinators = Karafka::Processing::CoordinatorsBuffer.new
160
+
161
+ consumer = described_class.new
162
+ consumer.topic = topic
163
+ consumer.producer = Karafka::App.producer
164
+ consumer.client = _karafka_consumer_client
165
+ consumer.coordinator = coordinators.find_or_create(topic.name, 0)
166
+ consumer
167
+ end
111
168
  end
112
169
  end
113
170
  end
@@ -4,20 +4,26 @@ module Karafka
4
4
  module Testing
5
5
  module RSpec
6
6
  # Proxy object for a nicer `karafka.` API within RSpec
7
+ # None other should be used by the end users
7
8
  class Proxy
8
9
  # @param rspec_example [RSpec::ExampleGroups] rspec context
9
10
  def initialize(rspec_example)
10
11
  @rspec_example = rspec_example
11
12
  end
12
13
 
13
- # @param args Anything that the `#karafka_consumer_for` accepts
14
+ # @param args Anything that the `#_karafka_consumer_for` accepts
14
15
  def consumer_for(*args)
15
- @rspec_example.karafka_consumer_for(*args)
16
+ @rspec_example._karafka_consumer_for(*args)
16
17
  end
17
18
 
18
- # @param args Anything that the `#karafka_publish` accepts
19
- def publish(*args)
20
- @rspec_example.karafka_publish(*args)
19
+ # @param args Anything that `#_karafka_produce` accepts
20
+ def produce(*args)
21
+ @rspec_example._karafka_produce(*args)
22
+ end
23
+
24
+ # @return [Array<Hash>] messages produced via `Karafka#producer`
25
+ def produced_messages
26
+ @rspec_example._karafka_produced_messages
21
27
  end
22
28
  end
23
29
  end
@@ -2,10 +2,10 @@
2
2
 
3
3
  module Karafka
4
4
  module Testing
5
- # A dummy client that takes over client delegated methods from the consumers
5
+ # A spec client that takes over client delegated methods from the consumers
6
6
  # For specs we do not mark anything as consumed, nor do we really send heartbeats.
7
7
  # Those things are tested in the framework itself
8
- class DummyClient
8
+ class SpecConsumerClient
9
9
  %i[
10
10
  mark_as_consumed
11
11
  mark_as_consumed!
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Testing
5
+ # Spec producer client used to buffer messages that we send out in specs
6
+ class SpecProducerClient < ::WaterDrop::Producer::DummyClient
7
+ attr_accessor :messages
8
+
9
+ # Sync fake response for the message delivery to Kafka, since we do not dispatch anything
10
+ class SyncResponse
11
+ # @param _args Handler wait arguments (irrelevant as waiting is fake here)
12
+ def wait(*_args)
13
+ false
14
+ end
15
+ end
16
+
17
+ # @param rspec [RSpec::Core::ExampleGroup] rspec example we need to hold to trigger actions
18
+ # on it that are rspec context aware
19
+ def initialize(rspec)
20
+ super()
21
+ @rspec = rspec
22
+ self.messages = []
23
+ end
24
+
25
+ # "Produces" message to Kafka. That is, it acknowledges it locally, adds it to the internal
26
+ # buffer and adds it (if needed) into the current consumer messages buffer
27
+ # @param message [Hash] `Karafka.producer.produce_sync` message hash
28
+ def produce(message)
29
+ messages << message
30
+
31
+ @rspec._karafka_add_message_to_consumer_if_needed(message)
32
+
33
+ SyncResponse.new
34
+ end
35
+
36
+ # Clears internal buffer
37
+ # Used in between specs so messages do not leak out
38
+ def reset
39
+ messages.clear
40
+ end
41
+ end
42
+ end
43
+ end
@@ -4,6 +4,6 @@
4
4
  module Karafka
5
5
  module Testing
6
6
  # Current version of gem. It should match Karafka framework version
7
- VERSION = '2.0.1'
7
+ VERSION = '2.0.2'
8
8
  end
9
9
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: karafka-testing
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld
@@ -10,31 +10,32 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhtYWNp
14
- ZWovREM9bWVuc2ZlbGQvREM9cGwwHhcNMjEwODExMTQxNTEzWhcNMjIwODExMTQx
15
- NTEzWjAjMSEwHwYDVQQDDBhtYWNpZWovREM9bWVuc2ZlbGQvREM9cGwwggGiMA0G
16
- CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDV2jKH4Ti87GM6nyT6D+ESzTI0MZDj
17
- ak2/TEwnxvijMJyCCPKT/qIkbW4/f0VHM4rhPr1nW73sb5SZBVFCLlJcOSKOBdUY
18
- TMY+SIXN2EtUaZuhAOe8LxtxjHTgRHvHcqUQMBENXTISNzCo32LnUxweu66ia4Pd
19
- 1mNRhzOqNv9YiBZvtBf7IMQ+sYdOCjboq2dlsWmJiwiDpY9lQBTnWORnT3mQxU5x
20
- vPSwnLB854cHdCS8fQo4DjeJBRZHhEbcE5sqhEMB3RZA3EtFVEXOxlNxVTS3tncI
21
- qyNXiWDaxcipaens4ObSY1C2HTV7OWb7OMqSCIybeYTSfkaSdqmcl4S6zxXkjH1J
22
- tnjayAVzD+QVXGijsPLE2PFnJAh9iDET2cMsjabO1f6l1OQNyAtqpcyQcgfnyW0z
23
- g7tGxTYD+6wJHffM9d9txOUw6djkF6bDxyqB8lo4Z3IObCx18AZjI9XPS9QG7w6q
24
- LCWuMG2lkCcRgASqaVk9fEf9yMc2xxz5o3kCAwEAAaN3MHUwCQYDVR0TBAIwADAL
25
- BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFBqUFCKCOe5IuueUVqOB991jyCLLMB0GA1Ud
26
- EQQWMBSBEm1hY2llakBtZW5zZmVsZC5wbDAdBgNVHRIEFjAUgRJtYWNpZWpAbWVu
27
- c2ZlbGQucGwwDQYJKoZIhvcNAQELBQADggGBADD0/UuTTFgW+CGk2U0RDw2RBOca
28
- W2LTF/G7AOzuzD0Tc4voc7WXyrgKwJREv8rgBimLnNlgmFJLmtUCh2U/MgxvcilH
29
- yshYcbseNvjkrtYnLRlWZR4SSB6Zei5AlyGVQLPkvdsBpNegcG6w075YEwzX/38a
30
- 8V9B/Yri2OGELBz8ykl7BsXUgNoUPA/4pHF6YRLz+VirOaUIQ4JfY7xGj6fSOWWz
31
- /rQ/d77r6o1mfJYM/3BRVg73a3b7DmRnE5qjwmSaSQ7u802pJnLesmArch0xGCT/
32
- fMmRli1Qb+6qOTl9mzD6UDMAyFR4t6MStLm0mIEqM0nBO5nUdUWbC7l9qXEf8XBE
33
- 2DP28p3EqSuS+lKbAWKcqv7t0iRhhmaod+Yn9mcrLN1sa3q3KSQ9BCyxezCD4Mk2
34
- R2P11bWoCtr70BsccVrN8jEhzwXngMyI2gVt750Y+dbTu1KgRqZKp/ECe7ZzPzXj
35
- pIy9vHxTANKYVyI4qj8OrFdEM5BQNu8oQpL0iQ==
13
+ MIIEcDCCAtigAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MRAwDgYDVQQDDAdjb250
14
+ YWN0MRcwFQYKCZImiZPyLGQBGRYHa2FyYWZrYTESMBAGCgmSJomT8ixkARkWAmlv
15
+ MB4XDTIyMDgxOTE3MjEzN1oXDTIzMDgxOTE3MjEzN1owPzEQMA4GA1UEAwwHY29u
16
+ dGFjdDEXMBUGCgmSJomT8ixkARkWB2thcmFma2ExEjAQBgoJkiaJk/IsZAEZFgJp
17
+ bzCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAODzeO3L6lxdATzMHKNW
18
+ jFA/GGunoPuylO/BMzy8RiQHh7VIvysAKs0tHhTx3g2D0STDpF+hcQcPELFikiT2
19
+ F+1wOHj/SsrK7VKqfA8+gq04hKc5sQoX2Egf9k3V0YJ3eZ6R/koHkQ8A0TVt0w6F
20
+ ZQckoV4MqnEAx0g/FZN3mnHTlJ3VFLSBqJEIe+S6FZMl92mSv+hTrlUG8VaYxSfN
21
+ lTCvnKk284F6QZq5XIENLRmcDd/3aPBLnLwNnyMyhB+6gK8cUO+CFlDO5tjo/aBA
22
+ rUnl++wGG0JooF1ed0v+evOn9KoMBG6rHewcf79qJbVOscbD8qSAmo+sCXtcFryr
23
+ KRMTB8gNbowJkFRJDEe8tfRy11u1fYzFg/qNO82FJd62rKAw2wN0C29yCeQOPRb1
24
+ Cw9Y4ZwK9VFNEcV9L+3pHTHn2XfuZHtDaG198VweiF6raFO4yiEYccodH/USP0L5
25
+ cbcCFtmu/4HDSxL1ByQXO84A0ybJuk3/+aPUSXe9C9U8fwIDAQABo3cwdTAJBgNV
26
+ HRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUSlcEakb7gfn/5E2WY6z73BF/
27
+ iZkwHQYDVR0RBBYwFIESY29udGFjdEBrYXJhZmthLmlvMB0GA1UdEgQWMBSBEmNv
28
+ bnRhY3RAa2FyYWZrYS5pbzANBgkqhkiG9w0BAQsFAAOCAYEA1aS+E7RXJ1w9g9mJ
29
+ G0NzFxe64OEuENosNlvYQCbRKGCXAU1qqelYkBQHseRgRKxLICrnypRo9IEobyHa
30
+ vDnJ4r7Tsb34dleqQW2zY/obG+cia3Ym2JsegXWF7dDOzCXJ4FN8MFoT2jHlqLLw
31
+ yrap0YO5zx0GSQ0Dwy8h2n2v2vanMEeCx7iNm3ERgR5WuN5sjzWoz2A/JLEEcK0C
32
+ EnAGKCWAd1fuG8IemDjT1edsd5FyYR4bIX0m+99oDuFZyPiiIbalmyYiSBBp59Yb
33
+ Q0P8zeBi4OfwCZNcxqz0KONmw9JLNv6DgyEAH5xe/4JzhMEgvIRiPj0pHfA7oqQF
34
+ KUNqvD1KlxbEC+bZfE5IZhnqYLdld/Ksqd22FI1RBhiS1Ejfsj99LVIm9cBuZEY2
35
+ Qf04B9ceLUaC4fPVEz10FyobjaFoY4i32xRto3XnrzeAgfEe4swLq8bQsR3w/EF3
36
+ MGU0FeSV2Yj7Xc2x/7BzLK8xQn5l7Yy75iPF+KP3vVmDHnNl
36
37
  -----END CERTIFICATE-----
37
- date: 2022-08-05 00:00:00.000000000 Z
38
+ date: 2022-09-29 00:00:00.000000000 Z
38
39
  dependencies:
39
40
  - !ruby/object:Gem::Dependency
40
41
  name: karafka
@@ -58,7 +59,7 @@ dependencies:
58
59
  version: 3.0.0
59
60
  description: Library which provides helpers for easier Karafka consumers tests
60
61
  email:
61
- - maciej@mensfeld.pl
62
+ - contact@karafka.io
62
63
  executables: []
63
64
  extensions: []
64
65
  extra_rdoc_files: []
@@ -76,20 +77,21 @@ files:
76
77
  - Gemfile.lock
77
78
  - MIT-LICENSE
78
79
  - README.md
79
- - certs/mensfeld.pem
80
+ - certs/cert_chain.pem
80
81
  - karafka-testing.gemspec
81
82
  - lib/karafka-testing.rb
82
83
  - lib/karafka/testing.rb
83
- - lib/karafka/testing/dummy_client.rb
84
84
  - lib/karafka/testing/errors.rb
85
85
  - lib/karafka/testing/rspec/helpers.rb
86
86
  - lib/karafka/testing/rspec/proxy.rb
87
+ - lib/karafka/testing/spec_consumer_client.rb
88
+ - lib/karafka/testing/spec_producer_client.rb
87
89
  - lib/karafka/testing/version.rb
88
90
  homepage: https://karafka.io
89
91
  licenses:
90
92
  - MIT
91
93
  metadata:
92
- source_code_uri: https://github.com/karafka/karafka
94
+ source_code_uri: https://github.com/karafka/karafka-testing
93
95
  rubygems_mfa_required: 'true'
94
96
  post_install_message:
95
97
  rdoc_options: []
metadata.gz.sig CHANGED
Binary file
data/certs/mensfeld.pem DELETED
@@ -1,25 +0,0 @@
1
- -----BEGIN CERTIFICATE-----
2
- MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhtYWNp
3
- ZWovREM9bWVuc2ZlbGQvREM9cGwwHhcNMjEwODExMTQxNTEzWhcNMjIwODExMTQx
4
- NTEzWjAjMSEwHwYDVQQDDBhtYWNpZWovREM9bWVuc2ZlbGQvREM9cGwwggGiMA0G
5
- CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDV2jKH4Ti87GM6nyT6D+ESzTI0MZDj
6
- ak2/TEwnxvijMJyCCPKT/qIkbW4/f0VHM4rhPr1nW73sb5SZBVFCLlJcOSKOBdUY
7
- TMY+SIXN2EtUaZuhAOe8LxtxjHTgRHvHcqUQMBENXTISNzCo32LnUxweu66ia4Pd
8
- 1mNRhzOqNv9YiBZvtBf7IMQ+sYdOCjboq2dlsWmJiwiDpY9lQBTnWORnT3mQxU5x
9
- vPSwnLB854cHdCS8fQo4DjeJBRZHhEbcE5sqhEMB3RZA3EtFVEXOxlNxVTS3tncI
10
- qyNXiWDaxcipaens4ObSY1C2HTV7OWb7OMqSCIybeYTSfkaSdqmcl4S6zxXkjH1J
11
- tnjayAVzD+QVXGijsPLE2PFnJAh9iDET2cMsjabO1f6l1OQNyAtqpcyQcgfnyW0z
12
- g7tGxTYD+6wJHffM9d9txOUw6djkF6bDxyqB8lo4Z3IObCx18AZjI9XPS9QG7w6q
13
- LCWuMG2lkCcRgASqaVk9fEf9yMc2xxz5o3kCAwEAAaN3MHUwCQYDVR0TBAIwADAL
14
- BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFBqUFCKCOe5IuueUVqOB991jyCLLMB0GA1Ud
15
- EQQWMBSBEm1hY2llakBtZW5zZmVsZC5wbDAdBgNVHRIEFjAUgRJtYWNpZWpAbWVu
16
- c2ZlbGQucGwwDQYJKoZIhvcNAQELBQADggGBADD0/UuTTFgW+CGk2U0RDw2RBOca
17
- W2LTF/G7AOzuzD0Tc4voc7WXyrgKwJREv8rgBimLnNlgmFJLmtUCh2U/MgxvcilH
18
- yshYcbseNvjkrtYnLRlWZR4SSB6Zei5AlyGVQLPkvdsBpNegcG6w075YEwzX/38a
19
- 8V9B/Yri2OGELBz8ykl7BsXUgNoUPA/4pHF6YRLz+VirOaUIQ4JfY7xGj6fSOWWz
20
- /rQ/d77r6o1mfJYM/3BRVg73a3b7DmRnE5qjwmSaSQ7u802pJnLesmArch0xGCT/
21
- fMmRli1Qb+6qOTl9mzD6UDMAyFR4t6MStLm0mIEqM0nBO5nUdUWbC7l9qXEf8XBE
22
- 2DP28p3EqSuS+lKbAWKcqv7t0iRhhmaod+Yn9mcrLN1sa3q3KSQ9BCyxezCD4Mk2
23
- R2P11bWoCtr70BsccVrN8jEhzwXngMyI2gVt750Y+dbTu1KgRqZKp/ECe7ZzPzXj
24
- pIy9vHxTANKYVyI4qj8OrFdEM5BQNu8oQpL0iQ==
25
- -----END CERTIFICATE-----