weel 1.0.3

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.
Files changed (41) hide show
  1. data/AUTHORS +2 -0
  2. data/COPYING +504 -0
  3. data/FEATURES +20 -0
  4. data/INSTALL +7 -0
  5. data/README +4 -0
  6. data/Rakefile +15 -0
  7. data/example/SimpleHandlerWrapper.rb +68 -0
  8. data/example/SimpleWorkflow.rb +15 -0
  9. data/example/runme.rb +12 -0
  10. data/lib/weel.rb +749 -0
  11. data/test/ContinueTest.rb +25 -0
  12. data/test/TestHandlerWrapper.rb +120 -0
  13. data/test/TestWorkflow.rb +35 -0
  14. data/test/basic/tc_choose.rb +82 -0
  15. data/test/basic/tc_codereplace.rb +38 -0
  16. data/test/basic/tc_data.rb +32 -0
  17. data/test/basic/tc_endpoint.rb +40 -0
  18. data/test/basic/tc_handler.rb +19 -0
  19. data/test/basic/tc_parallel.rb +115 -0
  20. data/test/basic/tc_search.rb +37 -0
  21. data/test/basic/tc_state.rb +17 -0
  22. data/test/basic/tc_wf_control.rb +68 -0
  23. data/test/complex/tc_generalsynchonizingmerge_loopsearch.rb +113 -0
  24. data/test/complex/tc_parallel_stop.rb +32 -0
  25. data/test/wfp_adv_branching/tc_generalizedjoin.rb +11 -0
  26. data/test/wfp_adv_branching/tc_generalsynchronizingmerge.rb +45 -0
  27. data/test/wfp_adv_branching/tc_localsynchronizingmerge.rb +37 -0
  28. data/test/wfp_adv_branching/tc_multichoice_structuredsynchronizingmerge.rb +47 -0
  29. data/test/wfp_adv_branching/tc_multimerge.rb +11 -0
  30. data/test/wfp_adv_branching/tc_structured_discriminator.rb +28 -0
  31. data/test/wfp_adv_branching/tc_structured_partial_join.rb +41 -0
  32. data/test/wfp_adv_branching/tc_threadmerge.rb +11 -0
  33. data/test/wfp_adv_branching/tc_threadsplit.rb +11 -0
  34. data/test/wfp_basic/tc_exclusivechoice_simplemerge.rb +22 -0
  35. data/test/wfp_basic/tc_parallelsplit_synchronization.rb +26 -0
  36. data/test/wfp_basic/tc_sequence.rb +16 -0
  37. data/test/wfp_iteration/tc_structuredloop.rb +65 -0
  38. data/test/wfp_state_based/tc_deferredchoice.rb +38 -0
  39. data/test/wfp_state_based/tc_interleavedparallelrouting.rb +30 -0
  40. data/weel.gemspec +25 -0
  41. metadata +127 -0
@@ -0,0 +1,25 @@
1
+ vim ./wfp_state_based/tc_interleavedparallelrouting.rb
2
+ vim ./wfp_state_based/tc_deferredchoice.rb
3
+ vim ./wfp_iteration/tc_structuredloop.rb
4
+ vim ./wfp_adv_branching
5
+ vim ./wfp_adv_branching/tc_multichoice_structuredsynchronizingmerge.rb
6
+ vim ./wfp_adv_branching/tc_generalsynchronizingmerge.rb
7
+ vim ./wfp_adv_branching/tc_localsynchronizingmerge.rb
8
+ vim ./wfp_adv_branching/tc_threadmerge.rb
9
+ vim ./wfp_adv_branching/tc_generalizedjoin.rb
10
+ vim ./wfp_adv_branching/tc_threadsplit.rb
11
+ vim ./wfp_adv_branching/tc_multimerge.rb
12
+ vim ./wfp_adv_branching/tc_structured_discriminator.rb
13
+ vim ./wfp_adv_branching/tc_structured_partial_join.rb
14
+ vim ./basic/tc_codereplace.rb
15
+ vim ./basic/tc_data.rb
16
+ vim ./basic/tc_handler.rb
17
+ vim ./basic/tc_parallel.rb
18
+ vim ./basic/tc_search.rb
19
+ vim ./basic/tc_endpoint.rb
20
+ vim ./basic/tc_wf_control.rb
21
+ vim ./basic/tc_choose.rb
22
+ vim ./basic/tc_state.rb
23
+ vim ./wfp_basic/tc_exclusivechoice_simplemerge.rb
24
+ vim ./wfp_basic/tc_sequence.rb
25
+ vim ./wfp_basic/tc_parallelsplit_synchronization.rb
@@ -0,0 +1,120 @@
1
+ class TestHandlerWrapper < WEEL::HandlerWrapperBase
2
+ def initialize(args,endpoint=nil,position=nil,continue=nil)
3
+ @__myhandler_stopped = false
4
+ @__myhandler_position = position
5
+ @__myhandler_continue = continue
6
+ @__myhandler_endpoint = endpoint
7
+ @__myhandler_returnValue = nil
8
+ end
9
+
10
+ # executes a ws-call to the given endpoint with the given parameters. the call
11
+ # can be executed asynchron, see finished_call & return_value
12
+ def activity_handle(passthrough, parameters)
13
+ $long_track << "CALL #{@__myhandler_position}: passthrough=[#{passthrough}], endpoint=[#{@__myhandler_endpoint}], parameters=[#{parameters.inspect}]\n"
14
+ $short_track << "C#{@__myhandler_position}"
15
+
16
+ if @__myhandler_endpoint == 'stop it'
17
+ raise WEEL::Signal::Stop
18
+ end
19
+ if parameters[:call]
20
+ @t = Thread.new do
21
+ parameters[:call].call
22
+ @__myhandler_returnValue = parameters.has_key?(:result) ? parameters[:result] : 'Handler_Dummy_Result'
23
+ @__myhandler_continue.continue
24
+ end
25
+ # give nothing back
26
+ else
27
+ @__myhandler_returnValue = parameters.has_key?(:result) ? parameters[:result] : 'Handler_Dummy_Result'
28
+ @__myhandler_continue.continue
29
+ end
30
+ end
31
+
32
+ # returns the result of the last handled call
33
+ def activity_result_value
34
+ @__myhandler_returnValue
35
+ end
36
+ # Called if the WS-Call should be interrupted. The decision how to deal
37
+ # with this situation is given to the handler. To provide the possibility
38
+ # of a continue the Handler will be asked for a passthrough
39
+ def activity_stop
40
+ $long_track += "STOPPED #{@__myhandler_position}\n"
41
+ $short_track << "S#{@__myhandler_position}"
42
+ @t.exit if @t
43
+ @__myhandler_stopped = true
44
+ end
45
+ # is called from WEEL after stop_call to ask for a passthrough-value that may give
46
+ # information about how to continue the call. This passthrough-value is given
47
+ # to activity_handle if the workflow is configured to do so.
48
+ def activity_passthrough_value
49
+ "SOME passthrough"
50
+ end
51
+
52
+ # Called if the execution of the actual activity_handle is not necessary anymore
53
+ # It is definit that the call will not be continued.
54
+ # At this stage, this is only the case if parallel branches are not needed
55
+ # anymore to continue the workflow
56
+ def activity_no_longer_necessary
57
+ $long_track += "NO_LONGER_NECCESARY #{@__myhandler_position}\n"
58
+ $short_track << "NLN#{@__myhandler_position}"
59
+ @t.exit if @t
60
+ @__myhandler_returnValue = "No longer necessary"
61
+ @__myhandler_stopped = true
62
+ end
63
+ # Is called if a Activity is executed correctly
64
+ def inform_activity_manipulate
65
+ $long_track += "MANIPULATE #{@__myhandler_position}\n"
66
+ $short_track << "M#{@__myhandler_position}"
67
+ end
68
+ # Is called if a Activity is executed correctly
69
+ def inform_activity_done
70
+ $long_track += "DONE #{@__myhandler_position}\n"
71
+ $short_track << "D#{@__myhandler_position}"
72
+ end
73
+ # Is called if a Activity is executed with an error
74
+ def inform_activity_failed(err)
75
+ $long_track += "FAILED #{@__myhandler_position}: #{err}\n"
76
+ $short_track << "F#{@__myhandler_position}"
77
+ raise(err)
78
+ end
79
+ def inform_syntax_error(err,code)
80
+ $long_track += "ERROR: Syntax messed with error #{err}\n"
81
+ $short_track << "E"
82
+ raise(err)
83
+ end
84
+ def inform_state_change(newstate)
85
+ $long_track += "---> STATE #{newstate}\n"
86
+ $short_track << "|#{newstate}|"
87
+ end
88
+ end
89
+
90
+ module TestMixin #{{{
91
+ def setup
92
+ $long_track = ""
93
+ $short_track = ""
94
+ @wf = TestWorkflow.new
95
+ end
96
+
97
+ def teardown
98
+ @wf.stop.join
99
+ $long_track = ""
100
+ $short_track = ""
101
+ end
102
+
103
+ def wf_assert(what,cond=true)
104
+ if cond
105
+ assert($long_track.include?(what),"Missing \"#{what}\":\n#{$long_track}")
106
+ else
107
+ assert(!$long_track.include?(what),"Missing \"#{what}\":\n#{$long_track}")
108
+ end
109
+ end
110
+ def wf_sassert(what,cond=true)
111
+ if cond
112
+ assert($short_track.include?(what),"#{$short_track}\nNot Present \"#{what}\":\n#{$long_track}")
113
+ else
114
+ assert(!$short_track.include?(what),"#{$short_track}\nNot Present \"#{what}\":\n#{$long_track}")
115
+ end
116
+ end
117
+ def wf_rsassert(pat='')
118
+ assert($short_track =~ /#{pat}/,"Somehow executed different #{$short_track} should be '#{pat}'")
119
+ end
120
+ end #}}}
@@ -0,0 +1,35 @@
1
+ require File.expand_path(::File.dirname(__FILE__) + '/../lib/weel')
2
+ require File.expand_path(::File.dirname(__FILE__) + '/TestHandlerWrapper')
3
+
4
+ class TestWorkflow < WEEL
5
+ handlerwrapper TestHandlerWrapper
6
+
7
+ endpoint :endpoint1 => 'http://www.heise.de'
8
+ endpoint :stop => 'stop it'
9
+ data :x => 'begin_'
10
+
11
+ control flow do
12
+ activity :a1_1, :call, :endpoint1 do |result|
13
+ data.x += "#{result}"
14
+ end
15
+ parallel :wait => 2 do
16
+ parallel_branch do
17
+ activity :a2_1_1, :call, :endpoint1
18
+ end
19
+ parallel_branch do
20
+ activity :a2_2_1, :call, :endpoint1
21
+ end
22
+ end
23
+ activity :a3, :manipulate do
24
+ data.x += '_end'
25
+ end
26
+ choose do
27
+ alternative data.x != nil do
28
+ activity :a4a, :call, :endpoint1
29
+ end
30
+ otherwise do
31
+ activity :a4b, :call, :endpoint1
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,82 @@
1
+ require 'test/unit'
2
+ require File.expand_path(::File.dirname(__FILE__) + '/../TestWorkflow')
3
+
4
+ class TestChoose < Test::Unit::TestCase
5
+ include TestMixin
6
+
7
+ def test_choose_alternative
8
+ @wf.description do
9
+ choose do
10
+ alternative true do
11
+ activity :a_1, :call, :endpoint1
12
+ end
13
+ alternative false do
14
+ activity :a_2, :call, :endpoint1
15
+ end
16
+ otherwise do
17
+ activity :a_3, :call, :endpoint1
18
+ end
19
+ end
20
+ end
21
+ @wf.start.join
22
+ wf_assert("CALL a_1: passthrough=[], endpoint=[http://www.heise.de], parameters=[{}]")
23
+ wf_assert("CALL a_2:",false)
24
+ wf_assert("CALL a_3:",false)
25
+ end
26
+
27
+ def test_choose_otherwise
28
+ @wf.description do
29
+ choose do
30
+ alternative false do
31
+ activity :a_1, :call, :endpoint1
32
+ end
33
+ otherwise do
34
+ activity :a_2, :call, :endpoint1
35
+ end
36
+ end
37
+ end
38
+ @wf.start.join
39
+ wf_assert("CALL a_2: passthrough=[], endpoint=[http://www.heise.de], parameters=[{}]")
40
+ wf_assert("CALL a_1:",false)
41
+ end
42
+
43
+ def test_choose_nested
44
+ @wf.description do
45
+ choose do
46
+ alternative true do
47
+ choose do
48
+ alternative false do
49
+ activity :a_1_1, :call, :endpoint1
50
+ end
51
+ alternative true do
52
+ choose do
53
+ alternative false do
54
+ activity :a_1_1_1, :call, :endpoint1
55
+ end
56
+ otherwise do
57
+ activity :a_1_1_2, :call, :endpoint1
58
+ end
59
+ end
60
+ end
61
+ otherwise do
62
+ activity :a_1_3, :call, :endpoint1
63
+ end
64
+ end
65
+ end
66
+ otherwise do
67
+ activity :a_2, :call, :endpoint1
68
+ end
69
+ end
70
+ end
71
+ @wf.start.join
72
+ wf_assert("CALL a_1_1_2: passthrough=[], endpoint=[http://www.heise.de], parameters=[{}]",true)
73
+ wf_assert("CALL a_1_1:",false)
74
+ wf_assert("CALL a_1_1_1:",false)
75
+ wf_assert("CALL a_1_3:",false)
76
+ wf_assert("CALL a_2:",false)
77
+ end
78
+
79
+ def test_choose_searchmode
80
+
81
+ end
82
+ end
@@ -0,0 +1,38 @@
1
+ require 'test/unit'
2
+ require File.expand_path(::File.dirname(__FILE__) + '/../TestWorkflow')
3
+
4
+ class TestCodeReplace < Test::Unit::TestCase
5
+ include TestMixin
6
+
7
+ def test_replace
8
+ @wf.description do
9
+ activity :a_test_1_1, :call, :endpoint1
10
+ activity :a_test_1_2, :call, :endpoint1
11
+ activity :a_test_1_3, :call, :endpoint1
12
+ end
13
+ @wf.search WEEL::Position.new(:a_test_1_1, :at)
14
+ @wf.start.join
15
+ wf_assert("CALL a_test_1_1:")
16
+ wf_assert("CALL a_test_1_2:")
17
+ wf_assert("CALL a_test_1_3:")
18
+ wf_sassert("|running|Ca_test_1_1Da_test_1_1Ca_test_1_2Da_test_1_2Ca_test_1_3Da_test_1_3|finished|")
19
+ end
20
+ #def test_wfdescription_string
21
+ # ret = @wf.description "activity :b_test_1_1, :call, :endpoint1"
22
+ # @wf.search WEEL::Position.new(:b_test_1_1, :at)
23
+ # @wf.start.join
24
+ # wf_assert("DONE b_test_1_1")
25
+ # wf_sassert("|running|Cb_test_1_1Db_test_1_1|finished|")
26
+ #end
27
+ def test_wfdescription_block
28
+ ret = @wf.description do
29
+ activity :c_test_1_1, :call, :endpoint1
30
+ activity :c_test_1_2, :call, :endpoint1
31
+ end
32
+
33
+ assert(ret.class == Proc, "wf_description should be nil => not available. codeblock was given!")
34
+ @wf.search WEEL::Position.new(:c_test_1_2, :at)
35
+ @wf.start.join
36
+ wf_sassert("|running|Cc_test_1_2Dc_test_1_2|finished|")
37
+ end
38
+ end
@@ -0,0 +1,32 @@
1
+ require 'test/unit'
2
+ require File.expand_path(::File.dirname(__FILE__) + '/../TestWorkflow')
3
+
4
+ class TestData < Test::Unit::TestCase
5
+ include TestMixin
6
+
7
+ def test_check_data
8
+ data = @wf.data
9
+ assert(data.is_a?(Hash), "data is not a Hash")
10
+ assert(data.size == 1, "data has not exactly 1 element, it has #{data.size}")
11
+ assert(data.keys[0] == :x, "data.keys[0] has not the correct value [#{data.keys[0]}]")
12
+ assert(data[:x] == "begin_", "data[:x] has not the correct value")
13
+ end
14
+ def test_set_data_variable
15
+ @wf.data[:a] = "test1"
16
+ data = @wf.data
17
+ assert(data.is_a?(Hash), "data is not a Hash")
18
+ assert(data.keys.include?(:a), "data has no key :a")
19
+ assert(data[:a] == "test1", "data[:a] has not the correct value [#{data[:x]}]")
20
+ end
21
+ def test_set_data
22
+ @wf.data[:x] = "test1"
23
+ @wf.data[:y] = "test2"
24
+ data = @wf.data
25
+ assert(data.is_a?(Hash), "data is not a Hash")
26
+ assert(data.size == 2, "data has not exactly 1 element, it has #{data.size}")
27
+ assert(data.keys.include?(:x), "data has no key x")
28
+ assert(data.keys.include?(:y), "data has no key y")
29
+ assert(data[:x] == "test1", "data[:x] has not the correct value [#{data[:x]}]")
30
+ assert(data[:y] == "test2", "data[:y] has not the correct value [#{data[:y]}]")
31
+ end
32
+ end
@@ -0,0 +1,40 @@
1
+ require 'test/unit'
2
+ require File.expand_path(::File.dirname(__FILE__) + '/../TestWorkflow')
3
+
4
+ class TestEndpoint < Test::Unit::TestCase
5
+ include TestMixin
6
+
7
+ def test_check_endpoint
8
+ ep1 = @wf.endpoints[:endpoint1]
9
+ assert(ep1.is_a?(String), "Endpoint1 is no string but should be")
10
+ assert(ep1 == "http://www.heise.de", "Endpoint1 has wrong value [#{ep1}]")
11
+ end
12
+ def test_create_endpoint
13
+ @wf.endpoint :endpoint2 => "http://www.test.at"
14
+ ep2 = @wf.endpoints[:endpoint2]
15
+ assert(ep2.is_a?(String), "Endpoint1 is no string but should be")
16
+ assert(ep2 == "http://www.test.at", "Endpoint1 has wrong value [#{ep2}]")
17
+ end
18
+ def test_change_endpoint
19
+ @wf.endpoint :endpoint1 => "http://www.newpoint.com"
20
+ ep1 = @wf.endpoints[:endpoint1]
21
+ assert(ep1.is_a?(String), "Endpoint1 is no string but should be")
22
+ assert(ep1 == "http://www.newpoint.com", "Endpoint1 has wrong value [#{ep1}]")
23
+ end
24
+ def test_change_endpoint2
25
+ @wf.endpoints[:endpoint1] = "http://www.newpoint2.com"
26
+ ep1 = @wf.endpoints[:endpoint1]
27
+ assert(ep1.is_a?(String), "Endpoint1 is no string but should be")
28
+ assert(ep1 == "http://www.newpoint2.com", "Endpoint1 has wrong value [#{ep1}]")
29
+ end
30
+
31
+ def test_endpoints
32
+ @wf.endpoint :endpoint2 => "http://www.test.at" # asure that there is endpoint1 & endpoint2
33
+ @wf.endpoints[:endpoint1]="http://www.test2.com" # asure that ep1 has original value
34
+ eps = @wf.endpoints
35
+ assert(eps.is_a?(Hash), "Endpoints should result a Hash but returns a #{eps.class}")
36
+ assert(eps.size == 3, "Endpoints should have two entries: #{eps.inspect}")
37
+ assert(eps[:endpoint1] == "http://www.test2.com", "Endpoint 1 has wrong value or does not exist: #{eps.inspect}")
38
+ assert(eps[:endpoint2] == "http://www.test.at", "Endpoint 2 has wrong value or does not exist: #{eps.inspect}")
39
+ end
40
+ end
@@ -0,0 +1,19 @@
1
+ require 'test/unit'
2
+ require File.expand_path(::File.dirname(__FILE__) + '/../TestWorkflow')
3
+
4
+ class TestCaseHandler < Test::Unit::TestCase
5
+ include TestMixin
6
+
7
+ def test_handler
8
+ assert_raise RuntimeError do
9
+ @wf.handlerwrapper = String
10
+ end
11
+ assert_nothing_raised do
12
+ @wf.handlerwrapper = TestHandlerWrapper
13
+ end
14
+ end
15
+ def test_handlerargs
16
+ @wf.handlerwrapper_args = ["1", "2"]
17
+ assert(@wf.handlerwrapper_args.is_a?(Array), "Handler arguments is not an array, it is a #{@wf.handlerwrapper_args.inspect}")
18
+ end
19
+ end
@@ -0,0 +1,115 @@
1
+ require 'test/unit'
2
+ require File.expand_path(::File.dirname(__FILE__) + '/../TestWorkflow')
3
+
4
+ class TestParallel < Test::Unit::TestCase
5
+ include TestMixin
6
+
7
+ def test_parallel_simple
8
+ @wf.description do
9
+ parallel do
10
+ parallel_branch do
11
+ activity :a_1, :call, :endpoint1, :call => Proc.new{ sleep 0.5 }
12
+ end
13
+ parallel_branch do
14
+ activity :a_2, :call, :endpoint1, :call => Proc.new{ sleep 0.5 }
15
+ end
16
+ parallel_branch do
17
+ activity :a_3, :call, :endpoint1, :call => Proc.new{ sleep 0.5 }
18
+ end
19
+ end
20
+ end
21
+ wf = @wf.start
22
+ sleep(0.25)
23
+ wf_assert("CALL a_1:")
24
+ wf_assert("CALL a_2:")
25
+ wf_assert("CALL a_3:")
26
+ wf.join
27
+ wf_assert("DONE a_1")
28
+ wf_assert("DONE a_2")
29
+ wf_assert("DONE a_3")
30
+ end
31
+ def test_parallel_wait
32
+ @wf.description do
33
+ parallel :wait do
34
+ parallel_branch do
35
+ activity :a_1, :call, :endpoint1
36
+ end
37
+ parallel_branch do
38
+ activity :a_2, :call, :endpoint1, :call => Proc.new{ sleep 0.5 }
39
+ end
40
+ end
41
+ activity :a_3, :call, :endpoint1
42
+ end
43
+ @wf.start.join
44
+ wf_assert('CALL a_1')
45
+ wf_assert('DONE a_1')
46
+ wf_assert('CALL a_2')
47
+ wf_sassert('Da_2Ca_3Da_3|finished|')
48
+ end
49
+ def test_parallel_nowait
50
+ @wf.description do
51
+ parallel :wait => 1 do
52
+ parallel_branch do
53
+ activity :a_1, :call, :endpoint1
54
+ end
55
+ parallel_branch do
56
+ activity :a_2, :call, :endpoint1, :call => Proc.new{ sleep 8.5 }
57
+ end
58
+ end
59
+ activity :a_3, :call, :endpoint1
60
+ end
61
+ @wf.start.join
62
+ wf_assert('CALL a_1')
63
+ wf_assert('CALL a_2')
64
+ wf_sassert('NLNa_2Ca_3Da_3|finished|')
65
+ end
66
+ def test_parallel_no_longer_necessary
67
+ @wf.description do
68
+ parallel :wait => 1 do
69
+ parallel_branch do
70
+ activity :a_1, :call, :endpoint1
71
+ end
72
+ parallel_branch do
73
+ activity :a_2, :call, :endpoint1, :call => Proc.new{ sleep 0.5 }
74
+ activity :a_2_2, :call, :endpoint1
75
+ end
76
+ end
77
+ activity :a_3, :call, :endpoint1
78
+ end
79
+ @wf.start.join
80
+ wf_assert('CALL a_1')
81
+ wf_assert('CALL a_2')
82
+ wf_sassert('NLNa_2Ca_3Da_3|finished|')
83
+ end
84
+ def test_parallel_nested
85
+ # |- :a_1
86
+ # |-|-|- :a_2_1_1
87
+ # |-|-|- :a_2_1_2
88
+ # |-|-|- => :a_2_1_3
89
+ # |-|- :a_2_2
90
+ # |-|- :a_2_3
91
+ # |- => :a_3
92
+ @wf.description do
93
+ parallel :wait do
94
+ parallel_branch do activity :a_1, :call, :endpoint1 end
95
+ parallel_branch do
96
+ parallel :wait do
97
+ parallel_branch do
98
+ parallel :wait do
99
+ parallel_branch do activity :a_2_1_1, :call, :endpoint1, :call => Proc.new {sleep 0.2} end
100
+ parallel_branch do activity :a_2_1_2, :call, :endpoint1, :call => Proc.new {sleep 0.4} end
101
+ end
102
+ activity :a_2_1_3, :call, :endpoint1, :call => Proc.new {sleep 0.8}
103
+ end
104
+ parallel_branch do activity :a_2_2, :call, :endpoint1, :call => Proc.new {sleep 0.8} end
105
+ parallel_branch do activity :a_2_3, :call, :endpoint1, :call => Proc.new {sleep 1.0} end
106
+ end
107
+ end
108
+ end
109
+ activity :a_3, :call, :endpoint1
110
+ end
111
+ @wf.start.join
112
+ nump = $long_track.split("\n").delete_if{|e| !(e =~ /^(DONE)/)}
113
+ assert(nump == ["DONE a_1", "DONE a_2_1_1", "DONE a_2_1_2", "DONE a_2_2", "DONE a_2_3", "DONE a_2_1_3", "DONE a_3"], "not in the right order, sorry")
114
+ end
115
+ end