dynflow 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +3 -4
- data/Dockerfile +9 -0
- data/Gemfile +6 -0
- data/Rakefile +1 -0
- data/doc/pages/Gemfile +1 -0
- data/doc/pages/Rakefile +1 -0
- data/doc/pages/plugins/alert_block.rb +1 -0
- data/doc/pages/plugins/div_tag.rb +1 -0
- data/doc/pages/plugins/graphviz.rb +1 -0
- data/doc/pages/plugins/plantuml.rb +1 -0
- data/doc/pages/plugins/play.rb +1 -0
- data/doc/pages/plugins/tags.rb +1 -0
- data/doc/pages/plugins/toc.rb +1 -0
- data/docker-compose.yml +41 -0
- data/dynflow.gemspec +1 -0
- data/examples/clock_benchmark.rb +1 -0
- data/examples/example_helper.rb +19 -2
- data/examples/future_execution.rb +2 -1
- data/examples/memory_limit_watcher.rb +1 -0
- data/examples/orchestrate.rb +4 -5
- data/examples/orchestrate_evented.rb +3 -2
- data/examples/remote_executor.rb +68 -0
- data/examples/singletons.rb +4 -3
- data/examples/sub_plan_concurrency_control.rb +2 -1
- data/examples/sub_plans.rb +3 -2
- data/examples/termination.rb +1 -0
- data/lib/dynflow.rb +20 -0
- data/lib/dynflow/action.rb +28 -3
- data/lib/dynflow/action/cancellable.rb +1 -0
- data/lib/dynflow/action/format.rb +1 -0
- data/lib/dynflow/action/missing.rb +1 -0
- data/lib/dynflow/action/polling.rb +3 -1
- data/lib/dynflow/action/progress.rb +1 -0
- data/lib/dynflow/action/rescue.rb +1 -0
- data/lib/dynflow/action/singleton.rb +1 -0
- data/lib/dynflow/action/suspended.rb +9 -2
- data/lib/dynflow/action/timeouts.rb +2 -1
- data/lib/dynflow/action/with_bulk_sub_plans.rb +2 -1
- data/lib/dynflow/action/with_polling_sub_plans.rb +7 -5
- data/lib/dynflow/action/with_sub_plans.rb +1 -0
- data/lib/dynflow/active_job/queue_adapter.rb +1 -0
- data/lib/dynflow/actor.rb +13 -5
- data/lib/dynflow/actors.rb +1 -0
- data/lib/dynflow/actors/execution_plan_cleaner.rb +1 -0
- data/lib/dynflow/clock.rb +27 -47
- data/lib/dynflow/config.rb +11 -2
- data/lib/dynflow/connectors.rb +1 -0
- data/lib/dynflow/connectors/abstract.rb +1 -0
- data/lib/dynflow/connectors/database.rb +1 -0
- data/lib/dynflow/connectors/direct.rb +1 -0
- data/lib/dynflow/coordinator.rb +1 -0
- data/lib/dynflow/coordinator_adapters.rb +1 -0
- data/lib/dynflow/coordinator_adapters/abstract.rb +1 -0
- data/lib/dynflow/coordinator_adapters/sequel.rb +1 -0
- data/lib/dynflow/dead_letter_silencer.rb +2 -0
- data/lib/dynflow/debug/telemetry/persistence.rb +1 -0
- data/lib/dynflow/delayed_executors.rb +1 -0
- data/lib/dynflow/delayed_executors/abstract.rb +1 -0
- data/lib/dynflow/delayed_executors/abstract_core.rb +1 -0
- data/lib/dynflow/delayed_executors/polling.rb +1 -0
- data/lib/dynflow/delayed_plan.rb +1 -0
- data/lib/dynflow/director.rb +80 -15
- data/lib/dynflow/director/execution_plan_manager.rb +17 -3
- data/lib/dynflow/director/flow_manager.rb +1 -0
- data/lib/dynflow/director/{work_queue.rb → queue_hash.rb} +9 -8
- data/lib/dynflow/director/running_steps_manager.rb +55 -18
- data/lib/dynflow/director/sequence_cursor.rb +1 -0
- data/lib/dynflow/director/sequential_manager.rb +12 -2
- data/lib/dynflow/dispatcher.rb +4 -2
- data/lib/dynflow/dispatcher/abstract.rb +1 -0
- data/lib/dynflow/dispatcher/client_dispatcher.rb +6 -4
- data/lib/dynflow/dispatcher/executor_dispatcher.rb +13 -1
- data/lib/dynflow/errors.rb +1 -0
- data/lib/dynflow/execution_history.rb +1 -0
- data/lib/dynflow/execution_plan.rb +3 -2
- data/lib/dynflow/execution_plan/dependency_graph.rb +1 -0
- data/lib/dynflow/execution_plan/hooks.rb +1 -0
- data/lib/dynflow/execution_plan/output_reference.rb +2 -1
- data/lib/dynflow/execution_plan/steps.rb +1 -0
- data/lib/dynflow/execution_plan/steps/abstract.rb +10 -5
- data/lib/dynflow/execution_plan/steps/abstract_flow_step.rb +2 -0
- data/lib/dynflow/execution_plan/steps/error.rb +1 -0
- data/lib/dynflow/execution_plan/steps/finalize_step.rb +1 -0
- data/lib/dynflow/execution_plan/steps/plan_step.rb +1 -0
- data/lib/dynflow/execution_plan/steps/run_step.rb +1 -0
- data/lib/dynflow/executors.rb +1 -1
- data/lib/dynflow/executors/abstract/core.rb +132 -0
- data/lib/dynflow/executors/parallel.rb +24 -11
- data/lib/dynflow/executors/parallel/core.rb +10 -91
- data/lib/dynflow/executors/parallel/pool.rb +4 -2
- data/lib/dynflow/executors/parallel/worker.rb +2 -1
- data/lib/dynflow/executors/sidekiq/core.rb +121 -0
- data/lib/dynflow/executors/sidekiq/internal_job_base.rb +24 -0
- data/lib/dynflow/executors/sidekiq/orchestrator_jobs.rb +60 -0
- data/lib/dynflow/executors/sidekiq/redis_locking.rb +69 -0
- data/lib/dynflow/executors/sidekiq/serialization.rb +33 -0
- data/lib/dynflow/executors/sidekiq/worker_jobs.rb +42 -0
- data/lib/dynflow/flows.rb +1 -0
- data/lib/dynflow/flows/abstract.rb +1 -0
- data/lib/dynflow/flows/abstract_composed.rb +1 -0
- data/lib/dynflow/flows/atom.rb +1 -0
- data/lib/dynflow/flows/concurrence.rb +1 -0
- data/lib/dynflow/flows/sequence.rb +1 -0
- data/lib/dynflow/logger_adapters.rb +1 -0
- data/lib/dynflow/logger_adapters/abstract.rb +1 -0
- data/lib/dynflow/logger_adapters/delegator.rb +1 -0
- data/lib/dynflow/logger_adapters/formatters.rb +1 -0
- data/lib/dynflow/logger_adapters/formatters/abstract.rb +1 -0
- data/lib/dynflow/logger_adapters/formatters/exception.rb +1 -0
- data/lib/dynflow/logger_adapters/simple.rb +1 -0
- data/lib/dynflow/middleware.rb +1 -0
- data/lib/dynflow/middleware/common/singleton.rb +1 -0
- data/lib/dynflow/middleware/common/transaction.rb +1 -0
- data/lib/dynflow/middleware/register.rb +1 -0
- data/lib/dynflow/middleware/resolver.rb +1 -0
- data/lib/dynflow/middleware/stack.rb +1 -0
- data/lib/dynflow/middleware/world.rb +1 -0
- data/lib/dynflow/persistence.rb +3 -2
- data/lib/dynflow/persistence_adapters.rb +1 -0
- data/lib/dynflow/persistence_adapters/abstract.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel.rb +10 -7
- data/lib/dynflow/persistence_adapters/sequel_migrations/001_initial.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/002_incremental_progress.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/003_parent_action.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/004_coordinator_records.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/005_envelopes.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/006_fix_data_length.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/007_future_execution.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/008_rename_scheduled_plans_to_delayed_plans.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/009_fix_mysql_data_length.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/010_add_execution_plans_label.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/011_placeholder.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/012_add_delayed_plans_serialized_args.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/013_add_action_columns.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/014_add_step_columns.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/015_add_execution_plan_columns.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/016_add_step_queue.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/017_add_delayed_plan_frozen.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/018_add_uuid_column.rb +1 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/019_update_mysql_time_precision.rb +48 -0
- data/lib/dynflow/rails.rb +1 -0
- data/lib/dynflow/rails/configuration.rb +6 -3
- data/lib/dynflow/rails/daemon.rb +1 -0
- data/lib/dynflow/round_robin.rb +1 -0
- data/lib/dynflow/semaphores.rb +1 -0
- data/lib/dynflow/semaphores/abstract.rb +1 -0
- data/lib/dynflow/semaphores/aggregating.rb +1 -0
- data/lib/dynflow/semaphores/dummy.rb +1 -0
- data/lib/dynflow/semaphores/stateful.rb +1 -0
- data/lib/dynflow/serializable.rb +13 -4
- data/lib/dynflow/serializer.rb +24 -0
- data/lib/dynflow/serializers.rb +1 -0
- data/lib/dynflow/serializers/abstract.rb +1 -0
- data/lib/dynflow/serializers/noop.rb +1 -0
- data/lib/dynflow/stateful.rb +1 -0
- data/lib/dynflow/telemetry.rb +1 -0
- data/lib/dynflow/telemetry_adapters/abstract.rb +1 -0
- data/lib/dynflow/telemetry_adapters/dummy.rb +1 -0
- data/lib/dynflow/telemetry_adapters/statsd.rb +1 -0
- data/lib/dynflow/testing.rb +1 -0
- data/lib/dynflow/testing/assertions.rb +6 -5
- data/lib/dynflow/testing/dummy_execution_plan.rb +1 -0
- data/lib/dynflow/testing/dummy_executor.rb +19 -2
- data/lib/dynflow/testing/dummy_planned_action.rb +1 -0
- data/lib/dynflow/testing/dummy_step.rb +3 -1
- data/lib/dynflow/testing/dummy_world.rb +9 -0
- data/lib/dynflow/testing/factories.rb +6 -1
- data/lib/dynflow/testing/in_thread_executor.rb +22 -3
- data/lib/dynflow/testing/in_thread_world.rb +9 -0
- data/lib/dynflow/testing/managed_clock.rb +1 -0
- data/lib/dynflow/testing/mimic.rb +1 -0
- data/lib/dynflow/throttle_limiter.rb +1 -0
- data/lib/dynflow/transaction_adapters.rb +1 -0
- data/lib/dynflow/transaction_adapters/abstract.rb +1 -0
- data/lib/dynflow/transaction_adapters/active_record.rb +1 -0
- data/lib/dynflow/transaction_adapters/none.rb +1 -0
- data/lib/dynflow/utils.rb +1 -0
- data/lib/dynflow/utils/indifferent_hash.rb +1 -0
- data/lib/dynflow/utils/priority_queue.rb +1 -0
- data/lib/dynflow/version.rb +2 -1
- data/lib/dynflow/watchers/memory_consumption_watcher.rb +1 -0
- data/lib/dynflow/web.rb +1 -0
- data/lib/dynflow/web/console.rb +1 -0
- data/lib/dynflow/web/console_helpers.rb +1 -0
- data/lib/dynflow/web/filtering_helpers.rb +1 -0
- data/lib/dynflow/web/world_helpers.rb +1 -0
- data/lib/dynflow/web_console.rb +1 -0
- data/lib/dynflow/world.rb +11 -1
- data/lib/dynflow/world/invalidation.rb +7 -1
- data/test/abnormal_states_recovery_test.rb +41 -40
- data/test/action_test.rb +160 -110
- data/test/activejob_adapter_test.rb +1 -0
- data/test/batch_sub_tasks_test.rb +12 -11
- data/test/clock_test.rb +2 -1
- data/test/concurrency_control_test.rb +20 -19
- data/test/coordinator_test.rb +20 -21
- data/test/daemon_test.rb +2 -1
- data/test/dead_letter_silencer_test.rb +9 -7
- data/test/dispatcher_test.rb +2 -1
- data/test/execution_plan_cleaner_test.rb +13 -12
- data/test/execution_plan_hooks_test.rb +3 -2
- data/test/execution_plan_test.rb +33 -32
- data/test/executor_test.rb +533 -489
- data/test/future_execution_test.rb +45 -44
- data/test/memory_cosumption_watcher_test.rb +5 -4
- data/test/middleware_test.rb +55 -54
- data/test/persistence_test.rb +56 -53
- data/test/rescue_test.rb +36 -35
- data/test/round_robin_test.rb +13 -12
- data/test/semaphores_test.rb +31 -30
- data/test/support/code_workflow_example.rb +1 -0
- data/test/support/dummy_example.rb +14 -1
- data/test/support/middleware_example.rb +2 -1
- data/test/support/rails/config/environment.rb +1 -0
- data/test/support/rescue_example.rb +1 -0
- data/test/support/test_execution_log.rb +1 -0
- data/test/test_helper.rb +18 -17
- data/test/testing_test.rb +45 -44
- data/test/utils_test.rb +18 -17
- data/test/web_console_test.rb +1 -0
- data/test/world_test.rb +7 -6
- metadata +13 -4
- data/lib/dynflow/executors/abstract.rb +0 -40
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative 'test_helper'
|
2
3
|
|
3
4
|
module Dynflow
|
@@ -72,7 +73,7 @@ module Dynflow
|
|
72
73
|
plan = world.persistence.load_execution_plan(plan.id)
|
73
74
|
action = plan.entry_action
|
74
75
|
|
75
|
-
action.output[:batch_count].must_equal action.total_count / action.batch_size
|
76
|
+
_(action.output[:batch_count]).must_equal action.total_count / action.batch_size
|
76
77
|
end
|
77
78
|
|
78
79
|
it 'can resume tasks' do
|
@@ -82,17 +83,17 @@ module Dynflow
|
|
82
83
|
wait_for { future.resolved? }
|
83
84
|
plan = world.persistence.load_execution_plan(plan.id)
|
84
85
|
action = plan.entry_action
|
85
|
-
action.output[:batch_count].must_equal 1
|
86
|
-
future.value.state.must_equal :paused
|
86
|
+
_(action.output[:batch_count]).must_equal 1
|
87
|
+
_(future.value.state).must_equal :paused
|
87
88
|
|
88
89
|
FailureSimulator.wont_fail!
|
89
90
|
future = world.execute plan.id
|
90
91
|
wait_for { future.resolved? }
|
91
92
|
action = future.value.entry_action
|
92
|
-
future.value.state.must_equal :stopped
|
93
|
-
action.output[:batch_count].must_equal (action.total_count / action.batch_size) + 1
|
94
|
-
action.output[:total_count].must_equal action.total_count
|
95
|
-
action.output[:success_count].must_equal action.total_count
|
93
|
+
_(future.value.state).must_equal :stopped
|
94
|
+
_(action.output[:batch_count]).must_equal (action.total_count / action.batch_size) + 1
|
95
|
+
_(action.output[:total_count]).must_equal action.total_count
|
96
|
+
_(action.output[:success_count]).must_equal action.total_count
|
96
97
|
end
|
97
98
|
|
98
99
|
it 'is controlled only by total_count and output[:planned_count]' do
|
@@ -101,12 +102,12 @@ module Dynflow
|
|
101
102
|
wait_for { future.resolved? }
|
102
103
|
plan = world.persistence.load_execution_plan(plan.id)
|
103
104
|
action = plan.entry_action
|
104
|
-
action.send(:can_spawn_next_batch?).must_equal false
|
105
|
-
action.current_batch.must_be :empty?
|
105
|
+
_(action.send(:can_spawn_next_batch?)).must_equal false
|
106
|
+
_(action.current_batch).must_be :empty?
|
106
107
|
action.output[:pending_count] = 0
|
107
108
|
action.output[:success_count] = 5
|
108
|
-
action.send(:can_spawn_next_batch?).must_equal false
|
109
|
-
action.current_batch.must_be :empty?
|
109
|
+
_(action.send(:can_spawn_next_batch?)).must_equal false
|
110
|
+
_(action.current_batch).must_be :empty?
|
110
111
|
end
|
111
112
|
|
112
113
|
end
|
data/test/clock_test.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative 'test_helper'
|
2
3
|
require 'logger'
|
3
4
|
|
@@ -8,7 +9,7 @@ describe clock_class do
|
|
8
9
|
let(:clock) { clock_class.spawn 'clock' }
|
9
10
|
|
10
11
|
it 'refuses who without #<< method' do
|
11
|
-
-> { clock.ping Object.new, 0.1, :pong }.must_raise TypeError
|
12
|
+
_(-> { clock.ping Object.new, 0.1, :pong }).must_raise TypeError
|
12
13
|
clock.ping [], 0.1, :pong
|
13
14
|
end
|
14
15
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative 'test_helper'
|
2
3
|
|
3
4
|
module Dynflow
|
@@ -80,9 +81,9 @@ module Dynflow
|
|
80
81
|
end
|
81
82
|
|
82
83
|
def check_step(plan, total, finished)
|
83
|
-
world.throttle_limiter.observe(plan.id).length.must_equal (total - finished)
|
84
|
-
plan.sub_plans.select { |sub| planned? sub }.count.must_equal (total - finished)
|
85
|
-
plan.sub_plans.select { |sub| successful? sub }.count.must_equal finished
|
84
|
+
_(world.throttle_limiter.observe(plan.id).length).must_equal (total - finished)
|
85
|
+
_(plan.sub_plans.select { |sub| planned? sub }.count).must_equal (total - finished)
|
86
|
+
_(plan.sub_plans.select { |sub| successful? sub }.count).must_equal finished
|
86
87
|
end
|
87
88
|
|
88
89
|
def planned?(plan)
|
@@ -126,7 +127,7 @@ module Dynflow
|
|
126
127
|
future = world.execute plan.id
|
127
128
|
wait_for { future.resolved? }
|
128
129
|
plan.sub_plans.all? { |sub| successful? sub }
|
129
|
-
world.throttle_limiter.core.ask!(:running).must_equal [0]
|
130
|
+
_(world.throttle_limiter.core.ask!(:running)).must_equal [0]
|
130
131
|
end
|
131
132
|
|
132
133
|
it 'limits by concurrency level' do
|
@@ -135,7 +136,7 @@ module Dynflow
|
|
135
136
|
plan = world.plan(ParentAction, total, level)
|
136
137
|
future = world.execute plan.id
|
137
138
|
wait_for { future.resolved? }
|
138
|
-
world.throttle_limiter.core.ask!(:running).max.must_be :<=, level
|
139
|
+
_(world.throttle_limiter.core.ask!(:running).max).must_be :<=, level
|
139
140
|
end
|
140
141
|
|
141
142
|
it 'allows to cancel' do
|
@@ -147,8 +148,8 @@ module Dynflow
|
|
147
148
|
world.event(plan.id, plan.steps.values.last.id, ::Dynflow::Action::Cancellable::Cancel)
|
148
149
|
wait_for { triggered.resolved? }
|
149
150
|
plan = world.persistence.load_execution_plan(plan.id)
|
150
|
-
plan.entry_action.output[:failed_count].must_equal total
|
151
|
-
world.throttle_limiter.core.ask!(:running).max.must_be :<=, 0
|
151
|
+
_(plan.entry_action.output[:failed_count]).must_equal total
|
152
|
+
_(world.throttle_limiter.core.ask!(:running).max).must_be :<=, 0
|
152
153
|
end
|
153
154
|
end
|
154
155
|
|
@@ -165,21 +166,21 @@ module Dynflow
|
|
165
166
|
wait_for { plan.sub_plans_count == total }
|
166
167
|
wait_for { klok.progress; plan.sub_plans.all? { |sub| successful? sub } }
|
167
168
|
# 10 tasks over 10 seconds, one task at a time, 1 task every second
|
168
|
-
get_interval.call(plan).must_equal 1.0
|
169
|
+
_(get_interval.call(plan)).must_equal 1.0
|
169
170
|
|
170
171
|
plan = world.plan(ParentAction, total, 4, 10)
|
171
172
|
world.execute(plan.id)
|
172
173
|
wait_for { plan.sub_plans_count == total }
|
173
174
|
wait_for { klok.progress; plan.sub_plans.all? { |sub| successful? sub } }
|
174
175
|
# 10 tasks over 10 seconds, four tasks at a time, 1 task every 0.25 second
|
175
|
-
get_interval.call(plan).must_equal 0.25
|
176
|
+
_(get_interval.call(plan)).must_equal 0.25
|
176
177
|
|
177
178
|
plan = world.plan(ParentAction, total, nil, 10)
|
178
179
|
world.execute(plan.id)
|
179
180
|
wait_for { plan.sub_plans_count == total }
|
180
181
|
wait_for { klok.progress; plan.sub_plans.all? { |sub| successful? sub } }
|
181
182
|
# 1o tasks over 10 seconds, one task at a time (default), 1 task every second
|
182
|
-
get_interval.call(plan).must_equal 1.0
|
183
|
+
_(get_interval.call(plan)).must_equal 1.0
|
183
184
|
end
|
184
185
|
end
|
185
186
|
|
@@ -204,9 +205,9 @@ module Dynflow
|
|
204
205
|
check_step(plan, total, finished)
|
205
206
|
end
|
206
207
|
end_time = klok.current_time
|
207
|
-
(end_time - start_time).must_equal 4
|
208
|
-
world.throttle_limiter.observe(plan.id).must_equal []
|
209
|
-
world.throttle_limiter.core.ask!(:running).max.must_be :<=, level
|
208
|
+
_((end_time - start_time)).must_equal 4
|
209
|
+
_(world.throttle_limiter.observe(plan.id)).must_equal []
|
210
|
+
_(world.throttle_limiter.core.ask!(:running).max).must_be :<=, level
|
210
211
|
end
|
211
212
|
end
|
212
213
|
|
@@ -218,7 +219,7 @@ module Dynflow
|
|
218
219
|
plan = world.plan(ParentAction, total, level, time_span)
|
219
220
|
future = world.execute(plan.id)
|
220
221
|
wait_for { future.resolved? }
|
221
|
-
plan.sub_plans.all? { |sub| sub.result == :error }.must_equal true
|
222
|
+
_(plan.sub_plans.all? { |sub| sub.result == :error }).must_equal true
|
222
223
|
end
|
223
224
|
|
224
225
|
it 'cancels tasks which could not be started within the time window' do
|
@@ -230,14 +231,14 @@ module Dynflow
|
|
230
231
|
future = world.execute(plan.id)
|
231
232
|
wait_for { plan.sub_plans_count == total && plan.sub_plans.all? { |sub| sub.result == :pending } }
|
232
233
|
planned, running = plan.sub_plans.partition { |sub| planned? sub }
|
233
|
-
planned.count.must_equal total - level
|
234
|
-
running.count.must_equal level
|
235
|
-
world.throttle_limiter.observe(plan.id).length.must_equal (total - 1)
|
234
|
+
_(planned.count).must_equal total - level
|
235
|
+
_(running.count).must_equal level
|
236
|
+
_(world.throttle_limiter.observe(plan.id).length).must_equal (total - 1)
|
236
237
|
4.times { klok.progress }
|
237
238
|
wait_for { future.resolved? }
|
238
239
|
finished, stopped = plan.sub_plans.partition { |sub| successful? sub }
|
239
|
-
finished.count.must_equal level
|
240
|
-
stopped.count.must_equal (total - level)
|
240
|
+
_(finished.count).must_equal level
|
241
|
+
_(stopped.count).must_equal (total - level)
|
241
242
|
end
|
242
243
|
end
|
243
244
|
end
|
data/test/coordinator_test.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative 'test_helper'
|
2
3
|
require 'fileutils'
|
3
4
|
|
@@ -11,13 +12,13 @@ module Dynflow
|
|
11
12
|
it 'unlocks the lock, when the block is passed' do
|
12
13
|
world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world)) {}
|
13
14
|
expected_locks = ["lock auto-execute", "unlock auto-execute"]
|
14
|
-
world.coordinator.adapter.lock_log.must_equal(expected_locks)
|
15
|
+
_(world.coordinator.adapter.lock_log).must_equal(expected_locks)
|
15
16
|
end
|
16
17
|
|
17
18
|
it "doesn't unlock, when the block is not passed" do
|
18
19
|
world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world))
|
19
20
|
expected_locks = ["lock auto-execute"]
|
20
|
-
world.coordinator.adapter.lock_log.must_equal(expected_locks)
|
21
|
+
_(world.coordinator.adapter.lock_log).must_equal(expected_locks)
|
21
22
|
end
|
22
23
|
|
23
24
|
it 'supports unlocking by owner' do
|
@@ -35,23 +36,23 @@ module Dynflow
|
|
35
36
|
it 'supports checking about locks' do
|
36
37
|
world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world))
|
37
38
|
locks = world.coordinator.find_locks(Coordinator::AutoExecuteLock.unique_filter)
|
38
|
-
locks.map(&:world_id).must_equal([world.id])
|
39
|
+
_(locks.map(&:world_id)).must_equal([world.id])
|
39
40
|
end
|
40
41
|
|
41
42
|
it 'deserializes the data from the adapter when searching for locks' do
|
42
43
|
lock = Coordinator::AutoExecuteLock.new(world)
|
43
44
|
world.coordinator.acquire(lock)
|
44
45
|
found_locks = world.coordinator.find_locks(owner_id: lock.owner_id)
|
45
|
-
found_locks.size.must_equal 1
|
46
|
-
found_locks.first.data.must_equal lock.data
|
46
|
+
_(found_locks.size).must_equal 1
|
47
|
+
_(found_locks.first.data).must_equal lock.data
|
47
48
|
|
48
49
|
found_locks = world.coordinator.find_locks(class: lock.class.name, id: lock.id)
|
49
|
-
found_locks.size.must_equal 1
|
50
|
-
found_locks.first.data.must_equal lock.data
|
50
|
+
_(found_locks.size).must_equal 1
|
51
|
+
_(found_locks.first.data).must_equal lock.data
|
51
52
|
|
52
53
|
another_lock = Coordinator::AutoExecuteLock.new(another_world)
|
53
54
|
found_locks = world.coordinator.find_locks(owner_id: another_lock.owner_id)
|
54
|
-
found_locks.size.must_equal 0
|
55
|
+
_(found_locks.size).must_equal 0
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
@@ -76,15 +77,15 @@ module Dynflow
|
|
76
77
|
dummy_record = DummyRecord.new('dummy', 'Foo')
|
77
78
|
world.coordinator.create_record(dummy_record)
|
78
79
|
saved_dummy_record = world.coordinator.find_records(class: dummy_record.class.name).first
|
79
|
-
saved_dummy_record.must_equal dummy_record
|
80
|
+
_(saved_dummy_record).must_equal dummy_record
|
80
81
|
|
81
82
|
dummy_record.value = 'Bar'
|
82
83
|
world.coordinator.update_record(dummy_record)
|
83
84
|
saved_dummy_record = world.coordinator.find_records(class: dummy_record.class.name).first
|
84
|
-
saved_dummy_record.data.must_equal dummy_record.data
|
85
|
+
_(saved_dummy_record.data).must_equal dummy_record.data
|
85
86
|
|
86
87
|
world.coordinator.delete_record(dummy_record)
|
87
|
-
world.coordinator.find_records(class: dummy_record.class.name).must_equal []
|
88
|
+
_(world.coordinator.find_records(class: dummy_record.class.name)).must_equal []
|
88
89
|
end
|
89
90
|
end
|
90
91
|
|
@@ -94,14 +95,12 @@ module Dynflow
|
|
94
95
|
another_world.coordinator.acquire Coordinator::WorldInvalidationLock.new(another_world, another_world)
|
95
96
|
world.terminate.wait
|
96
97
|
expected_locks = ["lock auto-execute", "unlock auto-execute"]
|
97
|
-
world.coordinator.adapter.lock_log.must_equal(expected_locks)
|
98
|
+
_(world.coordinator.adapter.lock_log).must_equal(expected_locks)
|
98
99
|
end
|
99
100
|
|
100
101
|
it 'prevents new locks to be acquired by the world being terminated' do
|
101
102
|
world.terminate
|
102
|
-
->
|
103
|
-
world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world))
|
104
|
-
end.must_raise(Errors::InactiveWorldError)
|
103
|
+
_(-> { world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world)) }).must_raise(Errors::InactiveWorldError)
|
105
104
|
end
|
106
105
|
end
|
107
106
|
|
@@ -114,7 +113,7 @@ module Dynflow
|
|
114
113
|
adapter.create_record(record)
|
115
114
|
tester.pause
|
116
115
|
end
|
117
|
-
-> { another_adapter.create_record(record) }.must_raise(Coordinator::DuplicateRecordError)
|
116
|
+
_(-> { another_adapter.create_record(record) }).must_raise(Coordinator::DuplicateRecordError)
|
118
117
|
tester.finish
|
119
118
|
end
|
120
119
|
|
@@ -134,16 +133,16 @@ module Dynflow
|
|
134
133
|
lock = Coordinator::AutoExecuteLock.new(world)
|
135
134
|
adapter.create_record(lock)
|
136
135
|
found_records = adapter.find_records(owner_id: lock.owner_id)
|
137
|
-
found_records.size.must_equal 1
|
138
|
-
found_records.first.must_equal lock.data
|
136
|
+
_(found_records.size).must_equal 1
|
137
|
+
_(found_records.first).must_equal lock.data
|
139
138
|
|
140
139
|
found_records = adapter.find_records(class: lock.class.name, id: lock.id)
|
141
|
-
found_records.size.must_equal 1
|
142
|
-
found_records.first.must_equal lock.data
|
140
|
+
_(found_records.size).must_equal 1
|
141
|
+
_(found_records.first).must_equal lock.data
|
143
142
|
|
144
143
|
another_lock = Coordinator::AutoExecuteLock.new(another_world)
|
145
144
|
found_records = adapter.find_records(owner_id: another_lock.owner_id)
|
146
|
-
found_records.size.must_equal 0
|
145
|
+
_(found_records.size).must_equal 0
|
147
146
|
end
|
148
147
|
end
|
149
148
|
end
|
data/test/daemon_test.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative 'test_helper'
|
2
3
|
require 'ostruct'
|
3
4
|
|
@@ -10,7 +11,7 @@ module Dynflow
|
|
10
11
|
let(:world) { WorldFactory.create_world }
|
11
12
|
|
12
13
|
it 'is started for each world' do
|
13
|
-
world.dead_letter_handler.actor_class
|
14
|
+
_(world.dead_letter_handler.actor_class)
|
14
15
|
.must_equal ::Dynflow::DeadLetterSilencer
|
15
16
|
end
|
16
17
|
|
@@ -26,19 +27,20 @@ module Dynflow
|
|
26
27
|
end
|
27
28
|
|
28
29
|
it 'matches any' do
|
29
|
-
DeadLetterSilencer::Matcher.new(any, any, any).match?(letter).must_equal true
|
30
|
+
_(DeadLetterSilencer::Matcher.new(any, any, any).match?(letter)).must_equal true
|
30
31
|
end
|
31
32
|
|
32
33
|
it 'matches comparing for equality' do
|
33
|
-
DeadLetterSilencer::Matcher.new(sender, msg, receiver)
|
34
|
-
|
35
|
-
DeadLetterSilencer::Matcher.new(any, :bad, any)
|
34
|
+
matcher = DeadLetterSilencer::Matcher.new(sender, msg, receiver)
|
35
|
+
_(matcher.match?(letter)).must_equal true
|
36
|
+
matcher = DeadLetterSilencer::Matcher.new(any, :bad, any)
|
37
|
+
_(matcher.match?(letter)).must_equal false
|
36
38
|
end
|
37
39
|
|
38
40
|
it 'matches by calling the proc' do
|
39
41
|
condition = proc { |actor_class| actor_class.is_a? Class }
|
40
|
-
DeadLetterSilencer::Matcher.new(condition, any, condition)
|
41
|
-
|
42
|
+
matcher = DeadLetterSilencer::Matcher.new(condition, any, condition)
|
43
|
+
_(matcher.match?(letter)).must_equal true
|
42
44
|
end
|
43
45
|
end
|
44
46
|
end
|
data/test/dispatcher_test.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative 'test_helper'
|
2
3
|
|
3
4
|
module Dynflow
|
@@ -24,7 +25,7 @@ module Dynflow
|
|
24
25
|
|
25
26
|
describe 'event passing' do
|
26
27
|
it 'succeeds when expected' do
|
27
|
-
result = client_world.trigger(Support::DummyExample::
|
28
|
+
result = client_world.trigger(Support::DummyExample::DeprecatedEventedAction, :timeout => 3)
|
28
29
|
step = wait_for do
|
29
30
|
client_world.persistence.load_execution_plan(result.id).
|
30
31
|
steps_in_state(:suspended).first
|
@@ -1,5 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative 'test_helper'
|
2
|
-
require 'mocha/
|
3
|
+
require 'mocha/minitest'
|
3
4
|
|
4
5
|
module Dynflow
|
5
6
|
module ExecutionPlanCleanerTest
|
@@ -28,16 +29,16 @@ module Dynflow
|
|
28
29
|
let(:clock) { Testing::ManagedClock.new }
|
29
30
|
|
30
31
|
it 'is disabled by default' do
|
31
|
-
default_world.execution_plan_cleaner
|
32
|
-
world.execution_plan_cleaner
|
33
|
-
|
32
|
+
assert_nil default_world.execution_plan_cleaner
|
33
|
+
_(world.execution_plan_cleaner)
|
34
|
+
.must_be_instance_of ::Dynflow::Actors::ExecutionPlanCleaner
|
34
35
|
end
|
35
36
|
|
36
37
|
it 'periodically looks for old execution plans' do
|
37
38
|
world.stub(:clock, clock) do
|
38
|
-
clock.pending_pings.count.must_equal 0
|
39
|
+
_(clock.pending_pings.count).must_equal 0
|
39
40
|
world.execution_plan_cleaner.core.ask!(:start)
|
40
|
-
clock.pending_pings.count.must_equal 1
|
41
|
+
_(clock.pending_pings.count).must_equal 1
|
41
42
|
world.persistence.expects(:find_old_execution_plans).returns([])
|
42
43
|
world.persistence.expects(:delete_execution_plans).with(:uuid => [])
|
43
44
|
clock.progress
|
@@ -48,7 +49,7 @@ module Dynflow
|
|
48
49
|
it 'cleans up old plans' do
|
49
50
|
world.stub(:clock, clock) do
|
50
51
|
world.execution_plan_cleaner.core.ask!(:start)
|
51
|
-
clock.pending_pings.count.must_equal 1
|
52
|
+
_(clock.pending_pings.count).must_equal 1
|
52
53
|
plans = (1..10).map { world.trigger SimpleAction }
|
53
54
|
.each { |plan| plan.finished.wait }
|
54
55
|
world.persistence.find_execution_plans(:uuid => plans.map(&:id))
|
@@ -57,8 +58,8 @@ module Dynflow
|
|
57
58
|
plan.save
|
58
59
|
end
|
59
60
|
world.execution_plan_cleaner.core.ask!(:clean!)
|
60
|
-
world.persistence.find_execution_plans(:uuid => plans.map(&:id))
|
61
|
-
|
61
|
+
plans = world.persistence.find_execution_plans(:uuid => plans.map(&:id))
|
62
|
+
_(plans.count).must_equal 0
|
62
63
|
end
|
63
64
|
end
|
64
65
|
|
@@ -66,12 +67,12 @@ module Dynflow
|
|
66
67
|
world.stub(:clock, clock) do
|
67
68
|
count = 10
|
68
69
|
world.execution_plan_cleaner.core.ask!(:start)
|
69
|
-
clock.pending_pings.count.must_equal 1
|
70
|
+
_(clock.pending_pings.count).must_equal 1
|
70
71
|
plans = (1..10).map { world.trigger SimpleAction }
|
71
72
|
.each { |plan| plan.finished.wait }
|
72
73
|
world.execution_plan_cleaner.core.ask!(:clean!)
|
73
|
-
world.persistence.find_execution_plans(:uuid => plans.map(&:id))
|
74
|
-
|
74
|
+
plans = world.persistence.find_execution_plans(:uuid => plans.map(&:id))
|
75
|
+
_(plans.count).must_equal count
|
75
76
|
end
|
76
77
|
end
|
77
78
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative 'test_helper'
|
2
3
|
|
3
4
|
module Dynflow
|
@@ -137,7 +138,7 @@ module Dynflow
|
|
137
138
|
plan = world.plan(ActionOnStop)
|
138
139
|
plan = world.execute(plan.id).wait!.value
|
139
140
|
assert Flag.raised?
|
140
|
-
plan.result.must_equal :success
|
141
|
+
_(plan.result).must_equal :success
|
141
142
|
end
|
142
143
|
|
143
144
|
it 'inherits the hooks when subclassing' do
|
@@ -158,7 +159,7 @@ module Dynflow
|
|
158
159
|
refute Flag.raised?
|
159
160
|
plan = world.trigger(ComposedAction)
|
160
161
|
plan.finished.wait!
|
161
|
-
Flag.raised_count.must_equal 1
|
162
|
+
_(Flag.raised_count).must_equal 1
|
162
163
|
end
|
163
164
|
end
|
164
165
|
end
|