geneva_drive 0.5.0 → 0.7.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 +14 -1
- data/MANUAL.md +449 -11
- data/README.md +5 -1
- data/lib/generators/geneva_drive/install/install_generator.rb +20 -0
- data/lib/generators/geneva_drive/install/templates/add_metadata_to_workflows.rb +17 -0
- data/lib/generators/geneva_drive/install/templates/add_resumable_step_support.rb +29 -0
- data/lib/generators/geneva_drive/install/templates/add_signals_support.rb +94 -0
- data/lib/generators/geneva_drive/install/templates/add_started_at_index_to_step_executions.rb +48 -0
- data/lib/generators/geneva_drive/install/templates/create_workflows_migration.rb +11 -0
- data/lib/generators/geneva_drive/install/templates/initializer.rb.tt +8 -0
- data/lib/geneva_drive/combined_exception_policy.rb +1 -1
- data/lib/geneva_drive/exception_policy.rb +36 -10
- data/lib/geneva_drive/executor.rb +352 -26
- data/lib/geneva_drive/flow_control.rb +87 -7
- data/lib/geneva_drive/iterable_step.rb +199 -0
- data/lib/geneva_drive/job_options.rb +70 -0
- data/lib/geneva_drive/jobs/housekeeping_job.rb +120 -7
- data/lib/geneva_drive/resumable_step_definition.rb +97 -0
- data/lib/geneva_drive/signal.rb +243 -0
- data/lib/geneva_drive/signal_matcher.rb +60 -0
- data/lib/geneva_drive/step_definition.rb +96 -2
- data/lib/geneva_drive/step_execution.rb +141 -2
- data/lib/geneva_drive/test_helpers.rb +212 -6
- data/lib/geneva_drive/version.rb +1 -1
- data/lib/geneva_drive/workflow/metadata_accessor.rb +85 -0
- data/lib/geneva_drive/workflow.rb +559 -43
- data/lib/geneva_drive.rb +37 -0
- data/test/dsl/signal_step_definition_test.rb +132 -0
- data/test/dsl/step_definition_test.rb +70 -0
- data/test/jobs/housekeeping_job_test.rb +119 -0
- data/test/jobs/housekeeping_signals_test.rb +198 -0
- data/test/jobs/perform_step_job_test.rb +25 -2
- data/test/migration_helpers_test.rb +1 -1
- data/test/test_helper.rb +4 -0
- data/test/test_helper_test.rb +281 -0
- data/test/workflow/cursor_size_limit_test.rb +75 -0
- data/test/workflow/instrumentation_test.rb +28 -0
- data/test/workflow/resumable_step_integration_test.rb +341 -0
- data/test/workflow/resumable_step_test.rb +615 -0
- data/test/workflow/resumable_without_migration_test.rb +103 -0
- data/test/workflow/signal_consumption_test.rb +397 -0
- data/test/workflow/signal_delivery_test.rb +255 -0
- data/test/workflow/signal_durability_test.rb +164 -0
- data/test/workflow/signal_rendezvous_test.rb +581 -0
- data/test/workflow/signals_without_migration_test.rb +97 -0
- data/test/workflow/workflow_test.rb +72 -1
- metadata +25 -15
- data/test/dummy/config/initializers/geneva_drive.rb +0 -44
- data/test/dummy/db/migrate/20260219212321_create_geneva_drive_workflows.rb +0 -74
- data/test/dummy/db/migrate/20260219212322_create_geneva_drive_step_executions.rb +0 -108
- data/test/dummy/db/migrate/20260219212323_add_finished_at_to_geneva_drive_step_executions.rb +0 -25
- data/test/dummy/db/migrate/20260219212324_add_error_class_name_to_geneva_drive_step_executions.rb +0 -7
- data/test/dummy/db/migrate/20260316100007_add_metadata_to_geneva_drive_step_executions.rb +0 -17
- data/test/dummy/db/migrate/20260327000000_allow_null_hero_on_geneva_drive_workflows.rb +0 -66
- data/test/dummy/db/schema.rb +0 -73
- data/test/dummy/log/development.log +0 -202
- data/test/dummy/log/test.log +0 -79471
- data/test/dummy/log/test.log.0 +0 -4
- data/test/dummy/tmp/local_secret.txt +0 -1
data/test/test_helper.rb
CHANGED
|
@@ -54,6 +54,10 @@ class ActiveSupport::TestCase
|
|
|
54
54
|
# same parallel process.
|
|
55
55
|
setup do
|
|
56
56
|
GenevaDrive::StepExecution.reset_metadata_column_cache!
|
|
57
|
+
GenevaDrive::StepExecution.reset_resumable_columns_cache!
|
|
58
|
+
GenevaDrive::StepExecution.reset_signal_columns_cache!
|
|
59
|
+
GenevaDrive::Signal.reset_table_available_cache!
|
|
60
|
+
GenevaDrive::Workflow.reset_metadata_column_cache!
|
|
57
61
|
end
|
|
58
62
|
|
|
59
63
|
# Helper to create a test user
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class TestHelperTest < ActiveSupport::TestCase
|
|
6
|
+
include GenevaDrive::TestHelpers
|
|
7
|
+
|
|
8
|
+
class MultiStepWorkflow < GenevaDrive::Workflow
|
|
9
|
+
step :first_step do
|
|
10
|
+
Thread.current[:first_step_ran] = true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
step :second_step do
|
|
14
|
+
Thread.current[:second_step_ran] = true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
step :third_step do
|
|
18
|
+
Thread.current[:third_step_ran] = true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class ResumableMultiStepWorkflow < GenevaDrive::Workflow
|
|
23
|
+
resumable_step :resumable_first do |iter|
|
|
24
|
+
items = %w[a b c]
|
|
25
|
+
iter.iterate_over(items) do |item|
|
|
26
|
+
Thread.current[:resumable_items] ||= []
|
|
27
|
+
Thread.current[:resumable_items] << item
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
step :after_resumable do
|
|
32
|
+
Thread.current[:after_resumable_ran] = true
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
setup do
|
|
37
|
+
@user = create_user
|
|
38
|
+
reset_thread_tracking!
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
teardown do
|
|
42
|
+
reset_thread_tracking!
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def reset_thread_tracking!
|
|
46
|
+
Thread.current[:first_step_ran] = nil
|
|
47
|
+
Thread.current[:second_step_ran] = nil
|
|
48
|
+
Thread.current[:third_step_ran] = nil
|
|
49
|
+
Thread.current[:resumable_items] = nil
|
|
50
|
+
Thread.current[:after_resumable_ran] = nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# speedrun_current_step tests
|
|
54
|
+
|
|
55
|
+
test "speedrun_current_step only runs the current step, not subsequent steps" do
|
|
56
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
57
|
+
|
|
58
|
+
speedrun_current_step(workflow)
|
|
59
|
+
|
|
60
|
+
assert Thread.current[:first_step_ran], "first step should have run"
|
|
61
|
+
assert_nil Thread.current[:second_step_ran], "second step should NOT have run"
|
|
62
|
+
assert_nil Thread.current[:third_step_ran], "third step should NOT have run"
|
|
63
|
+
|
|
64
|
+
# Workflow should still be ready with next step scheduled
|
|
65
|
+
workflow.reload
|
|
66
|
+
assert_equal "ready", workflow.state
|
|
67
|
+
assert_equal "second_step", workflow.next_step_name
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
test "speedrun_current_step runs resumable step to completion without continuing" do
|
|
71
|
+
workflow = ResumableMultiStepWorkflow.create!(hero: @user)
|
|
72
|
+
|
|
73
|
+
speedrun_current_step(workflow)
|
|
74
|
+
|
|
75
|
+
assert_equal %w[a b c], Thread.current[:resumable_items], "resumable step should complete all items"
|
|
76
|
+
assert_nil Thread.current[:after_resumable_ran], "step after resumable should NOT have run"
|
|
77
|
+
|
|
78
|
+
workflow.reload
|
|
79
|
+
assert_equal "ready", workflow.state
|
|
80
|
+
assert_equal "after_resumable", workflow.next_step_name
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
test "speedrun_current_step returns the step execution" do
|
|
84
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
85
|
+
|
|
86
|
+
result = speedrun_current_step(workflow)
|
|
87
|
+
|
|
88
|
+
assert_instance_of GenevaDrive::StepExecution, result
|
|
89
|
+
assert_equal "first_step", result.step_name
|
|
90
|
+
assert_equal "completed", result.state
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
test "speedrun_current_step returns nil if no current execution" do
|
|
94
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
95
|
+
speedrun_workflow(workflow) # Complete the whole workflow
|
|
96
|
+
|
|
97
|
+
result = speedrun_current_step(workflow)
|
|
98
|
+
|
|
99
|
+
assert_nil result
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# speedrun_workflow tests
|
|
103
|
+
|
|
104
|
+
test "speedrun_workflow runs all steps to completion" do
|
|
105
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
106
|
+
|
|
107
|
+
speedrun_workflow(workflow)
|
|
108
|
+
|
|
109
|
+
assert Thread.current[:first_step_ran]
|
|
110
|
+
assert Thread.current[:second_step_ran]
|
|
111
|
+
assert Thread.current[:third_step_ran]
|
|
112
|
+
assert_equal "finished", workflow.state
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
test "speedrun_workflow handles resumable steps" do
|
|
116
|
+
workflow = ResumableMultiStepWorkflow.create!(hero: @user)
|
|
117
|
+
|
|
118
|
+
speedrun_workflow(workflow)
|
|
119
|
+
|
|
120
|
+
assert_equal %w[a b c], Thread.current[:resumable_items]
|
|
121
|
+
assert Thread.current[:after_resumable_ran]
|
|
122
|
+
assert_equal "finished", workflow.state
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# perform_next_step tests
|
|
126
|
+
|
|
127
|
+
test "perform_next_step executes one step and stops" do
|
|
128
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
129
|
+
|
|
130
|
+
perform_next_step(workflow)
|
|
131
|
+
|
|
132
|
+
assert Thread.current[:first_step_ran]
|
|
133
|
+
assert_nil Thread.current[:second_step_ran]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
test "perform_next_step returns the executed step execution" do
|
|
137
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
138
|
+
|
|
139
|
+
result = perform_next_step(workflow)
|
|
140
|
+
|
|
141
|
+
assert_instance_of GenevaDrive::StepExecution, result
|
|
142
|
+
assert_equal "first_step", result.step_name
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
test "perform_next_step returns nil when no current execution" do
|
|
146
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
147
|
+
speedrun_workflow(workflow)
|
|
148
|
+
|
|
149
|
+
result = perform_next_step(workflow)
|
|
150
|
+
|
|
151
|
+
assert_nil result
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# perform_step_inline tests
|
|
155
|
+
|
|
156
|
+
test "perform_step_inline executes a specific step by name" do
|
|
157
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
158
|
+
|
|
159
|
+
perform_step_inline(workflow, :second_step)
|
|
160
|
+
|
|
161
|
+
assert_nil Thread.current[:first_step_ran], "first step should not run"
|
|
162
|
+
assert Thread.current[:second_step_ran], "second step should run"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
test "perform_step_inline executes current step when no name given" do
|
|
166
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
167
|
+
|
|
168
|
+
perform_step_inline(workflow)
|
|
169
|
+
|
|
170
|
+
assert Thread.current[:first_step_ran]
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
test "perform_step_inline raises ArgumentError for non-existent step" do
|
|
174
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
175
|
+
|
|
176
|
+
error = assert_raises(ArgumentError) do
|
|
177
|
+
perform_step_inline(workflow, :non_existent_step)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
assert_match(/non_existent_step/, error.message)
|
|
181
|
+
assert_match(/not defined/, error.message)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
test "perform_step_inline returns the step execution" do
|
|
185
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
186
|
+
|
|
187
|
+
result = perform_step_inline(workflow, :second_step)
|
|
188
|
+
|
|
189
|
+
assert_instance_of GenevaDrive::StepExecution, result
|
|
190
|
+
assert_equal "second_step", result.step_name
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# assert_step_executed tests
|
|
194
|
+
|
|
195
|
+
test "assert_step_executed passes when step is in expected state" do
|
|
196
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
197
|
+
perform_next_step(workflow)
|
|
198
|
+
|
|
199
|
+
# Should not raise
|
|
200
|
+
assert_step_executed(workflow, :first_step)
|
|
201
|
+
assert_step_executed(workflow, :first_step, state: "completed")
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
test "assert_step_executed fails when step not found" do
|
|
205
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
206
|
+
|
|
207
|
+
error = assert_raises(Minitest::Assertion) do
|
|
208
|
+
assert_step_executed(workflow, :first_step)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
assert_match(/first_step/, error.message)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
test "assert_step_executed fails when step in different state" do
|
|
215
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
216
|
+
perform_next_step(workflow)
|
|
217
|
+
|
|
218
|
+
error = assert_raises(Minitest::Assertion) do
|
|
219
|
+
assert_step_executed(workflow, :first_step, state: "failed")
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
assert_match(/first_step/, error.message)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# assert_workflow_state tests
|
|
226
|
+
|
|
227
|
+
test "assert_workflow_state passes when state matches" do
|
|
228
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
229
|
+
|
|
230
|
+
# Should not raise
|
|
231
|
+
assert_workflow_state(workflow, :ready)
|
|
232
|
+
assert_workflow_state(workflow, "ready")
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
test "assert_workflow_state fails when state differs" do
|
|
236
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
237
|
+
|
|
238
|
+
error = assert_raises(Minitest::Assertion) do
|
|
239
|
+
assert_workflow_state(workflow, :finished)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
assert_match(/finished/, error.message)
|
|
243
|
+
assert_match(/ready/, error.message)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
test "assert_workflow_state works after workflow completes" do
|
|
247
|
+
workflow = MultiStepWorkflow.create!(hero: @user)
|
|
248
|
+
speedrun_workflow(workflow)
|
|
249
|
+
|
|
250
|
+
assert_workflow_state(workflow, :finished)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# assert_cursor tests
|
|
254
|
+
|
|
255
|
+
test "assert_cursor passes when cursor matches" do
|
|
256
|
+
workflow = ResumableMultiStepWorkflow.create!(hero: @user)
|
|
257
|
+
|
|
258
|
+
# Execute the step - it will complete
|
|
259
|
+
speedrun_current_step(workflow)
|
|
260
|
+
|
|
261
|
+
# After completion, we can check the cursor on the last execution
|
|
262
|
+
# Note: For a fully completed step, cursor may be nil or final value
|
|
263
|
+
workflow.reload
|
|
264
|
+
execution = workflow.step_executions.find_by(step_name: "resumable_first")
|
|
265
|
+
assert_not_nil execution
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# assert_step_has_successor tests
|
|
269
|
+
|
|
270
|
+
test "assert_step_has_successor passes when successor exists" do
|
|
271
|
+
workflow = ResumableMultiStepWorkflow.create!(hero: @user)
|
|
272
|
+
|
|
273
|
+
# Execute the resumable step - it will complete without successor in this simple case
|
|
274
|
+
speedrun_current_step(workflow)
|
|
275
|
+
|
|
276
|
+
# Just verify the helper doesn't crash when there's no successor
|
|
277
|
+
workflow.reload
|
|
278
|
+
completed = workflow.step_executions.find_by(step_name: "resumable_first", state: "completed")
|
|
279
|
+
assert completed, "Expected completed execution"
|
|
280
|
+
end
|
|
281
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class CursorSizeLimitTest < ActiveSupport::TestCase
|
|
6
|
+
include GenevaDrive::TestHelpers
|
|
7
|
+
|
|
8
|
+
class PayloadCursorWorkflow < GenevaDrive::Workflow
|
|
9
|
+
resumable_step :process do |iter|
|
|
10
|
+
iter.set!(Thread.current[:cursor_payload])
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
setup do
|
|
15
|
+
@user = create_user
|
|
16
|
+
@original_limit = GenevaDrive.max_cursor_size
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
teardown do
|
|
20
|
+
GenevaDrive.max_cursor_size = @original_limit
|
|
21
|
+
Thread.current[:cursor_payload] = nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
test "defaults to 128 KB" do
|
|
25
|
+
assert_equal 128 * 1024, GenevaDrive.max_cursor_size
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
test "an oversized cursor raises CursorTooLargeError and pauses the workflow" do
|
|
29
|
+
GenevaDrive.max_cursor_size = 1024
|
|
30
|
+
Thread.current[:cursor_payload] = "x" * 2048
|
|
31
|
+
|
|
32
|
+
workflow = PayloadCursorWorkflow.create!(hero: @user)
|
|
33
|
+
|
|
34
|
+
error = assert_raises(GenevaDrive::CursorTooLargeError) { perform_next_step(workflow) }
|
|
35
|
+
assert_match(/max_cursor_size/, error.message)
|
|
36
|
+
|
|
37
|
+
workflow.reload
|
|
38
|
+
assert_equal "paused", workflow.state
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test "a cursor under the limit passes" do
|
|
42
|
+
GenevaDrive.max_cursor_size = 1024
|
|
43
|
+
Thread.current[:cursor_payload] = "x" * 100
|
|
44
|
+
|
|
45
|
+
workflow = PayloadCursorWorkflow.create!(hero: @user)
|
|
46
|
+
speedrun_workflow(workflow)
|
|
47
|
+
|
|
48
|
+
assert_equal "finished", workflow.state
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
test "a nil limit disables the check" do
|
|
52
|
+
GenevaDrive.max_cursor_size = nil
|
|
53
|
+
Thread.current[:cursor_payload] = "x" * (256 * 1024)
|
|
54
|
+
|
|
55
|
+
workflow = PayloadCursorWorkflow.create!(hero: @user)
|
|
56
|
+
speedrun_workflow(workflow)
|
|
57
|
+
|
|
58
|
+
assert_equal "finished", workflow.state
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
test "cursor_value= enforces the limit too" do
|
|
62
|
+
GenevaDrive.max_cursor_size = 1024
|
|
63
|
+
|
|
64
|
+
workflow = PayloadCursorWorkflow.create!(hero: @user)
|
|
65
|
+
execution = workflow.current_execution
|
|
66
|
+
|
|
67
|
+
assert_raises(GenevaDrive::CursorTooLargeError) do
|
|
68
|
+
execution.cursor_value = "x" * 2048
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
execution.cursor_value = "x" * 100
|
|
72
|
+
execution.save!
|
|
73
|
+
assert_equal "x" * 100, execution.reload.cursor_value
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -60,6 +60,14 @@ class InstrumentationTest < ActiveSupport::TestCase
|
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
+
class UnreportedExceptionWorkflow < GenevaDrive::Workflow
|
|
64
|
+
on_exception :pause!, report: :never
|
|
65
|
+
|
|
66
|
+
step :failing_step do
|
|
67
|
+
raise StandardError, "test error"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
63
71
|
setup do
|
|
64
72
|
@user = create_user
|
|
65
73
|
@events = []
|
|
@@ -181,6 +189,26 @@ class InstrumentationTest < ActiveSupport::TestCase
|
|
|
181
189
|
assert_equal "test error", event[:payload][:exception].message
|
|
182
190
|
end
|
|
183
191
|
|
|
192
|
+
test "adds GenevaDrive context to Rails error reports during step execution" do
|
|
193
|
+
workflow = ExceptionWorkflow.create!(hero: @user)
|
|
194
|
+
step_execution = workflow.step_executions.first
|
|
195
|
+
|
|
196
|
+
report = assert_error_reported(StandardError) do
|
|
197
|
+
assert_raises(StandardError) do
|
|
198
|
+
GenevaDrive::Executor.execute!(step_execution)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
assert_equal({
|
|
203
|
+
workflow_id: workflow.id,
|
|
204
|
+
workflow_class: "InstrumentationTest::ExceptionWorkflow",
|
|
205
|
+
step_execution_id: step_execution.id,
|
|
206
|
+
step_name: "failing_step",
|
|
207
|
+
hero_type: "User",
|
|
208
|
+
hero_id: @user.id
|
|
209
|
+
}, report.context[:geneva_drive])
|
|
210
|
+
end
|
|
211
|
+
|
|
184
212
|
test "emits finalize.geneva_drive event after step completion" do
|
|
185
213
|
InstrumentedWorkflow.reset_tracking!
|
|
186
214
|
subscribe_to("finalize.geneva_drive")
|