dynflow 0.8.11 → 0.8.12

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