zeebe_bpmn_rspec 0.2.0 → 0.3.0

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: 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