aws-flow 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,210 @@
1
+ ##
2
+ # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License").
5
+ # You may not use this file except in compliance with the License.
6
+ # A copy of the License is located at
7
+ #
8
+ # http://aws.amazon.com/apache2.0
9
+ #
10
+ # or in the "license" file accompanying this file. This file is distributed
11
+ # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12
+ # express or implied. See the License for the specific language governing
13
+ # permissions and limitations under the License.
14
+ ##
15
+
16
+ describe Future do
17
+ let(:future) { Future.new }
18
+ let(:trace) { [] }
19
+ it "throws an exception when set multiple times" do
20
+ future.set(:foo)
21
+ expect { future.set(:bar) }.to raise_error AlreadySetException
22
+ end
23
+
24
+ it "returns the value which was set" do
25
+ value = :foo
26
+ future.set(value)
27
+ future.get.should == value
28
+ end
29
+
30
+ it "blocks a task until a value is ready" do
31
+ scope = AsyncScope.new do
32
+ task do
33
+ trace << :first
34
+ future.get
35
+ # TODO technically this should only be checked in a TaskContext test;
36
+ # a Future test would just make sure that this comes after :second
37
+ trace << :fourth
38
+ end
39
+
40
+ task do
41
+ trace << :second
42
+ future.set(:foo)
43
+ trace << :third
44
+ end
45
+ end
46
+
47
+ scope.eventLoop
48
+ trace.should == [:first, :second, :third, :fourth]
49
+ end
50
+
51
+ it "blocks multiple Fibers until a value is ready" do
52
+ scope = AsyncScope.new do
53
+ task do
54
+ trace << :first
55
+ future.get
56
+ trace << :fifth
57
+ end
58
+
59
+ task do
60
+ trace << :second
61
+ future.get
62
+ trace << :sixth
63
+ end
64
+
65
+ task do
66
+ trace << :third
67
+ future.set(:foo)
68
+ trace << :fourth
69
+ end
70
+ end
71
+ scope.eventLoop
72
+ trace.should == [:first, :second, :third, :fourth, :fifth, :sixth]
73
+ end
74
+
75
+ it "supports wait_for_any" do
76
+ scope = AsyncScope.new do
77
+ f1 = Future.new
78
+ f2 = Future.new
79
+ f3 = Future.new
80
+ trace << :before_task
81
+ task do
82
+ trace << :before_set
83
+ f2.set("bar")
84
+ trace << :after_set
85
+ end
86
+ trace << :before_wait
87
+
88
+ f = Future.wait_for_any(f1, f2, f3).first
89
+ trace << :after_wait
90
+ f.should == f2
91
+ f.get.should == "bar"
92
+ end
93
+ trace.length.should == 0
94
+ scope.eventLoop
95
+ trace.should == [:before_task, :before_wait, :before_set, :after_set, :after_wait]
96
+ end
97
+
98
+ it "supports wait_for_any with all set" do
99
+ scope = AsyncScope.new do
100
+ f1 = Future.new
101
+ f2 = Future.new
102
+ f3 = Future.new
103
+ trace << :before_task
104
+ task do
105
+ trace << :before_set
106
+ f2.set("bar")
107
+ f1.set("baz")
108
+ f3.set("foo")
109
+ trace << :after_set
110
+ end
111
+ trace << :before_wait
112
+ r1, r2, r3 = Future.wait_for_any(f1, f2, f3)
113
+ trace << :after_wait
114
+ r1.should == f2
115
+ r1.get.should == "bar"
116
+ r2.should == f1
117
+ r2.get.should == "baz"
118
+ r3.should == f3
119
+ r3.get.should == "foo"
120
+ end
121
+ trace.length.should == 0
122
+ scope.eventLoop
123
+ trace.should == [:before_task, :before_wait, :before_set, :after_set, :after_wait]
124
+ end
125
+
126
+ it "supports wait_for_all" do
127
+ scope = AsyncScope.new do
128
+ f1 = Future.new
129
+ f2 = Future.new
130
+ f3 = Future.new
131
+ trace << :before_task
132
+ task do
133
+ trace << :before_f2_set
134
+ f2.set("bar")
135
+ task do
136
+ trace << :before_f1_set
137
+ f1.set("baz")
138
+ task do
139
+ trace << :before_f3_set
140
+ f3.set("foo")
141
+ trace << :after_set
142
+ end
143
+ end
144
+ end
145
+ trace << :before_wait
146
+ r1, r2, r3 = Future.wait_for_all(f1, f2, f3)
147
+ trace << :after_wait
148
+ r1.should == f2
149
+ r1.get.should == "bar"
150
+ r2.should == f1
151
+ r2.get.should == "baz"
152
+ r3.should == f3
153
+ r3.get.should == "foo"
154
+ end
155
+ trace.length.should == 0
156
+ scope.eventLoop
157
+ trace.should == [:before_task, :before_wait, :before_f2_set, :before_f1_set, :before_f3_set, :after_set, :after_wait]
158
+ end
159
+
160
+ it "supports wait_for_all with no futures" do
161
+ scope = AsyncScope.new do
162
+ task do
163
+ wait_for_all
164
+ end
165
+ end
166
+ scope.eventLoop
167
+ scope.is_complete?.should == true
168
+ end
169
+
170
+ it "supports wait_for_any with no futures" do
171
+ scope = AsyncScope.new do
172
+ task do
173
+ wait_for_any
174
+ end
175
+ end
176
+ scope.eventLoop
177
+ scope.is_complete?.should == true
178
+ end
179
+
180
+ it "supports wait_for_all with a set future" do
181
+ scope = AsyncScope.new do
182
+ future = Future.new.set
183
+ wait_for_all(future)
184
+ end
185
+ scope.eventLoop
186
+ scope.is_complete?.should == true
187
+ end
188
+
189
+ it "supports wait_for_any with a set future" do
190
+ scope = AsyncScope.new do
191
+ future = Future.new.set
192
+ wait_for_any(future)
193
+ end
194
+ scope.eventLoop
195
+ scope.is_complete?.should == true
196
+ end
197
+
198
+ it "supports wait_for_all with one set future and one not set" do
199
+ future2 = Future.new
200
+ scope = AsyncScope.new do
201
+ future = Future.new.set
202
+ wait_for_all(future, future2)
203
+ end
204
+ scope.eventLoop
205
+ future2.set
206
+ scope.eventLoop
207
+ scope.is_complete?.should == true
208
+ end
209
+
210
+ end
@@ -274,12 +274,16 @@ describe "RubyFlowDecider" do
274
274
  end
275
275
  end
276
276
  class SubsequentWorkflow
277
- extend Decider
277
+ extend Workflows
278
+ workflow :entry_point do
279
+ {
280
+ :version => "1",
281
+ }
282
+ end
278
283
  version "1"
279
284
  activity_client :activity do |options|
280
285
  options.prefix_name = "SubsequentActivity"
281
286
  end
282
- entry_point :entry_point
283
287
  def entry_point
284
288
  activity.run_activity1
285
289
  activity.run_activity2
@@ -294,9 +298,18 @@ describe "RubyFlowDecider" do
294
298
  worker.register
295
299
  activity_worker.register
296
300
  sleep 3
297
- workflow_id = "basic_subsequent_activities"
298
- run_id = @swf.client.start_workflow_execution(:execution_start_to_close_timeout => "3600", :task_list => {:name => task_list}, :task_start_to_close_timeout => "3600", :child_policy => "REQUEST_CANCEL", :workflow_type => {:name => workflow_type_name, :version => "1"}, :workflow_id => workflow_id, :domain => @domain.name.to_s)
299
- workflow_execution = AWS::SimpleWorkflow::WorkflowExecution.new(@domain, workflow_id, run_id["runId"])
301
+
302
+
303
+ my_workflow_client = workflow_client(@swf.client, @domain) do
304
+ {
305
+ :from_class => "SubsequentWorkflow",
306
+ :execution_start_to_close_timeout => "3600",
307
+ :task_list => task_list,
308
+ :task_start_to_close_timeout => "3600",
309
+ :child_policy => "REQUEST_CANCEL",
310
+ }
311
+ end
312
+ workflow_execution = my_workflow_client.start_execution
300
313
  worker.run_once
301
314
  activity_worker.run_once
302
315
  worker.run_once
@@ -510,6 +523,29 @@ describe "RubyFlowDecider" do
510
523
  @my_workflow_client = workflow_client(@swf.client, @domain) { {:from_class => @workflow_class} }
511
524
  end
512
525
 
526
+ it "ensures that an activity returning more than 32k data fails the activity" do
527
+ general_test(:task_list => "ActivityTaskLargeOutput", :class_name => "ActivityTaskLargeOutput")
528
+ @activity_class.class_eval do
529
+ def run_activity1
530
+ # Make sure we return something that's over 32k. Note this won't
531
+ # necessarily work with all converters, as it's pretty trivially
532
+ # compressible
533
+ return "a" * 33000
534
+ end
535
+ end
536
+ workflow_execution = @my_workflow_client.start_execution
537
+ @worker.run_once
538
+ @activity_worker.run_once
539
+ @worker.run_once
540
+ history_events = workflow_execution.events.map(&:event_type)
541
+ # Previously, it would time out, as the failure would include the original
542
+ # large output that killed the completion call. Thus, we need to check that
543
+ # we fail the ActivityTask correctly.
544
+ history_events.should include "ActivityTaskFailed"
545
+ history_events.last.should == "WorkflowExecutionFailed"
546
+
547
+ end
548
+
513
549
  it "ensures that not filling in details/reason for activity_task_failed is handled correctly" do
514
550
  general_test(:task_list => "ActivityTaskFailedManually", :class_name => "ActivityTaskFailedManually")
515
551
  $task_token = nil
@@ -1274,7 +1310,7 @@ describe "RubyFlowDecider" do
1274
1310
  end
1275
1311
  entry_point :entry_point
1276
1312
  def entry_point(arg)
1277
- my_workflow_factory = workflow_factory($swf.client, $domain) do |options|
1313
+ client = workflow_client do |options|
1278
1314
  options.workflow_name = "OtherChildWorkflow"
1279
1315
  options.execution_method = "entry_point"
1280
1316
  options.execution_start_to_close_timeout = 3600
@@ -1282,7 +1318,7 @@ describe "RubyFlowDecider" do
1282
1318
  options.version = "1"
1283
1319
  options.task_list = "test2"
1284
1320
  end
1285
- client = my_workflow_factory.get_client
1321
+
1286
1322
  client.send_async(:start_execution, 5)
1287
1323
  client.send_async(:start_execution, 5)
1288
1324
  end
@@ -1306,6 +1342,7 @@ describe "RubyFlowDecider" do
1306
1342
 
1307
1343
  # Start, start off the child workflow
1308
1344
  worker.run_once
1345
+
1309
1346
  # Run Both child workflows
1310
1347
  worker2.run_once
1311
1348
  worker2.run_once
@@ -1315,6 +1352,7 @@ describe "RubyFlowDecider" do
1315
1352
  # In order to deal with this, we have the following line below
1316
1353
  worker.run_once if workflow_execution.events.map(&:event_type).last == "DecisionTaskCompleted"
1317
1354
  events = workflow_execution.events.map(&:event_type)
1355
+ workflow_execution.events.to_a.last.attributes.result.should_not =~ /secret_access_key/
1318
1356
  events.should include "ChildWorkflowExecutionStarted"
1319
1357
  events.should include "ChildWorkflowExecutionCompleted"
1320
1358
  events.should include "WorkflowExecutionCompleted"
@@ -1575,9 +1613,9 @@ describe "RubyFlowDecider" do
1575
1613
  activity :run_activity1 do |options|
1576
1614
  options.version = "1"
1577
1615
  options.default_task_list = "exponential_test_return_task_list"
1578
- options.default_task_schedule_to_close_timeout = "5"
1579
- options.default_task_schedule_to_start_timeout = "5"
1580
- options.default_task_start_to_close_timeout = "5"
1616
+ options.default_task_schedule_to_close_timeout = "15"
1617
+ options.default_task_schedule_to_start_timeout = "15"
1618
+ options.default_task_start_to_close_timeout = "15"
1581
1619
  options.default_task_heartbeat_timeout = "3600"
1582
1620
  end
1583
1621
  def run_activity1
@@ -1629,50 +1667,50 @@ describe "RubyFlowDecider" do
1629
1667
  workflow_execution = client.start_execution
1630
1668
  worker.run_once
1631
1669
  activity_worker.run_once
1632
-
1670
+ activity_worker.run_once unless workflow_execution.events.map(&:event_type).include? "ActivityTaskCompleted"
1633
1671
  worker.run_once
1634
1672
  workflow_execution.events.map(&:event_type).count("WorkflowExecutionCompleted").should == 1
1635
-
1636
1673
  end
1637
1674
 
1638
1675
  it "makes sure that signals work correctly" do
1639
1676
  class SignalWorkflow
1640
- class << self
1641
- attr_accessor :task_list, :trace
1677
+ extend Workflows
1678
+ workflow :entry_point do
1679
+ {
1680
+ :version => "1"
1681
+ }
1642
1682
  end
1643
- @trace = []
1644
- extend Decider
1645
- version "1"
1646
- def this_signal
1683
+ def this_signal(input)
1647
1684
  @wait.broadcast
1685
+ @input = input
1648
1686
  end
1649
1687
  signal :this_signal
1650
- entry_point :entry_point
1651
1688
  def entry_point
1689
+ @input = "bad_input"
1652
1690
  @wait ||= FiberConditionVariable.new
1653
1691
  @wait.wait
1692
+ @input.should =~ /new input!/
1654
1693
  end
1655
1694
  end
1656
1695
  task_list = "SignalWorkflow_tasklist"
1657
1696
  worker = WorkflowWorker.new(@swf.client, @domain, task_list)
1658
1697
  worker.add_workflow_implementation(SignalWorkflow)
1659
1698
  worker.register
1660
- my_workflow_factory = workflow_factory(@swf.client, @domain) do |options|
1699
+ my_workflow_client = workflow_client(@swf.client, @domain) do |options|
1661
1700
  options.workflow_name = "SignalWorkflow"
1662
1701
  options.execution_start_to_close_timeout = 3600
1663
1702
  options.task_list = task_list
1664
1703
  options.task_start_to_close_timeout = 10
1665
1704
  options.child_policy = :request_cancel
1666
1705
  end
1667
- my_workflow = my_workflow_factory.get_client
1668
1706
  sleep 3
1669
- workflow_execution = my_workflow.start_execution
1707
+ workflow_execution = my_workflow_client.start_execution
1670
1708
  forking_executor = ForkingExecutor.new(:max_workers => 2)
1671
1709
  worker.run_once
1672
- my_workflow.signal_workflow_execution("this_signal", workflow_execution)
1710
+
1711
+ my_workflow_client.signal_workflow_execution("this_signal", workflow_execution) { {:input => "new input!"}}
1673
1712
  worker.run_once
1674
1713
  forking_executor.shutdown(1)
1675
-
1676
1714
  workflow_execution.events.map(&:event_type).count("WorkflowExecutionCompleted").should == 1
1677
1715
  end
1678
1716
 
@@ -1931,7 +1969,6 @@ describe "RubyFlowDecider" do
1931
1969
  options.default_task_start_to_close_timeout = "3600"
1932
1970
  end
1933
1971
  def run_activity1(arg)
1934
- arg.should == 5
1935
1972
  arg + 1
1936
1973
  end
1937
1974
  def run_activity2(arg)
@@ -1942,7 +1979,7 @@ describe "RubyFlowDecider" do
1942
1979
  end
1943
1980
  end
1944
1981
  # Definition of the workflow logic
1945
- class MyWorkflow
1982
+ class ParallelWorkflow
1946
1983
  extend Decider
1947
1984
  version "1"
1948
1985
  activity_client :activity do |options|
@@ -1983,15 +2020,15 @@ describe "RubyFlowDecider" do
1983
2020
  task_list = "parallel_split_task_list"
1984
2021
  # @swf and @domain are set beforehand with the aws ruby sdk
1985
2022
  worker = WorkflowWorker.new(@swf.client, @domain, task_list)
1986
- worker.add_workflow_implementation(MyWorkflow)
1987
- activity_worker = ActivityWorker.new(@swf.client, @domain, task_list)
2023
+ worker.add_workflow_implementation(ParallelWorkflow)
2024
+ activity_worker = ActivityWorker.new(@swf.client, @domain, task_list) { {:use_forking => false}}
1988
2025
  activity_worker.add_activities_implementation(ParallelSplitActivity)
1989
2026
  worker.register
1990
2027
  activity_worker.register
1991
2028
 
1992
2029
  # Get a workflow client to start the workflow
1993
2030
  my_workflow_factory = workflow_factory @swf.client, @domain do |options|
1994
- options.workflow_name = "MyWorkflow"
2031
+ options.workflow_name = "ParallelWorkflow"
1995
2032
  options.execution_start_to_close_timeout = 3600
1996
2033
  options.task_list = task_list
1997
2034
  options.task_start_to_close_timeout = 10
@@ -2019,6 +2056,7 @@ describe "RubyFlowDecider" do
2019
2056
  # Sleep to give the threads some time to compute, as we'll run right out of
2020
2057
  # the test before they can run otherwise
2021
2058
  sleep 50
2059
+ p workflow_execution.events.to_a
2022
2060
  workflow_execution.events.map(&:event_type).count("WorkflowExecutionCompleted").should == 1
2023
2061
  end
2024
2062
 
@@ -2159,10 +2197,15 @@ describe "RubyFlowDecider" do
2159
2197
 
2160
2198
  it "ensures you cannot schedule more than 99 things in one decision" do
2161
2199
  general_test(:task_list => "schedule_more_than_100", :class_name => "Above100TasksScheduled")
2200
+ @activity_class.class_eval do
2201
+ def run_activity1(arg)
2202
+ arg
2203
+ end
2204
+ end
2162
2205
  @workflow_class.class_eval do
2163
2206
  def entry_point
2164
- 101.times do
2165
- activity.send_async(:run_activity1)
2207
+ 101.times do |i|
2208
+ activity.send_async(:run_activity1, i)
2166
2209
  end
2167
2210
  end
2168
2211
  end
@@ -2223,7 +2266,7 @@ describe "RubyFlowDecider" do
2223
2266
  "did some work in run_activity1"
2224
2267
  end
2225
2268
  end
2226
- class MyWorkflow
2269
+ class TimeoutWorkflow
2227
2270
  extend Decider
2228
2271
  version "1"
2229
2272
  activity_client :activity do |options|
@@ -2234,17 +2277,18 @@ describe "RubyFlowDecider" do
2234
2277
  activity.run_activity1
2235
2278
  end
2236
2279
  end
2237
- worker = WorkflowWorker.new(@swf.client, @domain, "timeout_test", MyWorkflow)
2280
+ worker = WorkflowWorker.new(@swf.client, @domain, "timeout_test", TimeoutWorkflow)
2238
2281
  activity_worker = ActivityWorker.new(@swf.client, @domain, "timeout_test", TimeoutActivity)
2239
2282
  worker.register
2240
2283
  activity_worker.register
2241
2284
  my_workflow_factory = workflow_factory @swf.client, @domain do |options|
2242
- options.workflow_name = "MyWorkflow"
2285
+ options.workflow_name = "TimeoutWorkflow"
2243
2286
  options.execution_start_to_close_timeout = 3600
2287
+ options.task_start_to_close_timeout = 5
2244
2288
  options.task_list = "timeout_test"
2245
2289
  end
2246
2290
  my_workflow_client = my_workflow_factory.get_client
2247
- num_tests = 50
2291
+ num_tests = 30
2248
2292
  workflow_executions = []
2249
2293
  1.upto(num_tests) { |i| workflow_executions << my_workflow_client.entry_point }
2250
2294
  forking_executor = ForkingExecutor.new(:max_workers => 3)
@@ -2252,6 +2296,7 @@ describe "RubyFlowDecider" do
2252
2296
  forking_executor.execute { activity_worker.start }
2253
2297
  sleep 60
2254
2298
  failed_executions = workflow_executions.each{|x| x.events.to_a.last.event_type.should == "WorkflowExecutionCompleted" }
2299
+
2255
2300
  end
2256
2301
  end
2257
2302
 
@@ -2273,7 +2318,7 @@ describe "RubyFlowDecider" do
2273
2318
  version "1"
2274
2319
  entry_point :entry_point
2275
2320
  def entry_point(arg)
2276
- my_workflow_factory = workflow_factory($swf_client, $domain) do |options|
2321
+ client = workflow_client(@swf_client, @domain) do |options|
2277
2322
  options.workflow_name = "SendAsyncWorkflow"
2278
2323
  options.execution_method = "entry_point"
2279
2324
  options.execution_start_to_close_timeout = 3600
@@ -2281,7 +2326,6 @@ describe "RubyFlowDecider" do
2281
2326
  options.version = "1"
2282
2327
  options.task_list = "client_test_async2"
2283
2328
  end
2284
- client = my_workflow_factory.get_client
2285
2329
  client.send_async(:start_execution, arg) { {:task_start_to_close_timeout => 35 } }
2286
2330
  client.send_async(:start_execution, arg)
2287
2331
  end
@@ -2297,8 +2341,8 @@ describe "RubyFlowDecider" do
2297
2341
  end
2298
2342
  my_workflow_client = my_workflow_factory.get_client
2299
2343
  workflow_execution = my_workflow_client.entry_point(5)
2300
-
2301
2344
  worker.run_once
2345
+
2302
2346
  internal_worker.run_once
2303
2347
  internal_worker.run_once
2304
2348
  worker.run_once
@@ -2407,7 +2451,7 @@ describe "RubyFlowDecider" do
2407
2451
  end
2408
2452
 
2409
2453
  it "ensures that with_retry does asynchronous blocking correctly" do
2410
- general_test(:task_list => "with_retry_synch", :class_name => "WithRetrySynchronous")
2454
+ general_test(:task_list => "with_retry_synch", :class_name => "WithRetryAsynchronous")
2411
2455
  @workflow_class.class_eval do
2412
2456
  def entry_point
2413
2457
  with_retry do