dynflow 0.5.0 → 0.5.1

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.
@@ -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