zeebe_bpmn_rspec 0.2.0 → 1.0.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: dbc8b0a3a6bf05f4ef29f2a5285b452afa1e733f2e166a521ba28e48dc2f94d1
4
+ data.tar.gz: 5ef538eea22fce15ba4356ea06204891b69ec51170706cc804d005f1639107f6
5
5
  SHA512:
6
- metadata.gz: 978a61f885179d519ede6340a283b93f9c36e1d712c1279629500732afe01a9f9ac7483a484c17d99356bcebb0258fb04f65771492a6d2b6774cd9be64454f1b
7
- data.tar.gz: 6f235e5995f75fd04b7996708bb8a23d81cbb1b7bf1ecd8ebea46a5fba78fa1e5c60f8ab1e305e263d0e16e7ac2005dad78dfdf5e684528ff3cdf3343a2f9c2e
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
- ### Deploy Workflow
42
+ The gem also defines [Custom Matchers](#custom-matchers).
43
43
 
44
- The `deploy_workflow` method requires a path to a BPMN file and deploys it to Zeebe. There is no support for
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) { deploy_workflow(filepath) }
50
+ before(:all) { deploy_process(filepath) }
49
51
  ```
50
52
 
51
- A custom name can also be specified for the workflow:
53
+ A custom name can also be specified for the process:
52
54
 
53
55
  ```ruby
54
- before(:all) { deploy_workflow(filepath, "custom_name") }
56
+ before(:all) { deploy_process(filepath, "custom_name") }
55
57
  ```
56
58
 
57
- ### With Workflow Instance
59
+ ### With Process Instance
58
60
 
59
- The `with_workflow_instance` method is used to create an instance for the specified workflow
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
- with_workflow_instance("file_basename") do
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 workflow by calling `activate_job` (previously `process_job`).
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 workflow
131
- project_job("my_job").
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
- ### Workflow Complete
201
+ ### Process Complete
190
202
 
191
- The `workflow_complete!` method can be used to assert that the current workflow is complete at the end of a
192
- test. This is implemented by cancelling the workflow and checking for an error that it is already
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
- with_workflow_instance("file_basename") do
208
+ with_process_instance("file_basename") do
197
209
  ...
198
210
 
199
- workflow_complete!
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 workflow at a time.
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.6.6
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:0.23.4
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
@@ -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, :workflow_instance_key
11
+ attr_reader :job, :type
12
12
 
13
- def initialize(job, type:, workflow_instance_key:, client:, context:)
13
+ def initialize(job, type:, process_instance_key:, client:, context:, validate:) # rubocop:disable Metrics/ParameterLists
14
14
  @job = job
15
15
  @type = type
16
- @workflow_instance_key = workflow_instance_key
16
+ @process_instance_key = process_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
+ 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
- def deploy_workflow(path, name = nil)
10
- _zeebe_client.deploy_workflow(DeployWorkflowRequest.new(
11
- workflows: [WorkflowRequestObject.new(
12
- name: (name && "#{name}.bpmn") || File.basename(path),
13
- type: WorkflowRequestObject::ResourceType::FILE,
14
- definition: File.read(path)
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 workflow: #{e}"
19
+ raise "Failed to deploy precess: #{e}"
19
20
  end
21
+ deprecate_workflow_alias :deploy_workflow, :deploy_process
20
22
 
21
- def with_workflow_instance(name, variables = {})
23
+ def with_process_instance(name, variables = {})
22
24
  system_error = nil
23
- workflow = _zeebe_client.create_workflow_instance(CreateWorkflowInstanceRequest.new(
24
- bpmnProcessId: name,
25
- version: -1, # always latest
26
- variables: variables.to_json
27
- ))
28
- @__workflow_instance_key = workflow.workflowInstanceKey
29
- yield(workflow.workflowInstanceKey)
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 workflow&.workflowInstanceKey
37
+ if process&.processInstanceKey
36
38
  begin
37
- _zeebe_client.cancel_workflow_instance(CancelWorkflowInstanceRequest.new(
38
- workflowInstanceKey: workflow.workflowInstanceKey
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 workflow_complete!
52
+ def process_complete!(wait_seconds: 0.25)
50
53
  error = nil
51
- sleep 0.25 # TODO: configurable?
54
+ sleep(wait_seconds)
52
55
  begin
53
- _zeebe_client.cancel_workflow_instance(CancelWorkflowInstanceRequest.new(
54
- workflowInstanceKey: workflow_instance_key
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 workflow instance #{workflow_instance_key} to be complete" if error.nil?
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 workflow_instance_key
64
- @__workflow_instance_key
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
- stream = _zeebe_client.activate_jobs(ActivateJobsRequest.new(
69
- type: type,
70
- worker: "#{type}-#{SecureRandom.hex}",
71
- maxJobsToActivate: 1,
72
- timeout: 5000, # TODO: configure
73
- requestTimeout: 5000
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
- workflow_instance_key: workflow_instance_key,
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
- # TODO: deprecate process_job
96
+ deprecate process_job: :activate_job
90
97
 
91
- def activate_jobs(type, max_jobs: nil)
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: 5000, # TODO: configure
97
- requestTimeout: 5000,
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
- workflow_instance_key: workflow_instance_key,
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: 5000,
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
- @__workflow_instance_key = nil
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ZeebeBpmnRspec
4
- VERSION = "0.2.0"
4
+ VERSION = "1.0.0"
5
5
  end
@@ -41,7 +41,9 @@ Gem::Specification.new do |spec|
41
41
  spec.executables = []
42
42
  spec.require_paths = ["lib"]
43
43
 
44
- spec.add_development_dependency "bundler", "~> 1.12"
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.2.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: 2020-07-29 00:00:00.000000000 Z
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.12'
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.12'
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: '0'
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: '0'
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: '0'
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.0.3
182
+ rubygems_version: 3.1.4
178
183
  signing_key:
179
184
  specification_version: 4
180
185
  summary: Zeebe BPMN testing using RSpec