dynflow 0.8.11 → 0.8.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 93710eb28bcde8ae7c912b0a93330f4dfa2c6cab
4
- data.tar.gz: 6a31996ff86af3a4ce6080d1410fc9a63b79b033
3
+ metadata.gz: 74ac597ce9af73467ae1ecbf398a2929f1595b14
4
+ data.tar.gz: 22cb74c9aef05391f93d8652888c9806fd9edde5
5
5
  SHA512:
6
- metadata.gz: 77d32bc910ab7fce6d73b968b9a96915577825803634e69023109d2ad9510a0fd9d9e9e7123200a47035dcf275514b0d7db50fb2fffc11ef316959fd1609177d
7
- data.tar.gz: c257770350812b06aa98462fec4c902a3c25215c7ebe31ec4c86cd1a0c3048d86dde7155435d78c24c4fe91b7544daaf73539dce5d1f617abc5f09b472ba6d81
6
+ metadata.gz: aec52cb41798f0730ef950e88195a3973b3d879f584b0e3341e8900147d66ff1b5642d394683894c4a0c33a1eb1d119296c08840dbbb8fb9a90d1b760d8fe0ef
7
+ data.tar.gz: 5e5908f5ad7938c036c948a1d925c23d714ea2384f3ef6ac0e1a40aa12c97ee71c044c598898e00e2942e04d4473738f975ceaa3b35ce0294b2a00ea0a969ede
data/Gemfile CHANGED
@@ -17,3 +17,7 @@ end
17
17
  group :mysql do
18
18
  gem "mysql2"
19
19
  end
20
+
21
+ if RUBY_VERSION < "2.2.2"
22
+ gem 'activesupport', '~> 4.2'
23
+ end
data/dynflow.gemspec CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_dependency "concurrent-ruby-edge", '~> 0.2'
26
26
  s.add_dependency "sequel"
27
27
 
28
+ s.add_development_dependency "rake"
28
29
  s.add_development_dependency "rack-test"
29
30
  s.add_development_dependency "minitest"
30
31
  s.add_development_dependency "minitest-reporters"
@@ -92,8 +92,8 @@ module Dynflow
92
92
 
93
93
  @phase = Type! attributes.fetch(:phase), Phase
94
94
  @world = Type! world, World
95
- @step = Type!(attributes.fetch(:step),
96
- ExecutionPlan::Steps::Abstract) if phase? Executable
95
+ @step = Type! attributes.fetch(:step), ExecutionPlan::Steps::Abstract, NilClass
96
+ raise ArgumentError, 'Step reference missing' if phase?(Executable) && @step.nil?
97
97
  @execution_plan_id = Type! attributes.fetch(:execution_plan_id), String
98
98
  @id = Type! attributes.fetch(:id), Integer
99
99
  @plan_step_id = Type! attributes.fetch(:plan_step_id), Integer
@@ -240,7 +240,7 @@ module Dynflow
240
240
  end
241
241
 
242
242
  def state
243
- phase! Executable
243
+ raise "state data not available" if @step.nil?
244
244
  @step.state
245
245
  end
246
246
 
@@ -251,7 +251,7 @@ module Dynflow
251
251
  end
252
252
 
253
253
  def error
254
- phase! Executable
254
+ raise "error data not available" if @step.nil?
255
255
  @step.error
256
256
  end
257
257
 
@@ -146,6 +146,14 @@ module Dynflow
146
146
  @data.merge!(owner_id: "world:#{world.id}", world_id: world.id)
147
147
  end
148
148
 
149
+ def self.lock_id(*args)
150
+ raise NoMethodError
151
+ end
152
+
153
+ def self.unique_filter(*args)
154
+ { :class => self.name, :id => lock_id(*args) }
155
+ end
156
+
149
157
  def validate!
150
158
  super
151
159
  raise Errors::InactiveWorldError.new(@world) if @world.terminating?
@@ -171,33 +179,49 @@ module Dynflow
171
179
  class DelayedExecutorLock < LockByWorld
172
180
  def initialize(world)
173
181
  super
174
- @data[:id] = "delayed-executor"
182
+ @data[:id] = self.class.lock_id
183
+ end
184
+
185
+ def self.lock_id
186
+ "delayed-executor"
175
187
  end
176
188
  end
177
189
 
178
190
  class WorldInvalidationLock < LockByWorld
179
191
  def initialize(world, invalidated_world)
180
192
  super(world)
181
- @data[:id] = "world-invalidation:#{invalidated_world.id}"
193
+ @data[:id] = self.class.lock_id(invalidated_world.id)
194
+ end
195
+
196
+ def self.lock_id(invalidated_world_id)
197
+ "world-invalidation:#{invalidated_world_id}"
182
198
  end
183
199
  end
184
200
 
185
201
  class AutoExecuteLock < LockByWorld
186
202
  def initialize(*args)
187
203
  super
188
- @data[:id] = "auto-execute"
204
+ @data[:id] = self.class.lock_id
205
+ end
206
+
207
+ def self.lock_id
208
+ "auto-execute"
189
209
  end
190
210
  end
191
211
 
192
212
  class ExecutionLock < LockByWorld
193
213
  def initialize(world, execution_plan_id, client_world_id, request_id)
194
214
  super(world)
195
- @data.merge!(id: "execution-plan:#{execution_plan_id}",
215
+ @data.merge!(id: self.class.lock_id(execution_plan_id),
196
216
  execution_plan_id: execution_plan_id,
197
217
  client_world_id: client_world_id,
198
218
  request_id: request_id)
199
219
  end
200
220
 
221
+ def self.lock_id(execution_plan_id)
222
+ "execution-plan:#{execution_plan_id}"
223
+ end
224
+
201
225
  # we need to store the following data in case of
202
226
  # invalidation of the lock from outside (after
203
227
  # the owner world terminated unexpectedly)
@@ -46,5 +46,8 @@ module Dynflow
46
46
  pass(*args)
47
47
  end
48
48
 
49
+ def present
50
+ pass
51
+ end
49
52
  end
50
53
  end
@@ -14,7 +14,7 @@ module Dynflow
14
14
  @middleware_class = Child! middleware_class, Middleware
15
15
  @middleware = middleware_class.new self
16
16
  @action = Type! action, Dynflow::Action, NilClass
17
- @method = Match! method, :delay, :plan, :run, :finalize, :plan_phase, :finalize_phase
17
+ @method = Match! method, :delay, :plan, :run, :finalize, :plan_phase, :finalize_phase, :present
18
18
  @next_stack = Type! next_stack, Middleware::Stack, Proc
19
19
  end
20
20
 
@@ -14,7 +14,7 @@ module Dynflow
14
14
  end
15
15
 
16
16
  def execute(method, action_or_class, *args, &block)
17
- Match! method, :delay, :plan, :run, :finalize, :plan_phase, :finalize_phase
17
+ Match! method, :delay, :plan, :run, :finalize, :plan_phase, :finalize_phase, :present
18
18
  if Child? action_or_class, Dynflow::Action
19
19
  action = nil
20
20
  action_class = action_or_class
@@ -21,9 +21,11 @@ module Dynflow
21
21
  return Action.from_hash(attributes, step.world)
22
22
  end
23
23
 
24
- def load_action_for_presentation(execution_plan, action_id)
24
+ def load_action_for_presentation(execution_plan, action_id, step = nil)
25
25
  attributes = adapter.load_action(execution_plan.id, action_id)
26
- Action.from_hash(attributes.update(phase: Action::Present, execution_plan: execution_plan), @world)
26
+ Action.from_hash(attributes.update(phase: Action::Present, execution_plan: execution_plan, step: step), @world).tap do |present_action|
27
+ @world.middleware.execute(:present, present_action) {}
28
+ end
27
29
  end
28
30
 
29
31
  def save_action(execution_plan_id, action)
@@ -1,3 +1,3 @@
1
1
  module Dynflow
2
- VERSION = '0.8.11'
2
+ VERSION = '0.8.12'
3
3
  end
@@ -45,7 +45,7 @@ module Dynflow
45
45
  end
46
46
 
47
47
  def load_action(step)
48
- world.persistence.load_action(step)
48
+ world.persistence.load_action_for_presentation(@plan, step.action_id, step)
49
49
  end
50
50
 
51
51
  def step_error(step)
data/lib/dynflow/world.rb CHANGED
@@ -354,7 +354,11 @@ module Dynflow
354
354
  coordinator.acquire(Coordinator::AutoExecuteLock.new(self)) do
355
355
  planned_execution_plans =
356
356
  self.persistence.find_execution_plans filters: { 'state' => %w(planned paused), 'result' => (ExecutionPlan.results - [:error]).map(&:to_s) }
357
- planned_execution_plans.map { |ep| execute ep.id }
357
+ planned_execution_plans.map do |ep|
358
+ if coordinator.find_locks(Dynflow::Coordinator::ExecutionLock.unique_filter(ep.id)).empty?
359
+ execute(ep.id)
360
+ end
361
+ end.compact
358
362
  end
359
363
  end
360
364
 
@@ -32,6 +32,12 @@ module Dynflow
32
32
  tester.finish
33
33
  end
34
34
 
35
+ it 'supports checking about locks' do
36
+ world.coordinator.acquire(Coordinator::AutoExecuteLock.new(world))
37
+ locks = world.coordinator.find_locks(Coordinator::AutoExecuteLock.unique_filter)
38
+ locks.map(&:world_id).must_equal([world.id])
39
+ end
40
+
35
41
  it 'deserializes the data from the adapter when searching for locks' do
36
42
  lock = Coordinator::AutoExecuteLock.new(world)
37
43
  world.coordinator.acquire(lock)
@@ -132,6 +132,57 @@ module Dynflow
132
132
  'run',
133
133
  'output#message:finished']
134
134
  end
135
+
136
+ describe 'Presnet middleware' do
137
+ let(:world_with_middleware) do
138
+ WorldFactory.create_world.tap do |world|
139
+ world.middleware.use(Support::MiddlewareExample::FilterSensitiveData)
140
+ end
141
+ end
142
+
143
+ let :execution_plan do
144
+ result = world.trigger(Support::CodeWorkflowExample::IncomingIssue, issue_data)
145
+ result.must_be :planned?
146
+ result.finished.value
147
+ end
148
+
149
+ let :execution_plan_2 do
150
+ result = world.trigger(Support::MiddlewareExample::SecretAction)
151
+ result.must_be :planned?
152
+ result.finished.value
153
+ end
154
+
155
+ let :filtered_execution_plan do
156
+ world_with_middleware.persistence.load_execution_plan(execution_plan.id)
157
+ end
158
+
159
+ let :issue_data do
160
+ { 'author' => 'Harry Potter', 'text' => 'Lord Voldemort is comming' }
161
+ end
162
+
163
+ let :presenter do
164
+ filtered_execution_plan.root_plan_step.action filtered_execution_plan
165
+ end
166
+
167
+ let :presenter_2 do
168
+ execution_plan_2.root_plan_step.action execution_plan_2
169
+ end
170
+
171
+ let :presenter_without_middleware do
172
+ execution_plan.root_plan_step.action execution_plan
173
+ end
174
+
175
+ it 'filters the data ===' do
176
+ presenter.input['text'].must_equal('You-Know-Who is comming')
177
+ presenter_2.output['spell'].must_equal('***')
178
+ end
179
+
180
+ it "doesn't affect stored data" do
181
+ presenter.input['text'].must_equal('You-Know-Who is comming')
182
+ presenter_without_middleware.input['text'].must_equal('Lord Voldemort is comming')
183
+ end
184
+ end
185
+
135
186
  end
136
187
  end
137
188
  end
@@ -70,6 +70,39 @@ module Support
70
70
  class AnotherLogRunMiddleware < LogRunMiddleware
71
71
  end
72
72
 
73
+ class FilterSensitiveData < Dynflow::Middleware
74
+ def present
75
+ if action.respond_to?(:filter_sensitive_data)
76
+ action.filter_sensitive_data
77
+ end
78
+ filter_sensitive_data(action.input)
79
+ filter_sensitive_data(action.output)
80
+ end
81
+
82
+ def filter_sensitive_data(data)
83
+ case data
84
+ when Hash
85
+ data.values.each { |value| filter_sensitive_data(value) }
86
+ when Array
87
+ data.each { |value| filter_sensitive_data(value) }
88
+ when String
89
+ data.gsub!('Lord Voldemort', 'You-Know-Who')
90
+ end
91
+ end
92
+ end
93
+
94
+ class SecretAction < Dynflow::Action
95
+ middleware.use(FilterSensitiveData)
96
+
97
+ def run
98
+ output[:spell] = 'Wingardium Leviosa'
99
+ end
100
+
101
+ def filter_sensitive_data
102
+ output[:spell] = '***'
103
+ end
104
+ end
105
+
73
106
  class LoggingAction < Dynflow::Action
74
107
 
75
108
  middleware.use LogMiddleware
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.8.11
4
+ version: 0.8.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Necas
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-05-16 00:00:00.000000000 Z
12
+ date: 2016-07-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
@@ -95,6 +95,20 @@ dependencies:
95
95
  - - ">="
96
96
  - !ruby/object:Gem::Version
97
97
  version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rake
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
98
112
  - !ruby/object:Gem::Dependency
99
113
  name: rack-test
100
114
  requirement: !ruby/object:Gem::Requirement
@@ -528,7 +542,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
528
542
  version: '0'
529
543
  requirements: []
530
544
  rubyforge_project:
531
- rubygems_version: 2.4.5
545
+ rubygems_version: 2.4.8
532
546
  signing_key:
533
547
  specification_version: 4
534
548
  summary: DYNamic workFLOW engine
@@ -557,3 +571,4 @@ test_files:
557
571
  - test/testing_test.rb
558
572
  - test/web_console_test.rb
559
573
  - test/world_test.rb
574
+ has_rdoc: