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 +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +96 -0
- data/docker-compose.yml +1 -1
- data/lib/zeebe_bpmn_rspec.rb +6 -1
- data/lib/zeebe_bpmn_rspec/activated_job.rb +15 -5
- data/lib/zeebe_bpmn_rspec/helpers.rb +15 -7
- data/lib/zeebe_bpmn_rspec/matchers/have_activated.rb +99 -0
- data/lib/zeebe_bpmn_rspec/matchers/have_headers.rb +15 -0
- data/lib/zeebe_bpmn_rspec/matchers/have_variables.rb +15 -0
- data/lib/zeebe_bpmn_rspec/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6bf6a270631bb041c26a38ccfacf5e57e6cbb8b91601f13e8bab26257151a4f8
|
4
|
+
data.tar.gz: 1e5e28c05d63f1317fc62ccf18b741e60ce9263b085d6e8a1da3232ec0bfeaf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 959b2bbb2c51a68bb7d7559aeffed2b475d660329ad33b7f87feba10e93af476ffd996dcfef7f81634c553423c8cb6dd2e82d0c0e1b280f5d072cb634880d4f8
|
7
|
+
data.tar.gz: 58ccf62381772827998bf76cc5ec18961d90fef06194d082848c4738b36fe4420a91c4f7d9f9f15f8fa8739395479566203337dbc412f802f0d35993644b77e1
|
data/CHANGELOG.md
CHANGED
@@ -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
|
data/docker-compose.yml
CHANGED
data/lib/zeebe_bpmn_rspec.rb
CHANGED
@@ -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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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:
|
97
|
-
requestTimeout:
|
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
|
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.
|
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-
|
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.
|
180
|
+
rubygems_version: 3.1.4
|
178
181
|
signing_key:
|
179
182
|
specification_version: 4
|
180
183
|
summary: Zeebe BPMN testing using RSpec
|