zeebe_bpmn_rspec 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ee557a1aed97212da2a198eafd8238859e12499f32e8ddf24d97d5240c83c36
4
- data.tar.gz: 0105ee8a65e00fbab192cf6f76710e43973bec36324b3defcc4f83882db833ca
3
+ metadata.gz: 6bf6a270631bb041c26a38ccfacf5e57e6cbb8b91601f13e8bab26257151a4f8
4
+ data.tar.gz: 1e5e28c05d63f1317fc62ccf18b741e60ce9263b085d6e8a1da3232ec0bfeaf8
5
5
  SHA512:
6
- metadata.gz: 978a61f885179d519ede6340a283b93f9c36e1d712c1279629500732afe01a9f9ac7483a484c17d99356bcebb0258fb04f65771492a6d2b6774cd9be64454f1b
7
- data.tar.gz: 6f235e5995f75fd04b7996708bb8a23d81cbb1b7bf1ecd8ebea46a5fba78fa1e5c60f8ab1e305e263d0e16e7ac2005dad78dfdf5e684528ff3cdf3343a2f9c2e
6
+ metadata.gz: 959b2bbb2c51a68bb7d7559aeffed2b475d660329ad33b7f87feba10e93af476ffd996dcfef7f81634c553423c8cb6dd2e82d0c0e1b280f5d072cb634880d4f8
7
+ data.tar.gz: 58ccf62381772827998bf76cc5ec18961d90fef06194d082848c4738b36fe4420a91c4f7d9f9f15f8fa8739395479566203337dbc412f802f0d35993644b77e1
@@ -1,5 +1,8 @@
1
1
  # zeebe_bpmn_rspec
2
2
 
3
+ ## v0.3.0
4
+ - Add custom matchers, `have_variables`, `have_headers`, and `have_activated`.
5
+
3
6
  ## v0.2.0
4
7
  - Add `retries` option to `ActivatedJob#and_fail`.
5
8
  - Add method aliases: `and_complete` (`complete`), `and_fail` (`fail`), `and_throw_error` (`throw_error`).
data/README.md CHANGED
@@ -39,6 +39,8 @@ end
39
39
 
40
40
  The gem adds the following helper methods to RSpec.
41
41
 
42
+ The gem also defines [Custom Matchers](#custom-matchers).
43
+
42
44
  ### Deploy Workflow
43
45
 
44
46
  The `deploy_workflow` method requires a path to a BPMN file and deploys it to Zeebe. There is no support for
@@ -217,6 +219,100 @@ publish_message("message_name", correlation_key: expected_value,
217
219
  variables: { foo: "bar" })
218
220
  ```
219
221
 
222
+ ### Custom Matchers
223
+
224
+ In addition to the helpers documented above, this gem defines custom RSpec matchers to provide a more typical
225
+ experience of expectations and matchers.
226
+
227
+ #### expect_job_of_type
228
+
229
+ The `expect_job_of_type` helper is a convenient wrapper to activate a job and set an expectation target.
230
+
231
+ ```ruby
232
+ expect_job_of_type("my_type")
233
+ ```
234
+
235
+ Similar to the `activate_job` helper, it activates a job and wraps the result in an `ActivatedJob` object.
236
+ That object is then passed to `expect()`. Unlike `activate_job`, this helper does not raise if there is no job activated.
237
+
238
+ This is equivalent to `expect(job_with_type("my_type")` or `expect(activate_job("my_type", validate: false))`.
239
+
240
+ `expect_job_of_type` is expected to be used with the matchers below.
241
+
242
+ #### have_activated
243
+
244
+ The `have_activated` matcher checks that the target represents an activated job. It will raise an error if no job
245
+ was activated.
246
+
247
+ ```ruby
248
+ expect_job_of_type("my_type").to have_activated
249
+ ```
250
+
251
+ Various additional methods can be chained on the `have_activated` matcher.
252
+
253
+ The `with_variables` method can be used to check the input variables that the job was activated with:
254
+
255
+ ```ruby
256
+ expect_job_of_type("my_type").to have_activated.with_variables(user_id: 123)
257
+ ```
258
+
259
+ The `with_headers` method can be used to check the headers that the job was activated with:
260
+
261
+ ```ruby
262
+ expect_job_of_type("my_type").to have_activated.with_headers(id_type: "user")
263
+ ```
264
+
265
+ The `with_variables` and `with_headers` methods can be chained on the same expectation:
266
+
267
+ ```ruby
268
+ expect_job_of_type("my_type").to have_activated.
269
+ with_variables(user_id: 123).
270
+ with_headers(id_type: "user")
271
+ ```
272
+
273
+ The matcher also supports methods to complete, fail, or throw an error for a job:
274
+
275
+ ```ruby
276
+ # Complete
277
+ expect_job_of_type("my_type").to have_activated.and_complete
278
+
279
+ # Complete with new variables
280
+ expect_job_of_type("my_type").to have_activated.and_complete(result_code: 456)
281
+
282
+ # Fail (sets retries to 0 by default)
283
+ expect_job_of_type("my_type").to have_activated.and_fail
284
+
285
+ # Fail and specify retries
286
+ expect_job_of_type("my_type").to have_activated.and_fail(retries: 1)
287
+
288
+ # Fail with an error message
289
+ expect_job_of_type("my_type").to have_activated.and_fail("boom!")
290
+
291
+ # Fail with an error message and specify retries
292
+ expect_job_of_type("my_type").to have_activated.and_fail("boom!", retries: 2)
293
+
294
+ # Throw an error (error code is required)
295
+ expect_job_of_type("my_type").to have_activated.and_throw_error("MY_ERROR")
296
+
297
+ # Throw an error with an error message
298
+ expect_job_of_type("my_type").to have_activated.and_throw_error("MY_ERROR", "went horribly wrong")
299
+ ```
300
+
301
+ Only one of `and_complete`, `and_fail`, or `and_throw_error` can be specified for a single expectation.
302
+
303
+ #### have_variables and have_headers
304
+
305
+ In addition to the `with_variables` and `with_headers` methods that can be chained onto the `have_activated`
306
+ matcher, there are matchers that can be used directly to set expectations on the variables or
307
+ headers for an `ActivatedJob`.
308
+
309
+ ```ruby
310
+ job = activate_job("my_type")
311
+
312
+ expect(job).to have_variables(user: 123)
313
+ expect(job).to have_headers(id_type: "user")
314
+ ```
315
+
220
316
  ## Tips & Tricks
221
317
 
222
318
  ### Enumerator for Multiple Jobs
@@ -18,7 +18,7 @@ x-service: &default-service
18
18
  stdin_open: true
19
19
  services:
20
20
  zeebe:
21
- image: camunda/zeebe:0.23.4
21
+ image: camunda/zeebe:${ZEEBE_VERSION:-0.24.1}
22
22
  environment:
23
23
  ZEEBE_LOG_LEVEL: debug
24
24
  volumes:
@@ -4,11 +4,12 @@ require "rspec"
4
4
  require "zeebe/client"
5
5
  require "zeebe_bpmn_rspec/helpers"
6
6
  require "zeebe_bpmn_rspec/version"
7
+ require "zeebe_bpmn_rspec/matchers/have_activated"
7
8
 
8
9
  # Top-level gem module
9
10
  module ZeebeBpmnRspec
10
11
  class << self
11
- attr_writer :client, :zeebe_address
12
+ attr_writer :client, :zeebe_address, :activate_request_timeout
12
13
 
13
14
  def configure
14
15
  yield(self)
@@ -23,6 +24,10 @@ module ZeebeBpmnRspec
23
24
  def zeebe_address
24
25
  @zeebe_address || ENV["ZEEBE_ADDRESS"] || (raise "zeebe_address must be set")
25
26
  end
27
+
28
+ def activate_request_timeout
29
+ @activate_request_timeout || 1000
30
+ end
26
31
  end
27
32
  end
28
33
 
@@ -10,25 +10,35 @@ module ZeebeBpmnRspec
10
10
 
11
11
  attr_reader :job, :type, :workflow_instance_key
12
12
 
13
- def initialize(job, type:, workflow_instance_key:, client:, context:)
13
+ def initialize(job, type:, workflow_instance_key:, client:, context:, validate:) # rubocop:disable Metrics/ParameterLists
14
14
  @job = job
15
15
  @type = type
16
16
  @workflow_instance_key = workflow_instance_key
17
17
  @client = client
18
18
  @context = context
19
19
 
20
- context.instance_eval do
21
- aggregate_failures do
22
- expect(job.workflowInstanceKey).to eq(workflow_instance_key)
23
- expect(job.type).to eq(type)
20
+ if validate
21
+ context.instance_eval do
22
+ aggregate_failures do
23
+ expect(job.workflowInstanceKey).to eq(workflow_instance_key)
24
+ expect(job.type).to eq(type)
25
+ end
24
26
  end
25
27
  end
26
28
  end
27
29
 
30
+ def raw
31
+ job
32
+ end
33
+
28
34
  def key
29
35
  job.key
30
36
  end
31
37
 
38
+ def to_s
39
+ raw.to_s
40
+ end
41
+
32
42
  def variables
33
43
  @_variables ||= JSON.parse(job.variables)
34
44
  end
@@ -64,7 +64,7 @@ module ZeebeBpmnRspec
64
64
  @__workflow_instance_key
65
65
  end
66
66
 
67
- def activate_job(type)
67
+ def activate_job(type, validate: true)
68
68
  stream = _zeebe_client.activate_jobs(ActivateJobsRequest.new(
69
69
  type: type,
70
70
  worker: "#{type}-#{SecureRandom.hex}",
@@ -75,26 +75,33 @@ module ZeebeBpmnRspec
75
75
 
76
76
  job = nil
77
77
  stream.find { |response| job = response.jobs.first }
78
- raise "No job with type #{type.inspect} found" if job.nil?
79
-
80
78
  # puts job.inspect # support debug logging?
81
79
 
82
80
  ActivatedJob.new(job,
83
81
  type: type,
84
82
  workflow_instance_key: workflow_instance_key,
85
83
  client: _zeebe_client,
86
- context: self)
84
+ context: self,
85
+ validate: validate)
87
86
  end
88
87
  alias process_job activate_job
89
88
  # TODO: deprecate process_job
90
89
 
90
+ def job_with_type(type)
91
+ activate_job(type, validate: false)
92
+ end
93
+
94
+ def expect_job_of_type(type)
95
+ expect(job_with_type(type))
96
+ end
97
+
91
98
  def activate_jobs(type, max_jobs: nil)
92
99
  stream = _zeebe_client.activate_jobs(ActivateJobsRequest.new({
93
100
  type: type,
94
101
  worker: "#{type}-#{SecureRandom.hex}",
95
102
  maxJobsToActivate: max_jobs,
96
- timeout: 5000, # TODO: configure
97
- requestTimeout: 5000,
103
+ timeout: 1000,
104
+ requestTimeout: ZeebeBpmnRspec.activate_request_timeout,
98
105
  }.compact))
99
106
 
100
107
  Enumerator.new do |yielder|
@@ -104,7 +111,8 @@ module ZeebeBpmnRspec
104
111
  type: type,
105
112
  workflow_instance_key: workflow_instance_key,
106
113
  client: _zeebe_client,
107
- context: self)
114
+ context: self,
115
+ validate: true)
108
116
  end
109
117
  end
110
118
  end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zeebe_bpmn_rspec/matchers/have_variables"
4
+ require "zeebe_bpmn_rspec/matchers/have_headers"
5
+
6
+ module ZeebeBpmnRspec
7
+ class HaveActivatedMatcherError < StandardError
8
+ def initialize
9
+ super("Only one of complete, fail, and throw error can be specified")
10
+ end
11
+ end
12
+ end
13
+
14
+ # rubocop:disable Metrics/BlockLength
15
+ RSpec::Matchers.define :have_activated do
16
+ match do |job|
17
+ @job = job
18
+
19
+ @matcher_error = nil
20
+ begin
21
+ aggregate_failures "activated job#{of_type(job)}" do
22
+ unless job.is_a?(ZeebeBpmnRspec::ActivatedJob)
23
+ raise ArgumentError.new("expectation target must be a "\
24
+ "#{ZeebeBpmnRspec::ActivatedJob.name}, got #{job.inspect}")
25
+ end
26
+
27
+ if job.raw.nil?
28
+ raise RSpec::Expectations::ExpectationNotMetError.new("expected activated job#{of_type(job)}, got nil")
29
+ end
30
+
31
+ expect(job).to have_variables(@variables) if @variables
32
+ expect(job).to have_headers(@headers) if @headers
33
+ end
34
+ rescue Exception => e # rubocop:disable Lint/RescueException
35
+ @matcher_error = e
36
+ end
37
+ return false if @matcher_error
38
+
39
+ if @complete
40
+ job.complete(@output || {})
41
+ elsif @fail
42
+ job.fail(@fail_message, retries: @retries)
43
+ elsif @throw
44
+ job.throw_error(@error_code, @throw_message)
45
+ end
46
+
47
+ true
48
+ end
49
+
50
+ def of_type(job)
51
+ job.respond_to?(:type) ? " of type #{job.type}" : nil
52
+ end
53
+
54
+ failure_message do |_job|
55
+ raise matcher_error
56
+ end
57
+
58
+ attr_reader :job, :matcher_error
59
+
60
+ def predestined?
61
+ @complete || @fail || @throw
62
+ end
63
+
64
+ def check_predestined!
65
+ raise ZeebeBpmnRspec::HaveActivatedMatcherError.new if predestined?
66
+ end
67
+
68
+ chain :with_variables do |variables|
69
+ @variables = variables.is_a?(Hash) ? variables.stringify_keys : variables
70
+ end
71
+
72
+ chain :with_headers do |headers|
73
+ @headers = headers.is_a?(Hash) ? headers.stringify_keys : headers
74
+ end
75
+
76
+ chain :and_complete do |output = nil|
77
+ check_predestined!
78
+
79
+ @output = output
80
+ @complete = true
81
+ end
82
+
83
+ chain :and_fail do |message = nil, retries: 0|
84
+ check_predestined!
85
+
86
+ @fail_message = message
87
+ @retries = retries
88
+ @fail = true
89
+ end
90
+
91
+ chain :and_throw_error do |error_code, message = nil|
92
+ check_predestined!
93
+
94
+ @error_code = error_code
95
+ @throw_message = message
96
+ @throw = true
97
+ end
98
+ end
99
+ # rubocop:enable Metrics/BlockLength
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec::Matchers.define :have_headers do
4
+ match do |actual|
5
+ @job = actual
6
+ @actual = @job.headers
7
+ values_match?(expected, @actual)
8
+ end
9
+
10
+ failure_message do |_actual|
11
+ "expected that job:\n #{@job}\n\nwould have headers #{expected}"
12
+ end
13
+
14
+ diffable
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec::Matchers.define :have_variables do |expected|
4
+ match do |actual|
5
+ @job = actual
6
+ @actual = @job.variables
7
+ values_match?(expected, @actual)
8
+ end
9
+
10
+ failure_message do |_actual|
11
+ "expected that job:\n #{@job}\n\nwould have variables #{expected}"
12
+ end
13
+
14
+ diffable
15
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ZeebeBpmnRspec
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zeebe_bpmn_rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ezCater, Inc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-29 00:00:00.000000000 Z
11
+ date: 2020-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -152,6 +152,9 @@ files:
152
152
  - lib/zeebe_bpmn_rspec.rb
153
153
  - lib/zeebe_bpmn_rspec/activated_job.rb
154
154
  - lib/zeebe_bpmn_rspec/helpers.rb
155
+ - lib/zeebe_bpmn_rspec/matchers/have_activated.rb
156
+ - lib/zeebe_bpmn_rspec/matchers/have_headers.rb
157
+ - lib/zeebe_bpmn_rspec/matchers/have_variables.rb
155
158
  - lib/zeebe_bpmn_rspec/version.rb
156
159
  - zeebe_bpmn_rspec.gemspec
157
160
  homepage: https://github.com/ezcater/zeebe_bpmn_rspec
@@ -174,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
174
177
  - !ruby/object:Gem::Version
175
178
  version: '0'
176
179
  requirements: []
177
- rubygems_version: 3.0.3
180
+ rubygems_version: 3.1.4
178
181
  signing_key:
179
182
  specification_version: 4
180
183
  summary: Zeebe BPMN testing using RSpec