busybee 0.1.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 +71 -7
- data/README.md +70 -42
- data/docs/client/quick_start.md +279 -0
- data/docs/client.md +825 -0
- data/docs/configuration.md +550 -0
- data/docs/grpc.md +50 -25
- data/docs/testing.md +118 -28
- data/docs/workers.md +982 -0
- data/exe/busybee +6 -0
- data/lib/busybee/cli.rb +173 -0
- data/lib/busybee/client/error_handling.rb +37 -0
- data/lib/busybee/client/job_operations.rb +236 -0
- data/lib/busybee/client/message_operations.rb +84 -0
- data/lib/busybee/client/process_operations.rb +108 -0
- data/lib/busybee/client/variable_operations.rb +64 -0
- data/lib/busybee/client.rb +87 -0
- data/lib/busybee/configure.rb +290 -0
- data/lib/busybee/credentials/camunda_cloud.rb +58 -0
- data/lib/busybee/credentials/insecure.rb +24 -0
- data/lib/busybee/credentials/oauth.rb +157 -0
- data/lib/busybee/credentials/tls.rb +43 -0
- data/lib/busybee/credentials.rb +200 -0
- data/lib/busybee/defaults.rb +20 -0
- data/lib/busybee/error.rb +50 -0
- data/lib/busybee/grpc/error.rb +60 -0
- data/lib/busybee/grpc.rb +2 -2
- data/lib/busybee/job.rb +219 -0
- data/lib/busybee/job_stream.rb +85 -0
- data/lib/busybee/logging.rb +61 -0
- data/lib/busybee/railtie.rb +113 -0
- data/lib/busybee/runner/hybrid.rb +64 -0
- data/lib/busybee/runner/multi.rb +101 -0
- data/lib/busybee/runner/polling.rb +54 -0
- data/lib/busybee/runner/streaming.rb +159 -0
- data/lib/busybee/runner.rb +97 -0
- data/lib/busybee/runtime_config.rb +184 -0
- data/lib/busybee/serialization.rb +100 -0
- data/lib/busybee/testing/activated_job.rb +33 -8
- data/lib/busybee/testing/helpers/execution.rb +139 -0
- data/lib/busybee/testing/helpers/support.rb +78 -0
- data/lib/busybee/testing/helpers.rb +56 -66
- data/lib/busybee/testing/matchers/complete_job.rb +55 -0
- data/lib/busybee/testing/matchers/fail_job.rb +75 -0
- data/lib/busybee/testing/matchers/have_activated.rb +1 -1
- data/lib/busybee/testing/matchers/have_available_jobs.rb +44 -0
- data/lib/busybee/testing/matchers/throw_bpmn_error_on.rb +72 -0
- data/lib/busybee/testing.rb +5 -33
- data/lib/busybee/version.rb +1 -1
- data/lib/busybee/worker/configuration.rb +287 -0
- data/lib/busybee/worker/dsl.rb +187 -0
- data/lib/busybee/worker/shutdown.rb +27 -0
- data/lib/busybee/worker.rb +130 -0
- data/lib/busybee.rb +134 -2
- metadata +80 -3
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "active_support"
|
|
4
|
+
require "active_support/duration"
|
|
4
5
|
require "base64"
|
|
5
|
-
require "
|
|
6
|
+
require "securerandom"
|
|
6
7
|
require "busybee/grpc"
|
|
7
|
-
|
|
8
|
+
require "busybee/serialization"
|
|
9
|
+
require "busybee/testing/activated_job"
|
|
10
|
+
require "busybee/testing/helpers/support"
|
|
11
|
+
require "busybee/testing/helpers/execution"
|
|
8
12
|
|
|
9
13
|
module Busybee
|
|
10
14
|
module Testing
|
|
@@ -13,6 +17,9 @@ module Busybee
|
|
|
13
17
|
|
|
14
18
|
# RSpec helper methods for testing BPMN workflows against Zeebe.
|
|
15
19
|
module Helpers
|
|
20
|
+
extend Support
|
|
21
|
+
include Execution
|
|
22
|
+
|
|
16
23
|
# Deploy a BPMN process file to Zeebe.
|
|
17
24
|
#
|
|
18
25
|
# By default, deploys the BPMN file as-is using its original process ID.
|
|
@@ -40,11 +47,11 @@ module Busybee
|
|
|
40
47
|
# result[:process_id] #=> "my-test-process"
|
|
41
48
|
def deploy_process(path, uniquify: nil)
|
|
42
49
|
if uniquify
|
|
43
|
-
process_id = uniquify == true ? unique_process_id : uniquify
|
|
44
|
-
bpmn_content = bpmn_with_unique_id(path, process_id)
|
|
50
|
+
process_id = uniquify == true ? Busybee::Testing::Helpers.unique_process_id : uniquify
|
|
51
|
+
bpmn_content = Busybee::Testing::Helpers.bpmn_with_unique_id(path, process_id)
|
|
45
52
|
else
|
|
46
53
|
bpmn_content = File.read(path)
|
|
47
|
-
process_id = extract_process_id(bpmn_content)
|
|
54
|
+
process_id = Busybee::Testing::Helpers.extract_process_id(bpmn_content)
|
|
48
55
|
end
|
|
49
56
|
|
|
50
57
|
resource = Busybee::GRPC::Resource.new(
|
|
@@ -73,7 +80,7 @@ module Busybee
|
|
|
73
80
|
request = Busybee::GRPC::CreateProcessInstanceRequest.new(
|
|
74
81
|
bpmnProcessId: process_name,
|
|
75
82
|
version: -1,
|
|
76
|
-
variables:
|
|
83
|
+
variables: Busybee::Serialization.to_json(variables)
|
|
77
84
|
)
|
|
78
85
|
|
|
79
86
|
response = grpc_client.create_process_instance(request)
|
|
@@ -82,7 +89,7 @@ module Busybee
|
|
|
82
89
|
yield @current_process_instance_key
|
|
83
90
|
ensure
|
|
84
91
|
if @current_process_instance_key
|
|
85
|
-
cancel_process_instance(@current_process_instance_key)
|
|
92
|
+
Busybee::Testing::Helpers.cancel_process_instance(@current_process_instance_key)
|
|
86
93
|
@last_process_instance_key = @current_process_instance_key
|
|
87
94
|
@current_process_instance_key = nil
|
|
88
95
|
end
|
|
@@ -103,6 +110,31 @@ module Busybee
|
|
|
103
110
|
@last_process_instance_key
|
|
104
111
|
end
|
|
105
112
|
|
|
113
|
+
# Activate a job, yield it, and complete it on block exit.
|
|
114
|
+
# Must be called within a with_process_instance block.
|
|
115
|
+
#
|
|
116
|
+
# @param job_type [String] job type to activate
|
|
117
|
+
# @yield [ActivatedJob] the activated job
|
|
118
|
+
def with_activated_job_instance(job_type)
|
|
119
|
+
job = activate_job(job_type)
|
|
120
|
+
@current_job_key = job.key
|
|
121
|
+
yield job
|
|
122
|
+
ensure
|
|
123
|
+
if @current_job_key
|
|
124
|
+
begin
|
|
125
|
+
request = Busybee::GRPC::CompleteJobRequest.new(
|
|
126
|
+
jobKey: @current_job_key,
|
|
127
|
+
variables: "{}"
|
|
128
|
+
)
|
|
129
|
+
grpc_client.complete_job(request)
|
|
130
|
+
rescue ::GRPC::BadStatus
|
|
131
|
+
# Job may have already been completed/failed in the test block - ignore
|
|
132
|
+
ensure
|
|
133
|
+
@current_job_key = nil
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
106
138
|
# Checks if Zeebe is available and responsive.
|
|
107
139
|
#
|
|
108
140
|
# This method attempts to connect to Zeebe and call the topology endpoint
|
|
@@ -114,17 +146,18 @@ module Busybee
|
|
|
114
146
|
request = Busybee::GRPC::TopologyRequest.new
|
|
115
147
|
grpc_client.topology(request, deadline: Time.now + timeout)
|
|
116
148
|
true
|
|
117
|
-
rescue GRPC::Unavailable, GRPC::DeadlineExceeded, GRPC::Core::CallError, GRPC::Unauthenticated
|
|
149
|
+
rescue ::GRPC::Unavailable, ::GRPC::DeadlineExceeded, ::GRPC::Core::CallError, ::GRPC::Unauthenticated
|
|
118
150
|
false
|
|
119
151
|
end
|
|
120
152
|
|
|
121
153
|
# Activate a single job of the given type.
|
|
122
154
|
#
|
|
123
155
|
# @param type [String] job type
|
|
156
|
+
# @param timeout [Integer, nil] request timeout in milliseconds (defaults to Busybee.default_job_request_timeout)
|
|
124
157
|
# @return [ActivatedJob]
|
|
125
158
|
# @raise [NoJobAvailable] if no job is available
|
|
126
|
-
def activate_job(type)
|
|
127
|
-
jobs = activate_jobs_raw(type, max_jobs: 1)
|
|
159
|
+
def activate_job(type, timeout: nil)
|
|
160
|
+
jobs = Busybee::Testing::Helpers.activate_jobs_raw(type, max_jobs: 1, timeout: timeout)
|
|
128
161
|
raise NoJobAvailable, "No job of type '#{type}' available" if jobs.empty?
|
|
129
162
|
|
|
130
163
|
ActivatedJob.new(jobs.first, client: grpc_client)
|
|
@@ -134,10 +167,11 @@ module Busybee
|
|
|
134
167
|
#
|
|
135
168
|
# @param type [String] job type
|
|
136
169
|
# @param max_jobs [Integer] maximum number of jobs to activate
|
|
170
|
+
# @param timeout [Integer, nil] request timeout in milliseconds (defaults to Busybee.default_job_request_timeout)
|
|
137
171
|
# @return [Enumerator<ActivatedJob>]
|
|
138
|
-
def activate_jobs(type, max_jobs:)
|
|
172
|
+
def activate_jobs(type, max_jobs:, timeout: nil)
|
|
139
173
|
Enumerator.new do |yielder|
|
|
140
|
-
activate_jobs_raw(type, max_jobs: max_jobs).each do |raw_job|
|
|
174
|
+
Busybee::Testing::Helpers.activate_jobs_raw(type, max_jobs: max_jobs, timeout: timeout).each do |raw_job|
|
|
141
175
|
yielder << ActivatedJob.new(raw_job, client: grpc_client)
|
|
142
176
|
end
|
|
143
177
|
end
|
|
@@ -153,7 +187,7 @@ module Busybee
|
|
|
153
187
|
request = Busybee::GRPC::PublishMessageRequest.new(
|
|
154
188
|
name: name,
|
|
155
189
|
correlationKey: correlation_key,
|
|
156
|
-
variables:
|
|
190
|
+
variables: Busybee::Serialization.to_json(variables),
|
|
157
191
|
timeToLive: ttl_ms
|
|
158
192
|
)
|
|
159
193
|
grpc_client.publish_message(request)
|
|
@@ -167,7 +201,7 @@ module Busybee
|
|
|
167
201
|
def set_variables(scope_key, variables, local: true)
|
|
168
202
|
request = Busybee::GRPC::SetVariablesRequest.new(
|
|
169
203
|
elementInstanceKey: scope_key,
|
|
170
|
-
variables:
|
|
204
|
+
variables: Busybee::Serialization.to_json(variables),
|
|
171
205
|
local: local
|
|
172
206
|
)
|
|
173
207
|
grpc_client.set_variables(request)
|
|
@@ -193,58 +227,14 @@ module Busybee
|
|
|
193
227
|
end
|
|
194
228
|
end
|
|
195
229
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def extract_process_id(bpmn_content)
|
|
203
|
-
match = bpmn_content.match(/<bpmn:process id="([^"]+)"/)
|
|
204
|
-
match ? match[1] : nil
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
def bpmn_with_unique_id(bpmn_path, process_id)
|
|
208
|
-
bpmn_content = File.read(bpmn_path)
|
|
209
|
-
bpmn_content
|
|
210
|
-
.gsub(/(<bpmn:process id=")[^"]+/, "\\1#{process_id}")
|
|
211
|
-
# Possessive quantifiers (++, *+) prevent polynomial backtracking
|
|
212
|
-
.gsub(/(<bpmndi:BPMNPlane\s++[^>]*+bpmnElement=")[^"]++/, "\\1#{process_id}")
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def cancel_process_instance(key)
|
|
216
|
-
request = Busybee::GRPC::CancelProcessInstanceRequest.new(
|
|
217
|
-
processInstanceKey: key
|
|
218
|
-
)
|
|
219
|
-
grpc_client.cancel_process_instance(request)
|
|
220
|
-
true
|
|
221
|
-
rescue ::GRPC::NotFound
|
|
222
|
-
# Process already completed, ignore
|
|
223
|
-
false
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
def activate_jobs_raw(type, max_jobs:)
|
|
227
|
-
worker = "#{type}-#{SecureRandom.hex(4)}"
|
|
228
|
-
request = Busybee::GRPC::ActivateJobsRequest.new(
|
|
229
|
-
type: type,
|
|
230
|
-
worker: worker,
|
|
231
|
-
timeout: 30_000,
|
|
232
|
-
maxJobsToActivate: max_jobs,
|
|
233
|
-
requestTimeout: Busybee::Testing.activate_request_timeout
|
|
234
|
-
)
|
|
235
|
-
|
|
236
|
-
jobs = []
|
|
237
|
-
grpc_client.activate_jobs(request).each do |response|
|
|
238
|
-
jobs.concat(response.jobs.to_a)
|
|
239
|
-
end
|
|
240
|
-
jobs
|
|
241
|
-
end
|
|
242
|
-
|
|
230
|
+
# Returns a GRPC client stub for direct Zeebe access.
|
|
231
|
+
# Uses Busybee.credential_type if set, autodetects from env vars otherwise.
|
|
232
|
+
#
|
|
233
|
+
# This is a public instance method that delegates to the module-level implementation.
|
|
234
|
+
#
|
|
235
|
+
# @return [Busybee::GRPC::Gateway::Stub]
|
|
243
236
|
def grpc_client
|
|
244
|
-
|
|
245
|
-
Busybee::Testing.address,
|
|
246
|
-
:this_channel_is_insecure
|
|
247
|
-
)
|
|
237
|
+
Busybee::Testing::Helpers.grpc_client
|
|
248
238
|
end
|
|
249
239
|
end
|
|
250
240
|
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rspec/expectations"
|
|
4
|
+
|
|
5
|
+
# Asserts that a worker completes the job successfully.
|
|
6
|
+
#
|
|
7
|
+
# Checks that the job ends in +:complete+ status. Optionally checks
|
|
8
|
+
# the return value of +perform+ for expected variables via +with_vars+.
|
|
9
|
+
#
|
|
10
|
+
# @example Basic usage
|
|
11
|
+
# job = build_test_job(variables: { order_id: 1 })
|
|
12
|
+
# expect(MyWorker).to complete_job(job)
|
|
13
|
+
#
|
|
14
|
+
# @example With expected return variables
|
|
15
|
+
# expect(MyWorker).to complete_job(job).with_vars(status: "done")
|
|
16
|
+
#
|
|
17
|
+
RSpec::Matchers.define :complete_job do |job|
|
|
18
|
+
match do |worker_class|
|
|
19
|
+
@result = execute_worker(worker_class, job: job)
|
|
20
|
+
return false unless job.complete?
|
|
21
|
+
|
|
22
|
+
if @expected_vars
|
|
23
|
+
if @result.is_a?(Hash)
|
|
24
|
+
values_match?(@expected_vars, @result)
|
|
25
|
+
else
|
|
26
|
+
@expected_vars == {}
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
rescue StandardError => e
|
|
32
|
+
@raised_error = e
|
|
33
|
+
false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
chain :with_vars do |expected|
|
|
37
|
+
@expected_vars = expected
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
chain :with_no_vars do
|
|
41
|
+
@expected_vars = {}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
failure_message do
|
|
45
|
+
if @raised_error
|
|
46
|
+
"expected #{actual} to complete the job, but it raised " \
|
|
47
|
+
"#{@raised_error.class}: #{@raised_error.message}"
|
|
48
|
+
elsif !job.complete?
|
|
49
|
+
"expected job to be complete, but was #{job.status}"
|
|
50
|
+
else
|
|
51
|
+
"expected result to match #{@expected_vars.inspect}, " \
|
|
52
|
+
"got #{@result.inspect}"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rspec/expectations"
|
|
4
|
+
|
|
5
|
+
# Asserts that a worker fails the job with an optional error match.
|
|
6
|
+
#
|
|
7
|
+
# Accepts the same argument forms as RSpec's +raise_error+:
|
|
8
|
+
# with_error(ErrorClass)
|
|
9
|
+
# with_error(ErrorClass, "exact message")
|
|
10
|
+
# with_error(ErrorClass, /message pattern/)
|
|
11
|
+
# with_error("exact message")
|
|
12
|
+
# with_error(/message pattern/)
|
|
13
|
+
#
|
|
14
|
+
# @example Basic usage
|
|
15
|
+
# job = build_test_job(variables: { order_id: 999 })
|
|
16
|
+
# expect(MyWorker).to fail_job(job)
|
|
17
|
+
#
|
|
18
|
+
# @example With error class
|
|
19
|
+
# expect(MyWorker).to fail_job(job).with_error(ActiveRecord::RecordNotFound)
|
|
20
|
+
#
|
|
21
|
+
# @example With error class and message
|
|
22
|
+
# expect(MyWorker).to fail_job(job).with_error(ArgumentError, /invalid/)
|
|
23
|
+
#
|
|
24
|
+
RSpec::Matchers.define :fail_job do |job|
|
|
25
|
+
match do |worker_class|
|
|
26
|
+
execute_worker(worker_class, job: job)
|
|
27
|
+
@no_error = true
|
|
28
|
+
false
|
|
29
|
+
rescue StandardError => e
|
|
30
|
+
@raised_error = e
|
|
31
|
+
job.failed? && error_matches?(e)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
chain :with_error do |expected_error_or_message, expected_message = nil|
|
|
35
|
+
case expected_error_or_message
|
|
36
|
+
when String, Regexp
|
|
37
|
+
@expected_error = StandardError
|
|
38
|
+
@expected_message = expected_error_or_message
|
|
39
|
+
else
|
|
40
|
+
@expected_error = expected_error_or_message
|
|
41
|
+
@expected_message = expected_message
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def error_matches?(error)
|
|
46
|
+
return true unless @expected_error
|
|
47
|
+
|
|
48
|
+
class_matches = @expected_error === error # rubocop:disable Style/CaseEquality
|
|
49
|
+
return false unless class_matches
|
|
50
|
+
return true unless @expected_message
|
|
51
|
+
|
|
52
|
+
case @expected_message
|
|
53
|
+
when Regexp then error.message.match?(@expected_message)
|
|
54
|
+
else error.message == @expected_message.to_s
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
failure_message do
|
|
59
|
+
if @no_error
|
|
60
|
+
"expected #{actual} to fail the job, but it completed successfully"
|
|
61
|
+
elsif !job.failed?
|
|
62
|
+
"expected job to be failed, but was #{job.status}"
|
|
63
|
+
else
|
|
64
|
+
"expected error matching #{expected_description}, " \
|
|
65
|
+
"got #{@raised_error.class}: #{@raised_error.message}"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def expected_description
|
|
70
|
+
parts = []
|
|
71
|
+
parts << @expected_error.inspect if @expected_error
|
|
72
|
+
parts << @expected_message.inspect if @expected_message
|
|
73
|
+
parts.join(" with message ")
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rspec/expectations"
|
|
4
|
+
|
|
5
|
+
# Matcher to check if jobs are available for activation.
|
|
6
|
+
#
|
|
7
|
+
# This matcher is designed to work with blocks that call `activate_job` or similar methods
|
|
8
|
+
# that raise `Busybee::Testing::NoJobAvailable` when no jobs are found.
|
|
9
|
+
#
|
|
10
|
+
# @example Check that jobs are available
|
|
11
|
+
# expect { activate_job("process-order") }.to have_available_jobs
|
|
12
|
+
#
|
|
13
|
+
# @example Check that NO jobs are available (most common usage)
|
|
14
|
+
# expect { activate_job("process-order") }.not_to have_available_jobs
|
|
15
|
+
#
|
|
16
|
+
RSpec::Matchers.define :have_available_jobs do
|
|
17
|
+
supports_block_expectations
|
|
18
|
+
|
|
19
|
+
match do |block|
|
|
20
|
+
block.call
|
|
21
|
+
@job_found = true
|
|
22
|
+
true
|
|
23
|
+
rescue Busybee::Testing::NoJobAvailable
|
|
24
|
+
@job_found = false
|
|
25
|
+
false
|
|
26
|
+
rescue StandardError => e
|
|
27
|
+
@unexpected_error = e
|
|
28
|
+
false
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
failure_message do
|
|
32
|
+
if @unexpected_error
|
|
33
|
+
"expected jobs to be available, but got #{@unexpected_error.class}: #{@unexpected_error.message}"
|
|
34
|
+
else
|
|
35
|
+
"expected jobs to be available, but no jobs were found (Busybee::Testing::NoJobAvailable raised)"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
failure_message_when_negated do
|
|
40
|
+
"expected no jobs to be available, but a job was activated"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
RSpec::Matchers.alias_matcher :have_an_available_job, :have_available_jobs
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rspec/expectations"
|
|
4
|
+
|
|
5
|
+
# Asserts that a worker throws a BPMN error on the job.
|
|
6
|
+
#
|
|
7
|
+
# Captures the error code and message passed to the stub client's
|
|
8
|
+
# +throw_bpmn_error+ call for optional verification via +with_code+.
|
|
9
|
+
#
|
|
10
|
+
# @example Basic usage
|
|
11
|
+
# job = build_test_job(variables: { order_id: 999 })
|
|
12
|
+
# expect(MyWorker).to throw_bpmn_error_on(job)
|
|
13
|
+
#
|
|
14
|
+
# @example With error code
|
|
15
|
+
# expect(MyWorker).to throw_bpmn_error_on(job).with_code(:not_found)
|
|
16
|
+
#
|
|
17
|
+
# @example With error code and message
|
|
18
|
+
# expect(MyWorker).to throw_bpmn_error_on(job).with_code(:not_found, message: /missing/)
|
|
19
|
+
#
|
|
20
|
+
RSpec::Matchers.define :throw_bpmn_error_on do |job|
|
|
21
|
+
match do |worker_class|
|
|
22
|
+
client = job.instance_variable_get(:@client)
|
|
23
|
+
allow(client).to receive(:throw_bpmn_error) do |_key, code, message:|
|
|
24
|
+
@actual_code = code
|
|
25
|
+
@actual_message = message
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
execute_worker(worker_class, job: job)
|
|
29
|
+
return false unless job.error?
|
|
30
|
+
|
|
31
|
+
code_matches? && message_matches?
|
|
32
|
+
rescue StandardError => e
|
|
33
|
+
@raised_error = e
|
|
34
|
+
false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
chain :with_code do |expected_code, opts = {}|
|
|
38
|
+
@expected_code = case expected_code
|
|
39
|
+
when Symbol then expected_code.to_s.upcase
|
|
40
|
+
when Class then expected_code.name.gsub("::", "_").underscore.upcase
|
|
41
|
+
else expected_code
|
|
42
|
+
end
|
|
43
|
+
@expected_message = opts[:message]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def code_matches?
|
|
47
|
+
return true unless @expected_code
|
|
48
|
+
|
|
49
|
+
values_match?(@expected_code, @actual_code)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def message_matches?
|
|
53
|
+
return true unless @expected_message
|
|
54
|
+
|
|
55
|
+
values_match?(@expected_message, @actual_message)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
failure_message do
|
|
59
|
+
if @raised_error
|
|
60
|
+
"expected #{actual} to throw a BPMN error, but it raised " \
|
|
61
|
+
"#{@raised_error.class}: #{@raised_error.message}"
|
|
62
|
+
elsif !job.error?
|
|
63
|
+
"expected job to be error, but was #{job.status}"
|
|
64
|
+
elsif @expected_code && !code_matches?
|
|
65
|
+
"expected BPMN error code #{@expected_code.inspect}, " \
|
|
66
|
+
"got #{@actual_code.inspect}"
|
|
67
|
+
else
|
|
68
|
+
"expected BPMN error message #{@expected_message.inspect}, " \
|
|
69
|
+
"got #{@actual_message.inspect}"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/busybee/testing.rb
CHANGED
|
@@ -3,40 +3,8 @@
|
|
|
3
3
|
require "busybee/grpc"
|
|
4
4
|
|
|
5
5
|
module Busybee
|
|
6
|
-
# Testing support for BPMN workflows with RSpec.
|
|
7
|
-
#
|
|
8
|
-
# @example Configuration
|
|
9
|
-
# Busybee::Testing.configure do |config|
|
|
10
|
-
# config.address = "localhost:26500"
|
|
11
|
-
# config.username = "demo"
|
|
12
|
-
# config.password = "demo"
|
|
13
|
-
# config.activate_request_timeout = 2000
|
|
14
|
-
# end
|
|
15
|
-
#
|
|
6
|
+
# Testing support for BPMN workflows and workers with RSpec.
|
|
16
7
|
module Testing
|
|
17
|
-
class << self
|
|
18
|
-
attr_writer :address, :username, :password, :activate_request_timeout
|
|
19
|
-
|
|
20
|
-
def configure
|
|
21
|
-
yield self
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def address
|
|
25
|
-
@address || ENV["ZEEBE_ADDRESS"] || "localhost:26500"
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def username
|
|
29
|
-
@username || ENV["ZEEBE_USERNAME"] || "demo"
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def password
|
|
33
|
-
@password || ENV["ZEEBE_PASSWORD"] || "demo"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def activate_request_timeout
|
|
37
|
-
@activate_request_timeout || 1000
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
8
|
end
|
|
41
9
|
end
|
|
42
10
|
|
|
@@ -47,6 +15,10 @@ if defined?(RSpec)
|
|
|
47
15
|
require "busybee/testing/matchers/have_received_variables"
|
|
48
16
|
require "busybee/testing/matchers/have_received_headers"
|
|
49
17
|
require "busybee/testing/matchers/have_activated"
|
|
18
|
+
require "busybee/testing/matchers/have_available_jobs"
|
|
19
|
+
require "busybee/testing/matchers/fail_job"
|
|
20
|
+
require "busybee/testing/matchers/complete_job"
|
|
21
|
+
require "busybee/testing/matchers/throw_bpmn_error_on"
|
|
50
22
|
|
|
51
23
|
RSpec.configure do |config|
|
|
52
24
|
config.include Busybee::Testing::Helpers
|
data/lib/busybee/version.rb
CHANGED