dynflow 0.7.9 → 0.8.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.
- data/.gitignore +2 -0
- data/.travis.yml +16 -1
- data/Gemfile +13 -1
- data/doc/pages/source/_drafts/2015-03-01-new-documentation.markdown +10 -0
- data/doc/pages/source/_includes/menu.html +1 -0
- data/doc/pages/source/_includes/menu_right.html +1 -1
- data/doc/pages/source/_sass/_bootstrap-variables.sass +1 -0
- data/doc/pages/source/_sass/_style.scss +4 -0
- data/doc/pages/source/blog/index.html +12 -0
- data/doc/pages/source/documentation/index.md +330 -5
- data/dynflow.gemspec +3 -1
- data/examples/example_helper.rb +18 -11
- data/examples/orchestrate_evented.rb +2 -1
- data/examples/remote_executor.rb +53 -20
- data/lib/dynflow.rb +16 -6
- data/lib/dynflow/action/suspended.rb +1 -1
- data/lib/dynflow/action/with_sub_plans.rb +3 -6
- data/lib/dynflow/actor.rb +56 -0
- data/lib/dynflow/clock.rb +43 -38
- data/lib/dynflow/config.rb +107 -0
- data/lib/dynflow/connectors.rb +7 -0
- data/lib/dynflow/connectors/abstract.rb +41 -0
- data/lib/dynflow/connectors/database.rb +175 -0
- data/lib/dynflow/connectors/direct.rb +71 -0
- data/lib/dynflow/coordinator.rb +280 -0
- data/lib/dynflow/coordinator_adapters.rb +8 -0
- data/lib/dynflow/coordinator_adapters/abstract.rb +28 -0
- data/lib/dynflow/coordinator_adapters/sequel.rb +29 -0
- data/lib/dynflow/dispatcher.rb +58 -0
- data/lib/dynflow/dispatcher/abstract.rb +14 -0
- data/lib/dynflow/dispatcher/client_dispatcher.rb +139 -0
- data/lib/dynflow/dispatcher/executor_dispatcher.rb +86 -0
- data/lib/dynflow/errors.rb +7 -1
- data/lib/dynflow/execution_history.rb +46 -0
- data/lib/dynflow/execution_plan.rb +19 -15
- data/lib/dynflow/executors.rb +0 -1
- data/lib/dynflow/executors/abstract.rb +5 -10
- data/lib/dynflow/executors/parallel.rb +16 -13
- data/lib/dynflow/executors/parallel/core.rb +76 -78
- data/lib/dynflow/executors/parallel/execution_plan_manager.rb +4 -5
- data/lib/dynflow/executors/parallel/pool.rb +22 -52
- data/lib/dynflow/executors/parallel/running_steps_manager.rb +9 -2
- data/lib/dynflow/executors/parallel/worker.rb +5 -10
- data/lib/dynflow/persistence.rb +14 -0
- data/lib/dynflow/persistence_adapters/abstract.rb +14 -3
- data/lib/dynflow/persistence_adapters/sequel.rb +142 -38
- data/lib/dynflow/persistence_adapters/sequel_migrations/004_coordinator_records.rb +14 -0
- data/lib/dynflow/persistence_adapters/sequel_migrations/005_envelopes.rb +14 -0
- data/lib/dynflow/round_robin.rb +37 -0
- data/lib/dynflow/serializable.rb +1 -2
- data/lib/dynflow/serializer.rb +46 -0
- data/lib/dynflow/testing/dummy_executor.rb +2 -2
- data/lib/dynflow/testing/dummy_world.rb +1 -1
- data/lib/dynflow/transaction_adapters/abstract.rb +0 -5
- data/lib/dynflow/transaction_adapters/active_record.rb +0 -10
- data/lib/dynflow/version.rb +1 -1
- data/lib/dynflow/web.rb +26 -0
- data/lib/dynflow/web/console.rb +108 -0
- data/lib/dynflow/web/console_helpers.rb +158 -0
- data/lib/dynflow/web/filtering_helpers.rb +85 -0
- data/lib/dynflow/web/world_helpers.rb +9 -0
- data/lib/dynflow/web_console.rb +3 -310
- data/lib/dynflow/world.rb +188 -119
- data/test/abnormal_states_recovery_test.rb +152 -0
- data/test/action_test.rb +2 -3
- data/test/clock_test.rb +1 -5
- data/test/coordinator_test.rb +152 -0
- data/test/dispatcher_test.rb +146 -0
- data/test/execution_plan_test.rb +2 -1
- data/test/executor_test.rb +534 -612
- data/test/middleware_test.rb +4 -4
- data/test/persistence_test.rb +17 -0
- data/test/prepare_travis_env.sh +35 -0
- data/test/rescue_test.rb +5 -3
- data/test/round_robin_test.rb +28 -0
- data/test/support/code_workflow_example.rb +0 -73
- data/test/support/dummy_example.rb +130 -0
- data/test/support/test_execution_log.rb +41 -0
- data/test/test_helper.rb +222 -116
- data/test/testing_test.rb +10 -10
- data/test/web_console_test.rb +3 -3
- data/test/world_test.rb +23 -0
- data/web/assets/images/logo-square.png +0 -0
- data/web/assets/stylesheets/application.css +9 -0
- data/web/assets/vendor/bootstrap/config.json +429 -0
- data/web/assets/vendor/bootstrap/css/bootstrap-theme.css +479 -0
- data/web/assets/vendor/bootstrap/css/bootstrap-theme.min.css +10 -0
- data/web/assets/vendor/bootstrap/css/bootstrap.css +5377 -4980
- data/web/assets/vendor/bootstrap/css/bootstrap.min.css +9 -8
- data/web/assets/vendor/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- data/web/assets/vendor/bootstrap/fonts/glyphicons-halflings-regular.svg +288 -0
- data/web/assets/vendor/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/web/assets/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- data/web/assets/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/web/assets/vendor/bootstrap/js/bootstrap.js +1674 -1645
- data/web/assets/vendor/bootstrap/js/bootstrap.min.js +11 -5
- data/web/views/execution_history.erb +17 -0
- data/web/views/index.erb +4 -6
- data/web/views/layout.erb +44 -8
- data/web/views/show.erb +4 -5
- data/web/views/worlds.erb +26 -0
- metadata +116 -23
- checksums.yaml +0 -15
- data/lib/dynflow/daemon.rb +0 -30
- data/lib/dynflow/executors/remote_via_socket.rb +0 -43
- data/lib/dynflow/executors/remote_via_socket/core.rb +0 -184
- data/lib/dynflow/future.rb +0 -173
- data/lib/dynflow/listeners.rb +0 -7
- data/lib/dynflow/listeners/abstract.rb +0 -17
- data/lib/dynflow/listeners/serialization.rb +0 -77
- data/lib/dynflow/listeners/socket.rb +0 -117
- data/lib/dynflow/micro_actor.rb +0 -102
- data/lib/dynflow/simple_world.rb +0 -19
- data/test/remote_via_socket_test.rb +0 -170
- data/web/assets/vendor/bootstrap/css/bootstrap-responsive.css +0 -1109
- data/web/assets/vendor/bootstrap/css/bootstrap-responsive.min.css +0 -9
- data/web/assets/vendor/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/web/assets/vendor/bootstrap/img/glyphicons-halflings.png +0 -0
data/lib/dynflow/listeners.rb
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
module Dynflow
|
|
2
|
-
module Listeners
|
|
3
|
-
class Abstract
|
|
4
|
-
include Algebrick::TypeCheck
|
|
5
|
-
attr_reader :world, :logger
|
|
6
|
-
|
|
7
|
-
def initialize(world)
|
|
8
|
-
@world = Type! world, World
|
|
9
|
-
@logger = world.logger
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def terminate(future = Future.new)
|
|
13
|
-
raise NotImplementedError
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
module Dynflow
|
|
2
|
-
module Listeners
|
|
3
|
-
module Serialization
|
|
4
|
-
module Protocol
|
|
5
|
-
|
|
6
|
-
Job = Algebrick.type do
|
|
7
|
-
Event = type do
|
|
8
|
-
fields! execution_plan_id: String,
|
|
9
|
-
step_id: Fixnum,
|
|
10
|
-
event: Object
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
Execution = type do
|
|
14
|
-
fields! execution_plan_id: String
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
variants Event, Execution
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
Message = Algebrick.type do
|
|
21
|
-
Request = type do
|
|
22
|
-
variants Do = type { fields request_id: Integer, job: Job }
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
Response = type do
|
|
26
|
-
variants Accepted = type { fields request_id: Integer },
|
|
27
|
-
Failed = type { fields request_id: Integer, error: String },
|
|
28
|
-
Done = type { fields request_id: Integer }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
variants Request, Response
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
module Event
|
|
35
|
-
# TODO fix the workaround
|
|
36
|
-
# marshal and then use base64 because not all json libs can correctly escape binary data
|
|
37
|
-
def to_hash
|
|
38
|
-
super.update event: Base64.strict_encode64(Marshal.dump(event))
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def self.product_from_hash(hash)
|
|
42
|
-
super(hash.merge 'event' => Marshal.load(Base64.strict_decode64(hash.fetch('event'))))
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def dump(obj)
|
|
48
|
-
MultiJson.dump(obj.to_hash)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def load(str)
|
|
52
|
-
Protocol::Message.from_hash MultiJson.load(str)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def send_message(io, message, barrier = nil)
|
|
56
|
-
barrier.lock if barrier
|
|
57
|
-
io.puts dump(message)
|
|
58
|
-
true
|
|
59
|
-
rescue SystemCallError => error
|
|
60
|
-
@logger.warn "message could not be sent #{message} because #{error}"
|
|
61
|
-
false
|
|
62
|
-
ensure
|
|
63
|
-
barrier.unlock if barrier
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def receive_message(io)
|
|
67
|
-
if (message = io.gets)
|
|
68
|
-
load(message)
|
|
69
|
-
else
|
|
70
|
-
nil
|
|
71
|
-
end
|
|
72
|
-
rescue IOError
|
|
73
|
-
nil
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
module Dynflow
|
|
2
|
-
module Listeners
|
|
3
|
-
class Socket < Abstract
|
|
4
|
-
include Listeners::Serialization
|
|
5
|
-
include Algebrick::Matching
|
|
6
|
-
|
|
7
|
-
Terminate = Algebrick.atom
|
|
8
|
-
|
|
9
|
-
def initialize(world, socket_path, interval = 1)
|
|
10
|
-
super(world)
|
|
11
|
-
|
|
12
|
-
File.delete socket_path if File.exist? socket_path
|
|
13
|
-
@server = UNIXServer.new socket_path
|
|
14
|
-
File.chmod(0600, socket_path)
|
|
15
|
-
|
|
16
|
-
@clients = []
|
|
17
|
-
@client_barriers = {}
|
|
18
|
-
@terminate = false
|
|
19
|
-
@loop = Thread.new do
|
|
20
|
-
Thread.current.abort_on_exception = true
|
|
21
|
-
catch(Terminate) { loop { listen(interval) } }
|
|
22
|
-
@terminate.resolve true
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def terminate(future = Future.new)
|
|
27
|
-
raise 'multiple calls' if @terminate
|
|
28
|
-
@terminate = future
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
private
|
|
32
|
-
|
|
33
|
-
def listen(interval)
|
|
34
|
-
shutdown if @terminate
|
|
35
|
-
|
|
36
|
-
ios = [@server, *@clients]
|
|
37
|
-
reads, writes, errors = IO.select(ios, [], ios, interval)
|
|
38
|
-
Array(reads).each do |readable|
|
|
39
|
-
if readable == @server
|
|
40
|
-
add_client @server.accept
|
|
41
|
-
logger.info 'Client connected.'
|
|
42
|
-
|
|
43
|
-
else
|
|
44
|
-
match message = receive_message(readable),
|
|
45
|
-
(on ~Protocol::Do do |(id, job)|
|
|
46
|
-
execute_job(readable, id, job)
|
|
47
|
-
end),
|
|
48
|
-
(on NilClass.to_m do
|
|
49
|
-
remove_client readable
|
|
50
|
-
logger.info 'Client disconnected.'
|
|
51
|
-
end)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
rescue => error
|
|
55
|
-
logger.fatal error
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def execute_job(readable, id, job)
|
|
59
|
-
responded = false
|
|
60
|
-
respond = -> error = nil do
|
|
61
|
-
unless responded
|
|
62
|
-
responded = true
|
|
63
|
-
send_message_to_client(readable, if error
|
|
64
|
-
logger.error error
|
|
65
|
-
Protocol::Failed[id, error.message]
|
|
66
|
-
else
|
|
67
|
-
Protocol::Accepted[id]
|
|
68
|
-
end)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
future = Future.new.do_then do |_|
|
|
73
|
-
if future.resolved?
|
|
74
|
-
respond.call
|
|
75
|
-
send_message_to_client readable, Protocol::Done[id]
|
|
76
|
-
else
|
|
77
|
-
respond.call future.value
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
match job,
|
|
82
|
-
(on ~Protocol::Execution do |(uuid)|
|
|
83
|
-
@world.execute(uuid, future)
|
|
84
|
-
end),
|
|
85
|
-
(on ~Protocol::Event do |(uuid, step_id, event)|
|
|
86
|
-
@world.event(uuid, step_id, event, future)
|
|
87
|
-
end)
|
|
88
|
-
respond.call
|
|
89
|
-
rescue Dynflow::Error => e
|
|
90
|
-
respond.call e
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def add_client(client)
|
|
94
|
-
@clients << client
|
|
95
|
-
@client_barriers[client] = Mutex.new
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def remove_client(client)
|
|
99
|
-
@clients.delete client
|
|
100
|
-
@client_barriers.delete client
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def send_message_to_client(client, message)
|
|
104
|
-
send_message client, message, @client_barriers[client]
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def shutdown
|
|
108
|
-
@clients.each { |c| c.shutdown :RDWR }
|
|
109
|
-
@server.close
|
|
110
|
-
rescue => e
|
|
111
|
-
@logger.error e
|
|
112
|
-
ensure
|
|
113
|
-
throw Terminate
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|
data/lib/dynflow/micro_actor.rb
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
module Dynflow
|
|
2
|
-
class MicroActor
|
|
3
|
-
include Algebrick::TypeCheck
|
|
4
|
-
include Algebrick::Matching
|
|
5
|
-
|
|
6
|
-
attr_reader :logger, :initialized
|
|
7
|
-
|
|
8
|
-
Terminate = Algebrick.atom
|
|
9
|
-
|
|
10
|
-
def initialize(logger, *args)
|
|
11
|
-
@logger = logger
|
|
12
|
-
@initialized = Future.new
|
|
13
|
-
@thread = Thread.new { run *args }
|
|
14
|
-
Thread.pass until @mailbox
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def <<(message)
|
|
18
|
-
raise 'actor terminated' if terminated?
|
|
19
|
-
@mailbox << [message, nil]
|
|
20
|
-
self
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def ask(message, future = Future.new)
|
|
24
|
-
future.fail Dynflow::Error.new('actor terminated') if terminated?
|
|
25
|
-
@mailbox << [message, future]
|
|
26
|
-
future
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def stopped?
|
|
30
|
-
@terminated.ready?
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
private
|
|
34
|
-
|
|
35
|
-
def delayed_initialize(*args)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def termination
|
|
39
|
-
terminate!
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def terminating?
|
|
43
|
-
@terminated
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def terminated?
|
|
47
|
-
terminating? && @terminated.ready?
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def terminate!
|
|
51
|
-
raise unless Thread.current == @thread
|
|
52
|
-
@terminated.resolve true
|
|
53
|
-
throw Terminate
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def on_message(message)
|
|
57
|
-
raise NotImplementedError
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def receive
|
|
61
|
-
message, future = @mailbox.pop
|
|
62
|
-
#logger.debug "#{self.class} received:\n #{message}"
|
|
63
|
-
if message == Terminate
|
|
64
|
-
# TODO do not use this future to store in @terminated use one added to Terminate message
|
|
65
|
-
if terminating?
|
|
66
|
-
@terminated.do_then { future.resolve true } if future
|
|
67
|
-
else
|
|
68
|
-
@terminated = (future || Future.new)
|
|
69
|
-
termination
|
|
70
|
-
end
|
|
71
|
-
else
|
|
72
|
-
on_envelope message, future
|
|
73
|
-
end
|
|
74
|
-
rescue => error
|
|
75
|
-
logger.fatal error
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def on_envelope(message, future)
|
|
79
|
-
if future
|
|
80
|
-
future.evaluate_to { on_message message }
|
|
81
|
-
else
|
|
82
|
-
on_message message
|
|
83
|
-
end
|
|
84
|
-
if future && future.failed?
|
|
85
|
-
logger.error future.value
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def run(*args)
|
|
90
|
-
Thread.current.abort_on_exception = true
|
|
91
|
-
|
|
92
|
-
@mailbox = Queue.new
|
|
93
|
-
@terminated = nil
|
|
94
|
-
|
|
95
|
-
delayed_initialize(*args)
|
|
96
|
-
Thread.pass until @initialized
|
|
97
|
-
@initialized.resolve true
|
|
98
|
-
|
|
99
|
-
catch(Terminate) { loop { receive } }
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
data/lib/dynflow/simple_world.rb
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
module Dynflow
|
|
2
|
-
class SimpleWorld < World
|
|
3
|
-
def initialize(options_hash = {})
|
|
4
|
-
super options_hash
|
|
5
|
-
at_exit { self.terminate.wait } if options[:auto_terminate]
|
|
6
|
-
# we can check consistency here because SimpleWorld doesn't expect
|
|
7
|
-
# remote executor being in place.
|
|
8
|
-
self.consistency_check
|
|
9
|
-
self.execute_planned_execution_plans
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def default_options
|
|
13
|
-
super.merge(pool_size: 5,
|
|
14
|
-
persistence_adapter: PersistenceAdapters::Sequel.new('sqlite:/'),
|
|
15
|
-
transaction_adapter: TransactionAdapters::None.new,
|
|
16
|
-
auto_terminate: true)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
require_relative 'test_helper'
|
|
2
|
-
|
|
3
|
-
describe 'remote communication' do
|
|
4
|
-
|
|
5
|
-
let(:persistence_adapter) { Dynflow::PersistenceAdapters::Sequel.new('sqlite:/') }
|
|
6
|
-
|
|
7
|
-
module Helpers
|
|
8
|
-
def socket_path
|
|
9
|
-
@socket_path ||= Dir.tmpdir + "/dynflow_remote_#{rand(1e30)}"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def logger_adapter
|
|
13
|
-
WorldInstance.logger_adapter
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def create_world
|
|
17
|
-
Dynflow::SimpleWorld.new logger_adapter: logger_adapter,
|
|
18
|
-
auto_terminate: false,
|
|
19
|
-
exit_on_terminate: false,
|
|
20
|
-
persistence_adapter: persistence_adapter
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def create_remote_world
|
|
24
|
-
Dynflow::SimpleWorld.new(
|
|
25
|
-
logger_adapter: logger_adapter,
|
|
26
|
-
auto_terminate: false,
|
|
27
|
-
persistence_adapter: persistence_adapter,
|
|
28
|
-
exit_on_terminate: false,
|
|
29
|
-
executor: -> remote_world do
|
|
30
|
-
Dynflow::Executors::RemoteViaSocket.new(remote_world, socket_path)
|
|
31
|
-
end)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def create_listener(world)
|
|
35
|
-
Dynflow::Listeners::Socket.new world, socket_path, 0.05
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def terminate(*terminable)
|
|
39
|
-
terminable.each { |t| t.terminate.wait }
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
include Helpers
|
|
44
|
-
|
|
45
|
-
it 'raises when not connected' do
|
|
46
|
-
remote_world = create_remote_world
|
|
47
|
-
result = remote_world.trigger Support::CodeWorkflowExample::Commit, 'sha'
|
|
48
|
-
result.must_be :planned?
|
|
49
|
-
result.wont_be :triggered?
|
|
50
|
-
result.error.must_be_kind_of Dynflow::Error
|
|
51
|
-
|
|
52
|
-
terminate remote_world
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
describe 'execute_planned_execution_plans' do
|
|
56
|
-
specify do
|
|
57
|
-
remote_world = create_remote_world
|
|
58
|
-
result = remote_world.trigger Support::CodeWorkflowExample::Commit, 'sha'
|
|
59
|
-
result.must_be :planned?
|
|
60
|
-
result.wont_be :triggered?
|
|
61
|
-
result.error.must_be_kind_of Dynflow::Error
|
|
62
|
-
|
|
63
|
-
remote_world.persistence.load_execution_plan(result.id).state.must_equal :planned
|
|
64
|
-
|
|
65
|
-
world = create_world
|
|
66
|
-
listener = create_listener(world)
|
|
67
|
-
|
|
68
|
-
# waiting until it starts executing
|
|
69
|
-
assert(10.times do |i|
|
|
70
|
-
state = world.persistence.load_execution_plan(result.id).state
|
|
71
|
-
break :ok if [:running, :stopped].include? state
|
|
72
|
-
puts 'retry'
|
|
73
|
-
sleep 0.01 * i
|
|
74
|
-
end == :ok)
|
|
75
|
-
|
|
76
|
-
terminate remote_world, listener, world
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
describe 'shutting down' do
|
|
81
|
-
[:remote_world, :world, :listener].permutation.each do |order|
|
|
82
|
-
it "works when in order #{order}" do
|
|
83
|
-
objects = { world: w = create_world,
|
|
84
|
-
listener: create_listener(w),
|
|
85
|
-
remote_world: remote_world = create_remote_world }
|
|
86
|
-
|
|
87
|
-
result = remote_world.trigger Support::CodeWorkflowExample::Commit, 'sha'
|
|
88
|
-
result.must_be :planned?
|
|
89
|
-
result.finished.value!.must_be_kind_of Dynflow::ExecutionPlan
|
|
90
|
-
|
|
91
|
-
terminate *objects.values_at(*order)
|
|
92
|
-
assert true, 'it has to reach this'
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
it 'allows to work others' do
|
|
97
|
-
world = create_world
|
|
98
|
-
listener = create_listener(world)
|
|
99
|
-
rmw1 = create_remote_world
|
|
100
|
-
rmw2 = create_remote_world
|
|
101
|
-
|
|
102
|
-
[rmw1.trigger(Support::CodeWorkflowExample::Commit, 'sha').finished,
|
|
103
|
-
rmw2.trigger(Support::CodeWorkflowExample::Commit, 'sha').finished].
|
|
104
|
-
each(&:value!)
|
|
105
|
-
|
|
106
|
-
terminate rmw1
|
|
107
|
-
|
|
108
|
-
refute rmw1.trigger(Support::CodeWorkflowExample::Commit, 'sha').triggered?
|
|
109
|
-
rmw2.trigger(Support::CodeWorkflowExample::Commit, 'sha').
|
|
110
|
-
finished.value!.must_be_kind_of Dynflow::ExecutionPlan
|
|
111
|
-
|
|
112
|
-
terminate rmw2, listener, world
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
it 'raises when disconnected while executing' do
|
|
116
|
-
world = create_world
|
|
117
|
-
listener = create_listener(world)
|
|
118
|
-
remote_world = create_remote_world
|
|
119
|
-
|
|
120
|
-
result = remote_world.trigger(Support::CodeWorkflowExample::Slow, 2)
|
|
121
|
-
result.must_be :planned?
|
|
122
|
-
|
|
123
|
-
terminate listener
|
|
124
|
-
|
|
125
|
-
-> { result.finished.value! }.must_raise Dynflow::Future::FutureFailed
|
|
126
|
-
terminate remote_world, world
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
it 'restarts' do
|
|
132
|
-
world = create_world
|
|
133
|
-
listener = create_listener(world)
|
|
134
|
-
remote_world = create_remote_world
|
|
135
|
-
|
|
136
|
-
remote_world.trigger(Support::CodeWorkflowExample::Commit, 'sha').finished.value!
|
|
137
|
-
|
|
138
|
-
terminate listener
|
|
139
|
-
Thread.pass while remote_world.executor.connected?
|
|
140
|
-
listener = create_listener world
|
|
141
|
-
Thread.pass until remote_world.executor.connected?
|
|
142
|
-
|
|
143
|
-
remote_world.trigger(Support::CodeWorkflowExample::Commit, 'sha').finished.value!
|
|
144
|
-
|
|
145
|
-
terminate listener, world
|
|
146
|
-
Thread.pass while remote_world.executor.connected?
|
|
147
|
-
world = create_world
|
|
148
|
-
listener = create_listener world
|
|
149
|
-
Thread.pass until remote_world.executor.connected?
|
|
150
|
-
|
|
151
|
-
remote_world.trigger(Support::CodeWorkflowExample::Commit, 'sha').finished.value!
|
|
152
|
-
|
|
153
|
-
terminate listener, world, remote_world
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
describe '#connected?' do
|
|
157
|
-
specify do
|
|
158
|
-
remote_world = create_remote_world
|
|
159
|
-
|
|
160
|
-
remote_world.executor.connected?.must_equal false
|
|
161
|
-
|
|
162
|
-
world = create_world
|
|
163
|
-
listener = create_listener world
|
|
164
|
-
|
|
165
|
-
remote_world.executor.connected?.must_equal true
|
|
166
|
-
|
|
167
|
-
terminate listener, world, remote_world
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|