zeebe_bpmn_rspec 0.2.0 → 1.0.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 +28 -0
- data/README.md +154 -17
- data/docker-compose.simple-monitor.yml +17 -0
- data/docker-compose.yml +2 -15
- data/lib/zeebe_bpmn_rspec.rb +8 -1
- data/lib/zeebe_bpmn_rspec/activated_job.rb +39 -8
- data/lib/zeebe_bpmn_rspec/deprecate_workflow_alias.rb +14 -0
- data/lib/zeebe_bpmn_rspec/helpers.rb +76 -51
- 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
- data/zeebe_bpmn_rspec.gemspec +4 -2
- metadata +15 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbc8b0a3a6bf05f4ef29f2a5285b452afa1e733f2e166a521ba28e48dc2f94d1
|
4
|
+
data.tar.gz: 5ef538eea22fce15ba4356ea06204891b69ec51170706cc804d005f1639107f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89756e04128e43c7386cc13f785dc3146568b76a7ed5b841c9ec71851f243f043c5d91e1709dd6a44ec41dc05f6e8c2c2414e20fb4227eb3a896b1ee12efad5f
|
7
|
+
data.tar.gz: 3e2f49b5e1ad94878f83ac4b6efb69028a77728e3f53b8f46b2fa134cc6ea63b19f7f3c9e88717ab9942cc0daf97d103ebdfdb12492e937c5f59361b1ec069dd
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,33 @@
|
|
1
1
|
# zeebe_bpmn_rspec
|
2
2
|
|
3
|
+
## v1.0.0
|
4
|
+
- Support Zeebe 1.0.0. Method names now use `process` instead of `workflow`
|
5
|
+
to match the renaming in Zeebe. Previous methods are deprecated and will be
|
6
|
+
removed in a future release.
|
7
|
+
|
8
|
+
## v0.5.0 (unreleased)
|
9
|
+
- Require Ruby 2.6 or later.
|
10
|
+
- Require `worker` to be specified when activating a job. This argument is
|
11
|
+
defaulted but can no longer be specified as blank.
|
12
|
+
|
13
|
+
## v0.4.1
|
14
|
+
- Allow `with_workflow_instance` to be called without a block.
|
15
|
+
- Allow `worker` to be specified when activating a job.
|
16
|
+
- Expose `workflow_instance_key` for activated jobs.
|
17
|
+
|
18
|
+
## v0.4.0
|
19
|
+
- Add `ttl_ms` option for `publish_message`.
|
20
|
+
- Add `update_retries` method to `ActivatedJob` class.
|
21
|
+
- Add `set_variables` helper.
|
22
|
+
- Add support for `:fetch_variables` option when activating jobs.
|
23
|
+
|
24
|
+
## v0.3.1
|
25
|
+
- Use consistent activate request timeout.
|
26
|
+
- Provide a better error when a job is not activated.
|
27
|
+
|
28
|
+
## v0.3.0
|
29
|
+
- Add custom matchers, `have_variables`, `have_headers`, and `have_activated`.
|
30
|
+
|
3
31
|
## v0.2.0
|
4
32
|
- Add `retries` option to `ActivatedJob#and_fail`.
|
5
33
|
- Add method aliases: `and_complete` (`complete`), `and_fail` (`fail`), `and_throw_error` (`throw_error`).
|
data/README.md
CHANGED
@@ -39,24 +39,26 @@ end
|
|
39
39
|
|
40
40
|
The gem adds the following helper methods to RSpec.
|
41
41
|
|
42
|
-
|
42
|
+
The gem also defines [Custom Matchers](#custom-matchers).
|
43
43
|
|
44
|
-
|
44
|
+
### Deploy Process
|
45
|
+
|
46
|
+
The `deploy_process` (previously `deploy_workflow`) method requires a path to a BPMN file and deploys it to Zeebe. There is no support for
|
45
47
|
removing a BPMN file once deployed, so this can be done once before the examples that use it.
|
46
48
|
|
47
49
|
```ruby
|
48
|
-
before(:all) {
|
50
|
+
before(:all) { deploy_process(filepath) }
|
49
51
|
```
|
50
52
|
|
51
|
-
A custom name can also be specified for the
|
53
|
+
A custom name can also be specified for the process:
|
52
54
|
|
53
55
|
```ruby
|
54
|
-
before(:all) {
|
56
|
+
before(:all) { deploy_process(filepath, "custom_name") }
|
55
57
|
```
|
56
58
|
|
57
|
-
### With
|
59
|
+
### With Process Instance
|
58
60
|
|
59
|
-
The `with_workflow_instance` method is used to create an instance for the specified
|
61
|
+
The `with_process_instance` (previously `with_workflow_instance`) method is used to create an instance for the specified process
|
60
62
|
and then yields a block that can interact with the instance.
|
61
63
|
|
62
64
|
This method ensures that an active instance is cancelled at the end of the block.
|
@@ -65,14 +67,14 @@ For testing BPMN files it is expected that most of the test definition will be w
|
|
65
67
|
call to this method.
|
66
68
|
|
67
69
|
```ruby
|
68
|
-
|
70
|
+
with_process_instance("file_basename") do
|
69
71
|
...
|
70
72
|
end
|
71
73
|
```
|
72
74
|
|
73
75
|
### Processing Jobs
|
74
76
|
|
75
|
-
A single job can be processed for a
|
77
|
+
A single job can be processed for a process by calling `activate_job` (previously `process_job`).
|
76
78
|
`activate_job` is called with a job type:
|
77
79
|
|
78
80
|
```ruby
|
@@ -127,8 +129,8 @@ activate_job("my_job").
|
|
127
129
|
expect_input(user_id: 123).
|
128
130
|
and_complete
|
129
131
|
|
130
|
-
# Jobs can be completed with data that is merged with variables in the
|
131
|
-
|
132
|
+
# Jobs can be completed with data that is merged with variables in the process
|
133
|
+
activate_job("my_job").
|
132
134
|
and_complete(status: "ACTIVATED")
|
133
135
|
```
|
134
136
|
|
@@ -155,6 +157,16 @@ job = activate_job("my_job")
|
|
155
157
|
job.fail(retries: 1)
|
156
158
|
```
|
157
159
|
|
160
|
+
#### Update Retries
|
161
|
+
|
162
|
+
The retries for a job can also be modified using the `update_retries` method:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
job = activate_job("my_job")
|
166
|
+
|
167
|
+
job.update_retries(3)
|
168
|
+
```
|
169
|
+
|
158
170
|
#### Throw Error
|
159
171
|
|
160
172
|
The `and_throw_error` (also aliased as `throw_error`) method can be used to throw an error for a job. The error code is required and an
|
@@ -186,17 +198,17 @@ The maximum number of jobs to return can be specified:
|
|
186
198
|
jobs = activate_jobs("my_job", max_jobs: 2).to_a
|
187
199
|
```
|
188
200
|
|
189
|
-
###
|
201
|
+
### Process Complete
|
190
202
|
|
191
|
-
The `workflow_complete!` method can be used to assert that the current
|
192
|
-
test. This is implemented by cancelling the
|
203
|
+
The `process_complete!` (previously `workflow_complete!`) method can be used to assert that the current process is complete at the end of a
|
204
|
+
test. This is implemented by cancelling the process and checking for an error that it is already
|
193
205
|
complete.
|
194
206
|
|
195
207
|
```ruby
|
196
|
-
|
208
|
+
with_process_instance("file_basename") do
|
197
209
|
...
|
198
210
|
|
199
|
-
|
211
|
+
process_complete!
|
200
212
|
end
|
201
213
|
```
|
202
214
|
|
@@ -217,6 +229,131 @@ publish_message("message_name", correlation_key: expected_value,
|
|
217
229
|
variables: { foo: "bar" })
|
218
230
|
```
|
219
231
|
|
232
|
+
The time-to-live (in milliseconds) cna also be specified for a message.
|
233
|
+
It defaults to 5000 milliseconds if unspecified.
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
publish_message("message_name", correlation_key: expected_value, ttl_ms: 1000)
|
237
|
+
```
|
238
|
+
|
239
|
+
### Set Variables
|
240
|
+
|
241
|
+
The `set_variables` method can be used to set variables for a specified
|
242
|
+
scope in Zeebe:
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
# process_instance_key is a method that returns the key for the current process instance
|
246
|
+
set_variables(process_instance_key, { foo: "bar" })
|
247
|
+
```
|
248
|
+
|
249
|
+
An activated job can be used to determine the key for the task that it is associated with:
|
250
|
+
|
251
|
+
```ruby
|
252
|
+
job = job_with_type("my_type")
|
253
|
+
set_variables(job.task_key, { foo: "baz"})
|
254
|
+
```
|
255
|
+
|
256
|
+
Variables default to being local to the scope on which they are set. This
|
257
|
+
can be overridden by specifying the `:local` option:
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
set_variables(job.task_key, { foo: "baz"}, local: false)
|
261
|
+
```
|
262
|
+
|
263
|
+
### Custom Matchers
|
264
|
+
|
265
|
+
In addition to the helpers documented above, this gem defines custom RSpec matchers to provide a more typical
|
266
|
+
experience of expectations and matchers.
|
267
|
+
|
268
|
+
#### expect_job_of_type
|
269
|
+
|
270
|
+
The `expect_job_of_type` helper is a convenient wrapper to activate a job and set an expectation target.
|
271
|
+
|
272
|
+
```ruby
|
273
|
+
expect_job_of_type("my_type")
|
274
|
+
```
|
275
|
+
|
276
|
+
Similar to the `activate_job` helper, it activates a job and wraps the result in an `ActivatedJob` object.
|
277
|
+
That object is then passed to `expect()`. Unlike `activate_job`, this helper does not raise if there is no job activated.
|
278
|
+
|
279
|
+
This is equivalent to `expect(job_with_type("my_type")` or `expect(activate_job("my_type", validate: false))`.
|
280
|
+
|
281
|
+
`expect_job_of_type` is expected to be used with the matchers below.
|
282
|
+
|
283
|
+
#### have_activated
|
284
|
+
|
285
|
+
The `have_activated` matcher checks that the target represents an activated job. It will raise an error if no job
|
286
|
+
was activated.
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
expect_job_of_type("my_type").to have_activated
|
290
|
+
```
|
291
|
+
|
292
|
+
Various additional methods can be chained on the `have_activated` matcher.
|
293
|
+
|
294
|
+
The `with_variables` method can be used to check the input variables that the job was activated with:
|
295
|
+
|
296
|
+
```ruby
|
297
|
+
expect_job_of_type("my_type").to have_activated.with_variables(user_id: 123)
|
298
|
+
```
|
299
|
+
|
300
|
+
The `with_headers` method can be used to check the headers that the job was activated with:
|
301
|
+
|
302
|
+
```ruby
|
303
|
+
expect_job_of_type("my_type").to have_activated.with_headers(id_type: "user")
|
304
|
+
```
|
305
|
+
|
306
|
+
The `with_variables` and `with_headers` methods can be chained on the same expectation:
|
307
|
+
|
308
|
+
```ruby
|
309
|
+
expect_job_of_type("my_type").to have_activated.
|
310
|
+
with_variables(user_id: 123).
|
311
|
+
with_headers(id_type: "user")
|
312
|
+
```
|
313
|
+
|
314
|
+
The matcher also supports methods to complete, fail, or throw an error for a job:
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
# Complete
|
318
|
+
expect_job_of_type("my_type").to have_activated.and_complete
|
319
|
+
|
320
|
+
# Complete with new variables
|
321
|
+
expect_job_of_type("my_type").to have_activated.and_complete(result_code: 456)
|
322
|
+
|
323
|
+
# Fail (sets retries to 0 by default)
|
324
|
+
expect_job_of_type("my_type").to have_activated.and_fail
|
325
|
+
|
326
|
+
# Fail and specify retries
|
327
|
+
expect_job_of_type("my_type").to have_activated.and_fail(retries: 1)
|
328
|
+
|
329
|
+
# Fail with an error message
|
330
|
+
expect_job_of_type("my_type").to have_activated.and_fail("boom!")
|
331
|
+
|
332
|
+
# Fail with an error message and specify retries
|
333
|
+
expect_job_of_type("my_type").to have_activated.and_fail("boom!", retries: 2)
|
334
|
+
|
335
|
+
# Throw an error (error code is required)
|
336
|
+
expect_job_of_type("my_type").to have_activated.and_throw_error("MY_ERROR")
|
337
|
+
|
338
|
+
# Throw an error with an error message
|
339
|
+
expect_job_of_type("my_type").to have_activated.and_throw_error("MY_ERROR", "went horribly wrong")
|
340
|
+
```
|
341
|
+
|
342
|
+
Only one of `and_complete`, `and_fail`, or `and_throw_error` can be specified for a single expectation.
|
343
|
+
|
344
|
+
#### have_variables and have_headers
|
345
|
+
|
346
|
+
In addition to the `with_variables` and `with_headers` methods that can be chained onto the `have_activated`
|
347
|
+
matcher, there are matchers that can be used directly to set expectations on the variables or
|
348
|
+
headers for an `ActivatedJob`.
|
349
|
+
|
350
|
+
```ruby
|
351
|
+
job = activate_job("my_type")
|
352
|
+
|
353
|
+
expect(job).to have_variables(user: 123)
|
354
|
+
expect(job).to have_headers(id_type: "user")
|
355
|
+
```
|
356
|
+
|
220
357
|
## Tips & Tricks
|
221
358
|
|
222
359
|
### Enumerator for Multiple Jobs
|
@@ -233,7 +370,7 @@ to specify a short duration.
|
|
233
370
|
|
234
371
|
The current gem and approach have some limitations:
|
235
372
|
|
236
|
-
1. You can interact with only one
|
373
|
+
1. You can interact with only one process at a time.
|
237
374
|
|
238
375
|
## Development
|
239
376
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
version: "3.4"
|
2
|
+
|
3
|
+
services:
|
4
|
+
zeebe:
|
5
|
+
volumes:
|
6
|
+
- ./compose/zeebe-hazelcast-exporter.jar:/usr/local/zeebe/exporters/zeebe-hazelcast-exporter.jar
|
7
|
+
- ./compose/application.yml:/usr/local/zeebe/config/application.yaml
|
8
|
+
|
9
|
+
monitor:
|
10
|
+
image: camunda/zeebe-simple-monitor:0.19.1
|
11
|
+
environment:
|
12
|
+
- zeebe.client.broker.contactPoint=zeebe:26500
|
13
|
+
- zeebe.client.worker.hazelcast.connection=zeebe:5701
|
14
|
+
ports:
|
15
|
+
- "8082:8082"
|
16
|
+
depends_on:
|
17
|
+
- zeebe
|
data/docker-compose.yml
CHANGED
@@ -8,7 +8,7 @@ x-environment: &default-environment
|
|
8
8
|
BUNDLE_DISABLE_SHARED_GEMS: "true"
|
9
9
|
ZEEBE_ADDRESS: zeebe:26500
|
10
10
|
x-service: &default-service
|
11
|
-
image: ruby:2.
|
11
|
+
image: ruby:2.7.3
|
12
12
|
volumes:
|
13
13
|
- .:/usr/src/gem
|
14
14
|
- ./compose/entrypoint.sh:/tmp/entrypoint.sh
|
@@ -18,22 +18,9 @@ x-service: &default-service
|
|
18
18
|
stdin_open: true
|
19
19
|
services:
|
20
20
|
zeebe:
|
21
|
-
image: camunda/zeebe
|
21
|
+
image: camunda/zeebe:${ZEEBE_VERSION:-1.0.0}
|
22
22
|
environment:
|
23
23
|
ZEEBE_LOG_LEVEL: debug
|
24
|
-
volumes:
|
25
|
-
- ./compose/zeebe-hazelcast-exporter.jar:/usr/local/zeebe/exporters/zeebe-hazelcast-exporter.jar
|
26
|
-
- ./compose/application.yml:/usr/local/zeebe/config/application.yaml
|
27
|
-
|
28
|
-
monitor:
|
29
|
-
image: camunda/zeebe-simple-monitor:0.19.0
|
30
|
-
environment:
|
31
|
-
- zeebe.client.broker.contactPoint=zeebe:26500
|
32
|
-
- zeebe.client.worker.hazelcast.connection=zeebe:5701
|
33
|
-
ports:
|
34
|
-
- "8082:8082"
|
35
|
-
depends_on:
|
36
|
-
- zeebe
|
37
24
|
|
38
25
|
console:
|
39
26
|
<<: *default-service
|
data/lib/zeebe_bpmn_rspec.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support"
|
3
4
|
require "rspec"
|
4
5
|
require "zeebe/client"
|
6
|
+
require "zeebe_bpmn_rspec/deprecate_workflow_alias"
|
5
7
|
require "zeebe_bpmn_rspec/helpers"
|
6
8
|
require "zeebe_bpmn_rspec/version"
|
9
|
+
require "zeebe_bpmn_rspec/matchers/have_activated"
|
7
10
|
|
8
11
|
# Top-level gem module
|
9
12
|
module ZeebeBpmnRspec
|
10
13
|
class << self
|
11
|
-
attr_writer :client, :zeebe_address
|
14
|
+
attr_writer :client, :zeebe_address, :activate_request_timeout
|
12
15
|
|
13
16
|
def configure
|
14
17
|
yield(self)
|
@@ -23,6 +26,10 @@ module ZeebeBpmnRspec
|
|
23
26
|
def zeebe_address
|
24
27
|
@zeebe_address || ENV["ZEEBE_ADDRESS"] || (raise "zeebe_address must be set")
|
25
28
|
end
|
29
|
+
|
30
|
+
def activate_request_timeout
|
31
|
+
@activate_request_timeout || 1000
|
32
|
+
end
|
26
33
|
end
|
27
34
|
end
|
28
35
|
|
@@ -1,34 +1,58 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support"
|
4
3
|
require "active_support/core_ext/hash/keys"
|
5
4
|
require "json"
|
6
5
|
|
7
6
|
module ZeebeBpmnRspec
|
8
7
|
class ActivatedJob
|
9
8
|
include ::Zeebe::Client::GatewayProtocol # for direct reference of request classes
|
9
|
+
extend DeprecateWorkflowAlias
|
10
10
|
|
11
|
-
attr_reader :job, :type
|
11
|
+
attr_reader :job, :type
|
12
12
|
|
13
|
-
def initialize(job, type:,
|
13
|
+
def initialize(job, type:, process_instance_key:, client:, context:, validate:) # rubocop:disable Metrics/ParameterLists
|
14
14
|
@job = job
|
15
15
|
@type = type
|
16
|
-
@
|
16
|
+
@process_instance_key = process_instance_key
|
17
17
|
@client = client
|
18
18
|
@context = context
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
expect(job
|
23
|
-
|
20
|
+
if validate
|
21
|
+
context.instance_eval do
|
22
|
+
expect(job).not_to be_nil, "expected to receive job of type '#{type}' but received none"
|
23
|
+
aggregate_failures do
|
24
|
+
expect(job.processInstanceKey).to eq(process_instance_key)
|
25
|
+
expect(job.type).to eq(type)
|
26
|
+
end
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
31
|
+
def raw
|
32
|
+
job
|
33
|
+
end
|
34
|
+
|
28
35
|
def key
|
29
36
|
job.key
|
30
37
|
end
|
31
38
|
|
39
|
+
def process_instance_key
|
40
|
+
job.processInstanceKey
|
41
|
+
end
|
42
|
+
deprecate_workflow_alias :workflow_instance_key, :process_instance_key
|
43
|
+
|
44
|
+
def retries
|
45
|
+
job.retries
|
46
|
+
end
|
47
|
+
|
48
|
+
def task_key
|
49
|
+
job.elementInstanceKey
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
raw.to_s
|
54
|
+
end
|
55
|
+
|
32
56
|
def variables
|
33
57
|
@_variables ||= JSON.parse(job.variables)
|
34
58
|
end
|
@@ -87,6 +111,13 @@ module ZeebeBpmnRspec
|
|
87
111
|
end
|
88
112
|
alias complete and_complete
|
89
113
|
|
114
|
+
def update_retries(retries = 1)
|
115
|
+
client.update_job_retries(UpdateJobRetriesRequest.new(
|
116
|
+
jobKey: job.key,
|
117
|
+
retries: retries
|
118
|
+
))
|
119
|
+
end
|
120
|
+
|
90
121
|
private
|
91
122
|
|
92
123
|
attr_reader :client, :context
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/deprecation"
|
4
|
+
|
5
|
+
module ZeebeBpmnRspec
|
6
|
+
module DeprecateWorkflowAlias
|
7
|
+
WorkflowDeprecation = ActiveSupport::Deprecation.new("v2.0", "ZeebeBpmnRspec")
|
8
|
+
|
9
|
+
def deprecate_workflow_alias(deprecated_name, new_name)
|
10
|
+
alias_method deprecated_name, new_name
|
11
|
+
deprecate deprecated_name => new_name, deprecator: WorkflowDeprecation
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,42 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/object/blank"
|
3
4
|
require "zeebe_bpmn_rspec/activated_job"
|
4
5
|
|
5
6
|
module ZeebeBpmnRspec
|
6
7
|
module Helpers # rubocop:disable Metrics/ModuleLength
|
7
8
|
include ::Zeebe::Client::GatewayProtocol # for direct reference of request classes
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
extend DeprecateWorkflowAlias
|
10
|
+
|
11
|
+
def deploy_process(path, name = nil)
|
12
|
+
_zeebe_client.deploy_process(DeployProcessRequest.new(
|
13
|
+
processes: [ProcessRequestObject.new(
|
14
|
+
name: (name && "#{name}.bpmn") || File.basename(path),
|
15
|
+
definition: File.read(path)
|
16
|
+
)]
|
17
|
+
))
|
17
18
|
rescue StandardError => e
|
18
|
-
raise "Failed to deploy
|
19
|
+
raise "Failed to deploy precess: #{e}"
|
19
20
|
end
|
21
|
+
deprecate_workflow_alias :deploy_workflow, :deploy_process
|
20
22
|
|
21
|
-
def
|
23
|
+
def with_process_instance(name, variables = {})
|
22
24
|
system_error = nil
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@
|
29
|
-
yield(
|
25
|
+
process = _zeebe_client.create_process_instance(CreateProcessInstanceRequest.new(
|
26
|
+
bpmnProcessId: name,
|
27
|
+
version: -1, # always latest
|
28
|
+
variables: variables.to_json
|
29
|
+
))
|
30
|
+
@__process_instance_key = process.processInstanceKey
|
31
|
+
yield(process.processInstanceKey) if block_given?
|
30
32
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
31
33
|
# exceptions are rescued to ensure that instances are cancelled
|
32
34
|
# any error is re-raised below
|
33
35
|
system_error = e
|
34
36
|
ensure
|
35
|
-
if
|
37
|
+
if process&.processInstanceKey
|
36
38
|
begin
|
37
|
-
_zeebe_client.
|
38
|
-
|
39
|
-
|
39
|
+
_zeebe_client.cancel_process_instance(CancelProcessInstanceRequest.new(
|
40
|
+
processInstanceKey: process.processInstanceKey
|
41
|
+
))
|
40
42
|
rescue GRPC::NotFound => _e
|
41
43
|
# expected
|
42
44
|
rescue StandardError => _e
|
@@ -45,56 +47,70 @@ module ZeebeBpmnRspec
|
|
45
47
|
end
|
46
48
|
raise system_error if system_error
|
47
49
|
end
|
50
|
+
deprecate_workflow_alias :with_workflow_instance, :with_process_instance
|
48
51
|
|
49
|
-
def
|
52
|
+
def process_complete!(wait_seconds: 0.25)
|
50
53
|
error = nil
|
51
|
-
sleep
|
54
|
+
sleep(wait_seconds)
|
52
55
|
begin
|
53
|
-
_zeebe_client.
|
54
|
-
|
55
|
-
|
56
|
+
_zeebe_client.cancel_process_instance(CancelProcessInstanceRequest.new(
|
57
|
+
processInstanceKey: process_instance_key
|
58
|
+
))
|
56
59
|
rescue GRPC::NotFound => e
|
57
60
|
error = e
|
58
61
|
end
|
59
62
|
|
60
|
-
raise "Expected
|
63
|
+
raise "Expected process instance #{process_instance_key} to be complete" if error.nil?
|
61
64
|
end
|
65
|
+
deprecate_workflow_alias :workflow_complete!, :process_complete!
|
62
66
|
|
63
|
-
def
|
64
|
-
@
|
67
|
+
def process_instance_key
|
68
|
+
@__process_instance_key
|
65
69
|
end
|
70
|
+
deprecate_workflow_alias :workflow_instance_key, :process_instance_key
|
66
71
|
|
67
|
-
def activate_job(type)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
def activate_job(type, fetch_variables: nil, validate: true, worker: "#{type}-#{SecureRandom.hex}")
|
73
|
+
raise ArgumentError.new("'worker' cannot be blank") if worker.blank?
|
74
|
+
|
75
|
+
stream = _zeebe_client.activate_jobs(ActivateJobsRequest.new({
|
76
|
+
type: type,
|
77
|
+
worker: worker,
|
78
|
+
maxJobsToActivate: 1,
|
79
|
+
timeout: 1000,
|
80
|
+
fetchVariable: fetch_variables&.then { |v| Array(v) },
|
81
|
+
requestTimeout: ZeebeBpmnRspec.activate_request_timeout,
|
82
|
+
}.compact))
|
75
83
|
|
76
84
|
job = nil
|
77
85
|
stream.find { |response| job = response.jobs.first }
|
78
|
-
raise "No job with type #{type.inspect} found" if job.nil?
|
79
|
-
|
80
86
|
# puts job.inspect # support debug logging?
|
81
87
|
|
82
88
|
ActivatedJob.new(job,
|
83
89
|
type: type,
|
84
|
-
|
90
|
+
process_instance_key: process_instance_key,
|
85
91
|
client: _zeebe_client,
|
86
|
-
context: self
|
92
|
+
context: self,
|
93
|
+
validate: validate)
|
87
94
|
end
|
88
95
|
alias process_job activate_job
|
89
|
-
|
96
|
+
deprecate process_job: :activate_job
|
90
97
|
|
91
|
-
def
|
98
|
+
def job_with_type(type, fetch_variables: nil)
|
99
|
+
activate_job(type, fetch_variables: fetch_variables, validate: false)
|
100
|
+
end
|
101
|
+
|
102
|
+
def expect_job_of_type(type, fetch_variables: nil)
|
103
|
+
expect(job_with_type(type, fetch_variables: fetch_variables))
|
104
|
+
end
|
105
|
+
|
106
|
+
def activate_jobs(type, max_jobs: nil, fetch_variables: nil)
|
92
107
|
stream = _zeebe_client.activate_jobs(ActivateJobsRequest.new({
|
93
108
|
type: type,
|
94
109
|
worker: "#{type}-#{SecureRandom.hex}",
|
95
110
|
maxJobsToActivate: max_jobs,
|
96
|
-
timeout:
|
97
|
-
|
111
|
+
timeout: 1000,
|
112
|
+
fetchVariable: fetch_variables&.then { |v| Array(v) },
|
113
|
+
requestTimeout: ZeebeBpmnRspec.activate_request_timeout,
|
98
114
|
}.compact))
|
99
115
|
|
100
116
|
Enumerator.new do |yielder|
|
@@ -102,27 +118,36 @@ module ZeebeBpmnRspec
|
|
102
118
|
response.jobs.each do |job|
|
103
119
|
yielder << ActivatedJob.new(job,
|
104
120
|
type: type,
|
105
|
-
|
121
|
+
process_instance_key: process_instance_key,
|
106
122
|
client: _zeebe_client,
|
107
|
-
context: self
|
123
|
+
context: self,
|
124
|
+
validate: true)
|
108
125
|
end
|
109
126
|
end
|
110
127
|
end
|
111
128
|
end
|
112
129
|
|
113
|
-
def publish_message(name, correlation_key:, variables: nil)
|
130
|
+
def publish_message(name, correlation_key:, variables: nil, ttl_ms: 5000)
|
114
131
|
_zeebe_client.publish_message(PublishMessageRequest.new(
|
115
132
|
{
|
116
133
|
name: name,
|
117
134
|
correlationKey: correlation_key,
|
118
|
-
timeToLive:
|
135
|
+
timeToLive: ttl_ms,
|
119
136
|
variables: variables&.to_json,
|
120
137
|
}.compact
|
121
138
|
))
|
122
139
|
end
|
123
140
|
|
141
|
+
def set_variables(key, variables, local: true)
|
142
|
+
_zeebe_client.set_variables(SetVariablesRequest.new(
|
143
|
+
elementInstanceKey: key,
|
144
|
+
variables: variables.to_json,
|
145
|
+
local: local
|
146
|
+
))
|
147
|
+
end
|
148
|
+
|
124
149
|
def reset_zeebe!
|
125
|
-
@
|
150
|
+
@__process_instance_key = nil
|
126
151
|
end
|
127
152
|
|
128
153
|
private
|
@@ -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
|
data/zeebe_bpmn_rspec.gemspec
CHANGED
@@ -41,7 +41,9 @@ Gem::Specification.new do |spec|
|
|
41
41
|
spec.executables = []
|
42
42
|
spec.require_paths = ["lib"]
|
43
43
|
|
44
|
-
spec.
|
44
|
+
spec.required_ruby_version = ">= 2.6"
|
45
|
+
|
46
|
+
spec.add_development_dependency "bundler", "~> 2.1"
|
45
47
|
spec.add_development_dependency "ezcater_rubocop", "2.0.0"
|
46
48
|
spec.add_development_dependency "overcommit"
|
47
49
|
spec.add_development_dependency "rake", "~> 10.0"
|
@@ -50,5 +52,5 @@ Gem::Specification.new do |spec|
|
|
50
52
|
|
51
53
|
spec.add_runtime_dependency "activesupport"
|
52
54
|
spec.add_runtime_dependency "rspec", "~> 3.4"
|
53
|
-
spec.add_runtime_dependency "zeebe-client"
|
55
|
+
spec.add_runtime_dependency "zeebe-client", "~> 0.14.0"
|
54
56
|
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: 1.0.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:
|
11
|
+
date: 2021-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1
|
19
|
+
version: '2.1'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1
|
26
|
+
version: '2.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: ezcater_rubocop
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,16 +126,16 @@ dependencies:
|
|
126
126
|
name: zeebe-client
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- - "
|
129
|
+
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
131
|
+
version: 0.14.0
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
|
-
- - "
|
136
|
+
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
138
|
+
version: 0.14.0
|
139
139
|
description: Zeebe BPMN testing using RSpec
|
140
140
|
email:
|
141
141
|
- engineering@ezcater.com
|
@@ -148,10 +148,15 @@ files:
|
|
148
148
|
- Gemfile
|
149
149
|
- LICENSE.txt
|
150
150
|
- README.md
|
151
|
+
- docker-compose.simple-monitor.yml
|
151
152
|
- docker-compose.yml
|
152
153
|
- lib/zeebe_bpmn_rspec.rb
|
153
154
|
- lib/zeebe_bpmn_rspec/activated_job.rb
|
155
|
+
- lib/zeebe_bpmn_rspec/deprecate_workflow_alias.rb
|
154
156
|
- lib/zeebe_bpmn_rspec/helpers.rb
|
157
|
+
- lib/zeebe_bpmn_rspec/matchers/have_activated.rb
|
158
|
+
- lib/zeebe_bpmn_rspec/matchers/have_headers.rb
|
159
|
+
- lib/zeebe_bpmn_rspec/matchers/have_variables.rb
|
155
160
|
- lib/zeebe_bpmn_rspec/version.rb
|
156
161
|
- zeebe_bpmn_rspec.gemspec
|
157
162
|
homepage: https://github.com/ezcater/zeebe_bpmn_rspec
|
@@ -167,14 +172,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
167
172
|
requirements:
|
168
173
|
- - ">="
|
169
174
|
- !ruby/object:Gem::Version
|
170
|
-
version: '
|
175
|
+
version: '2.6'
|
171
176
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
177
|
requirements:
|
173
178
|
- - ">="
|
174
179
|
- !ruby/object:Gem::Version
|
175
180
|
version: '0'
|
176
181
|
requirements: []
|
177
|
-
rubygems_version: 3.
|
182
|
+
rubygems_version: 3.1.4
|
178
183
|
signing_key:
|
179
184
|
specification_version: 4
|
180
185
|
summary: Zeebe BPMN testing using RSpec
|