dynflow 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -395,6 +395,8 @@ module Dynflow
395
395
  end
396
396
  end
397
397
  end
398
+
399
+ check_serializable :input
398
400
  end
399
401
  end
400
402
 
@@ -422,6 +424,8 @@ module Dynflow
422
424
  if result == SUSPEND
423
425
  self.state = :suspended
424
426
  end
427
+
428
+ check_serializable :output
425
429
  end
426
430
 
427
431
  else
@@ -440,5 +444,14 @@ module Dynflow
440
444
  end
441
445
  end
442
446
  end
447
+
448
+ def check_serializable(what)
449
+ Match! what, :input, :output
450
+ value = send what
451
+ recursive_to_hash value # it raises when not serializable
452
+ rescue => e
453
+ value.replace not_serializable: true
454
+ raise e
455
+ end
443
456
  end
444
457
  end
@@ -23,6 +23,7 @@ module Dynflow
23
23
  sequential_manager.finalize
24
24
  end)
25
25
  @pool << WorkerDone[work: message, worker: self]
26
+ ensure
26
27
  @transaction_adapter.cleanup
27
28
  end
28
29
  end
@@ -30,6 +30,16 @@ module Dynflow
30
30
  found
31
31
  end
32
32
 
33
+ def refute_action_planed(action, planned_action_class)
34
+ Match! action.phase, Action::Plan
35
+ Match! action.state, :success
36
+ found = action.execution_plan.planned_plan_steps.
37
+ select { |a| a.is_a?(planned_action_class) }
38
+
39
+ assert(found.empty?, "Action #{planned_action_class} was planned")
40
+ found
41
+ end
42
+
33
43
  # assert that +action+ has run-phase planned
34
44
  def assert_run_phase(action, input = nil, &block)
35
45
  Match! action.phase, Action::Plan
@@ -7,16 +7,28 @@ module Dynflow
7
7
  attr_reader :id, :planned_plan_steps, :planned_run_steps, :planned_finalize_steps
8
8
 
9
9
  def initialize
10
- @id = Testing.get_id.to_s
11
- @planned_plan_steps = []
12
- @planned_run_steps = []
13
- @planned_finalize_steps = []
10
+ @id = Testing.get_id.to_s
11
+ @planned_plan_steps = []
12
+ @planned_run_steps = []
13
+ @planned_finalize_steps = []
14
+ @planned_action_stubbers = {}
14
15
  end
15
16
 
16
17
  def world
17
18
  @world ||= DummyWorld.new
18
19
  end
19
20
 
21
+ # Allows modify the DummyPlannedAction returned by plan_action
22
+ def stub_planned_action(klass, &block)
23
+ @planned_action_stubbers[klass] = block
24
+ end
25
+
26
+ def add_plan_step(klass, _)
27
+ dummy_planned_action(klass).tap do |action|
28
+ @planned_plan_steps << action
29
+ end
30
+ end
31
+
20
32
  def add_run_step(action)
21
33
  @planned_run_steps << action
22
34
  action
@@ -27,9 +39,12 @@ module Dynflow
27
39
  action
28
40
  end
29
41
 
30
- def add_plan_step(klass, action)
31
- @planned_plan_steps << action = DummyPlannedAction.new(klass)
32
- action
42
+ def dummy_planned_action(klass)
43
+ DummyPlannedAction.new(klass).tap do |action|
44
+ if planned_action_stubber = @planned_action_stubbers[klass]
45
+ planned_action_stubber.call(action)
46
+ end
47
+ end
33
48
  end
34
49
 
35
50
  def switch_flow(*args, &block)
@@ -1,3 +1,3 @@
1
1
  module Dynflow
2
- VERSION = '0.5.0'
2
+ VERSION = '0.5.1'
3
3
  end
@@ -56,6 +56,10 @@ module Dynflow
56
56
  end
57
57
  end
58
58
 
59
+ def duration_to_s(duration)
60
+ h("%0.2fs" % duration)
61
+ end
62
+
59
63
  def load_action(step)
60
64
  world.persistence.load_action(step)
61
65
  end
@@ -74,7 +78,7 @@ module Dynflow
74
78
  if !value_html.empty?
75
79
  <<-HTML
76
80
  <p>
77
- #{h(label)}
81
+ <b>#{h(label)}</b>
78
82
  #{value_html}
79
83
  </p>
80
84
  HTML
@@ -139,11 +143,11 @@ module Dynflow
139
143
  end
140
144
 
141
145
  def updated_url(new_params)
142
- url("?" + Rack::Utils.build_query(params.merge(new_params.stringify_keys)))
146
+ url("?" + Rack::Utils.build_nested_query(params.merge(new_params.stringify_keys)))
143
147
  end
144
148
 
145
149
  def paginated_url(delta)
146
- h(updated_url(page: [0, page + delta].max))
150
+ h(updated_url(page: [0, page + delta].max.to_s))
147
151
  end
148
152
 
149
153
  def pagination_options
data/test/action_test.rb CHANGED
@@ -70,5 +70,26 @@ module Dynflow
70
70
  presenter.summary.must_equal(assignees: ["John Doe"])
71
71
  end
72
72
  end
73
+
74
+ describe 'serialization' do
75
+
76
+ include Testing
77
+
78
+ it 'fails when input is not serializable' do
79
+ klass = Class.new(Dynflow::Action)
80
+ -> { create_and_plan_action klass, key: Object.new }.must_raise NoMethodError
81
+ end
82
+
83
+ it 'fails when output is not serializable' do
84
+ klass = Class.new(Dynflow::Action) do
85
+ def run
86
+ output.update key: Object.new
87
+ end
88
+ end
89
+ action = create_and_plan_action klass, {}
90
+ -> { run_action action }.must_raise NoMethodError
91
+ end
92
+ end
93
+
73
94
  end
74
95
  end
data/test/testing_test.rb CHANGED
@@ -9,7 +9,7 @@ module Dynflow
9
9
 
10
10
  describe 'testing' do
11
11
 
12
- it '#plan_action' do
12
+ specify '#plan_action' do
13
13
  input = { 'input' => 'input' }
14
14
  action = create_and_plan_action CWE::DummyHeavyProgress, input
15
15
 
@@ -21,9 +21,20 @@ module Dynflow
21
21
  assert_run_phase action
22
22
  assert_finalize_phase action
23
23
  assert_action_planed action, CWE::DummySuspended
24
+ refute_action_planed action, CWE::DummyAnotherTrigger
24
25
  end
25
26
 
26
- it '#run_action without suspend' do
27
+ specify 'stub_plan_action' do
28
+ action = create_action CWE::DummyHeavyProgress
29
+ action.execution_plan.stub_planned_action(CWE::DummySuspended) do |sub_action|
30
+ sub_action.define_singleton_method(:test) { "test" }
31
+ end
32
+ plan_action(action, {})
33
+ stubbed_action = action.execution_plan.planned_plan_steps.first
34
+ stubbed_action.test.must_equal "test"
35
+ end
36
+
37
+ specify '#run_action without suspend' do
27
38
  input = { 'input' => 'input' }
28
39
  plan = create_and_plan_action CWE::DummyHeavyProgress, input
29
40
  action = run_action plan
@@ -37,7 +48,7 @@ module Dynflow
37
48
  action.progress_done.must_equal 1
38
49
  end
39
50
 
40
- it '#run_action with suspend' do
51
+ specify '#run_action with suspend' do
41
52
  input = { 'input' => 'input' }
42
53
  plan = create_and_plan_action CWE::DummySuspended, input
43
54
  action = run_action plan
@@ -59,7 +70,7 @@ module Dynflow
59
70
  action.progress_done.must_equal 1
60
71
  end
61
72
 
62
- it '#finalizes' do
73
+ specify '#finalize_action' do
63
74
  input = { 'input' => 'input' }
64
75
  plan = create_and_plan_action CWE::DummyHeavyProgress, input
65
76
  run = run_action plan
@@ -122,14 +133,14 @@ module Dynflow
122
133
  let(:planned_action) { create_and_plan_action CWE::Merge, plan_input }
123
134
  let(:runned_action) { run_action planned_action }
124
135
 
125
- it '#plans' do
136
+ it 'plans' do
126
137
  assert_run_phase planned_action
127
138
  refute_finalize_phase planned_action
128
139
 
129
140
  planned_action.execution_plan.planned_plan_steps.must_be_empty
130
141
  end
131
142
 
132
- it '#runs' do
143
+ it 'runs' do
133
144
  runned_action.output.fetch(:passed).must_equal true
134
145
  end
135
146
 
@@ -138,7 +149,7 @@ module Dynflow
138
149
  super.update review_results: [true, false]
139
150
  end
140
151
 
141
- it '#runs' do
152
+ it 'runs' do
142
153
  runned_action.output.fetch(:passed).must_equal false
143
154
  end
144
155
  end
@@ -5,17 +5,27 @@
5
5
  <% end %>
6
6
 
7
7
  <span class="step-label">
8
- <%= h(step.id) %>: <%= h(step.action_class.name) %> (<%= h(step.state) %>)
8
+ <%= h(step.id) %>: <%= h(step.action_class.name) %>
9
+ (<%= h(step.state) %>)
10
+ <% unless step.state == :pending %>
11
+ [ <%= duration_to_s(step.real_time) %> / <%= duration_to_s(step.execution_time) %> ]
12
+ <% end %>
9
13
  </span>
10
14
  <% if @plan.state == :paused && step.state == :error %>
11
15
  <a href="<%= url("/#{@plan.id}/skip/#{step.id}") %>" class="postlink">Skip</a>
12
16
  <% end %>
13
17
  <div class="action">
18
+ <% unless @plan.state == :pending %>
19
+ <p><b>Started at:</b> <%= h(step.started_at) %></p>
20
+ <p><b>Ended at:</b> <%= h(step.ended_at) %></p>
21
+ <p><b>Real time:</b> <%= duration_to_s(step.real_time) %></p>
22
+ <p><b>Execution time (excluding suspended state):</b> <%= duration_to_s(step.execution_time) %></p>
23
+ <% end %>
14
24
  <%= show_action_data("Input:", action.input) %>
15
25
  <%= show_action_data("Output:", action.output) %>
16
26
  <% if step.error %>
17
27
  <p>
18
- Error:
28
+ <b>Error:</b>
19
29
  </p>
20
30
  <p>
21
31
  <%= h(step.error.exception_class) %>
data/web/views/show.erb CHANGED
@@ -14,6 +14,16 @@
14
14
  <%= h(@plan.result) %>
15
15
  </p>
16
16
 
17
+ <p>
18
+ <b>Started at:</b>
19
+ <%= h(@plan.started_at) %>
20
+ </p>
21
+
22
+ <p>
23
+ <b>Ended at:</b>
24
+ <%= h(@plan.ended_at) %>
25
+ </p>
26
+
17
27
  <ul class="phases nav nav-tabs" id="myTab">
18
28
  <li><a href="#plan">Plan</a></li>
19
29
  <li class="active"><a href="#run">Run</a></li>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynflow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-25 00:00:00.000000000 Z
12
+ date: 2014-03-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport