trailblazer-operation 0.0.13 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -3
- data/CHANGES.md +44 -0
- data/Gemfile +13 -2
- data/Rakefile +8 -6
- data/lib/trailblazer/operation.rb +86 -12
- data/lib/trailblazer/operation/deprecated_macro.rb +19 -0
- data/lib/trailblazer/operation/inject.rb +34 -0
- data/lib/trailblazer/operation/inspect.rb +80 -0
- data/lib/trailblazer/operation/public_call.rb +62 -0
- data/lib/trailblazer/operation/railway.rb +32 -0
- data/lib/trailblazer/operation/railway/fast_track.rb +13 -0
- data/lib/trailblazer/operation/railway/normalizer.rb +73 -0
- data/lib/trailblazer/operation/railway/task_builder.rb +44 -0
- data/lib/trailblazer/operation/result.rb +6 -4
- data/lib/trailblazer/operation/skill.rb +8 -24
- data/lib/trailblazer/operation/task_wrap.rb +68 -0
- data/lib/trailblazer/operation/trace.rb +49 -0
- data/lib/trailblazer/operation/variable_mapping.rb +91 -0
- data/lib/trailblazer/operation/version.rb +1 -1
- data/test/call_test.rb +27 -8
- data/test/class_dependencies_test.rb +16 -0
- data/test/docs/doormat_test.rb +189 -0
- data/test/docs/wiring_test.rb +421 -0
- data/test/dry_container_test.rb +4 -0
- data/test/fast_track_test.rb +197 -0
- data/test/gemfiles/Gemfile.ruby-2.0 +1 -2
- data/test/gemfiles/Gemfile.ruby-2.0.lock +40 -0
- data/test/inheritance_test.rb +1 -1
- data/test/inspect_test.rb +43 -0
- data/test/introspect_test.rb +50 -0
- data/test/macro_test.rb +61 -0
- data/test/operation_test.rb +94 -0
- data/test/result_test.rb +14 -8
- data/test/ruby-2.0.0/operation_test.rb +73 -0
- data/test/ruby-2.0.0/step_test.rb +136 -0
- data/test/skill_test.rb +66 -48
- data/test/step_test.rb +228 -0
- data/test/task_wrap_test.rb +91 -0
- data/test/test_helper.rb +37 -0
- data/test/trace_test.rb +62 -0
- data/test/variable_mapping_test.rb +66 -0
- data/test/wire_test.rb +113 -0
- data/test/wiring/defaults_test.rb +197 -0
- data/test/wiring/subprocess_test.rb +70 -0
- data/trailblazer-operation.gemspec +3 -5
- metadata +62 -36
- data/lib/trailblazer/operation/1.9.3/option.rb +0 -36
- data/lib/trailblazer/operation/generic.rb +0 -12
- data/lib/trailblazer/operation/option.rb +0 -54
- data/lib/trailblazer/operation/pipetree.rb +0 -142
- data/lib/trailblazer/skill.rb +0 -70
- data/test/2.0.0-pipetree_test.rb +0 -100
- data/test/2.1.0-pipetree_test.rb +0 -100
- data/test/operation_skill_test.rb +0 -89
- data/test/pipetree_test.rb +0 -185
@@ -0,0 +1,91 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "trailblazer/operation/inject" # an optional feature.com.
|
4
|
+
|
5
|
+
class TaskWrapTest < Minitest::Spec
|
6
|
+
MyMacro = ->( (options, *args), *) do
|
7
|
+
options["MyMacro.contract"] = options[:contract]
|
8
|
+
[ Trailblazer::Activity::Right, [options, *args] ]
|
9
|
+
end
|
10
|
+
|
11
|
+
class Create < Trailblazer::Operation
|
12
|
+
step :model!
|
13
|
+
# step [ MyMacro, { name: "MyMacro" }, { dependencies: { "contract" => :external_maybe } }]
|
14
|
+
step(
|
15
|
+
task: MyMacro,
|
16
|
+
id: "MyMacro",
|
17
|
+
|
18
|
+
runner_options: {
|
19
|
+
merge: Trailblazer::Activity::Magnetic::Builder::Path.plan do
|
20
|
+
task Trailblazer::Operation::Wrap::Inject::ReverseMergeDefaults.new( contract: "MyDefaultContract" ),
|
21
|
+
id: "inject.my_default",
|
22
|
+
before: "task_wrap.call_task"
|
23
|
+
end
|
24
|
+
}
|
25
|
+
|
26
|
+
)
|
27
|
+
|
28
|
+
def model!(options, **)
|
29
|
+
options["options.contract"] = options[:contract]
|
30
|
+
true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# it { Create.__call__("adsf", options={}, {}).inspect("MyMacro.contract", "options.contract").must_equal %{} }
|
35
|
+
|
36
|
+
def inspect_hash(hash, *keys)
|
37
|
+
Hash[ keys.collect { |key| [key, hash[key]] } ].inspect
|
38
|
+
end
|
39
|
+
|
40
|
+
#-
|
41
|
+
# default gets set by Injection.
|
42
|
+
it do
|
43
|
+
direction, (options, _) = Create.__call__( [{}, {}] )
|
44
|
+
|
45
|
+
|
46
|
+
inspect_hash(options, "options.contract", :contract, "MyMacro.contract").
|
47
|
+
must_equal %{{"options.contract"=>nil, :contract=>"MyDefaultContract", "MyMacro.contract"=>"MyDefaultContract"}}
|
48
|
+
end
|
49
|
+
|
50
|
+
# injected from outside, Injection skips.
|
51
|
+
it do
|
52
|
+
direction, (options, _) = Create.__call__( [ { :contract=>"MyExternalContract" }, {} ] )
|
53
|
+
|
54
|
+
inspect_hash(options, "options.contract", :contract, "MyMacro.contract").
|
55
|
+
must_equal %{{"options.contract"=>"MyExternalContract", :contract=>"MyExternalContract", "MyMacro.contract"=>"MyExternalContract"}}
|
56
|
+
end
|
57
|
+
|
58
|
+
#- Nested task_wraps should not override the outer.
|
59
|
+
AnotherMacro = ->( (options, *args), *) do
|
60
|
+
options["AnotherMacro.another_contract"] = options[:another_contract]
|
61
|
+
[ Trailblazer::Activity::Right, [options, *args] ]
|
62
|
+
end
|
63
|
+
|
64
|
+
class Update < Trailblazer::Operation
|
65
|
+
step(
|
66
|
+
task: ->( (options, *args), * ) {
|
67
|
+
_d, *o = Create.__call__( [ options, *args ] )
|
68
|
+
|
69
|
+
[ Trailblazer::Activity::Right, *o ]
|
70
|
+
},
|
71
|
+
id: "Create"
|
72
|
+
)
|
73
|
+
step(
|
74
|
+
task: AnotherMacro,
|
75
|
+
id: "AnotherMacro",
|
76
|
+
runner_options: {
|
77
|
+
merge: Trailblazer::Activity::Magnetic::Builder::Path.plan do
|
78
|
+
task Trailblazer::Operation::Wrap::Inject::ReverseMergeDefaults.new( another_contract: "AnotherDefaultContract" ), id: "inject.my_default",
|
79
|
+
before: "task_wrap.call_task"
|
80
|
+
end
|
81
|
+
}
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
it do
|
86
|
+
direction, (options, _) = Update.__call__( [ {}, {} ] )
|
87
|
+
|
88
|
+
inspect_hash(options, "options.contract", :contract, "MyMacro.contract", "AnotherMacro.another_contract").
|
89
|
+
must_equal %{{"options.contract"=>nil, :contract=>"MyDefaultContract", "MyMacro.contract"=>"MyDefaultContract", "AnotherMacro.another_contract"=>"AnotherDefaultContract"}}
|
90
|
+
end
|
91
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,2 +1,39 @@
|
|
1
|
+
require "pp"
|
2
|
+
|
1
3
|
require "minitest/autorun"
|
2
4
|
require "trailblazer/operation"
|
5
|
+
|
6
|
+
Minitest::Spec::Activity = Trailblazer::Activity
|
7
|
+
|
8
|
+
module Test
|
9
|
+
# Create a step method in `klass` with the following body.
|
10
|
+
#
|
11
|
+
# def a(options, a_return:, data:, **)
|
12
|
+
# data << :a
|
13
|
+
#
|
14
|
+
# a_return
|
15
|
+
# end
|
16
|
+
def self.step(klass, *names)
|
17
|
+
names.each do |name|
|
18
|
+
method_def =
|
19
|
+
%{def #{name}(options, #{name}_return:, data:, **)
|
20
|
+
data << :#{name}
|
21
|
+
|
22
|
+
#{name}_return
|
23
|
+
end}
|
24
|
+
|
25
|
+
klass.class_eval(method_def)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# builder for PlusPoles
|
30
|
+
def self.plus_poles_for(mapping)
|
31
|
+
ary = mapping.collect { |evt, semantic| [Trailblazer:: Activity::Output(evt, semantic), semantic ] }
|
32
|
+
|
33
|
+
Trailblazer::Activity::Magnetic::DSL::PlusPoles.new.merge(::Hash[ary])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Minitest::Spec.class_eval do
|
38
|
+
|
39
|
+
end
|
data/test/trace_test.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class TraceTest < Minitest::Spec
|
4
|
+
class B < Trailblazer::Operation
|
5
|
+
step ->(options, **) { options[:b] = true }, id: "B.task.b"
|
6
|
+
step ->(options, **) { options[:e] = true }, id: "B.task.e"
|
7
|
+
|
8
|
+
def self.call( (options, flow_options), **circuit_options )
|
9
|
+
__call__( [Trailblazer::Context(options), flow_options], circuit_options )
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Create < Trailblazer::Operation
|
14
|
+
step ->(options, a_return:, **) { options[:a] = a_return }, id: "Create.task.a"
|
15
|
+
step( {task: B, id: "MyNested"}, B.outputs[:success] => :success )
|
16
|
+
step ->(options, **) { options[:c] = true }, id: "Create.task.c"
|
17
|
+
step ->(options, params:, **) { params.any? }, id: "Create.task.params"
|
18
|
+
|
19
|
+
def self.call( (options, flow_options), **circuit_options )
|
20
|
+
__call__( [Trailblazer::Context(options), flow_options], circuit_options ) # FIXME.
|
21
|
+
end
|
22
|
+
end
|
23
|
+
# raise Create["__task_wraps__"].inspect
|
24
|
+
|
25
|
+
it "allows using low-level Activity::Trace" do
|
26
|
+
operation = ->(*args) { puts "@@@@@ #{args.last.inspect}"; Create.__call__(*args) }
|
27
|
+
|
28
|
+
stack, _ = Trailblazer::Activity::Trace.(
|
29
|
+
Create,
|
30
|
+
[
|
31
|
+
{ a_return: true, "params" => {} },
|
32
|
+
]
|
33
|
+
)
|
34
|
+
|
35
|
+
puts output = Trailblazer::Activity::Trace::Present.tree(stack)
|
36
|
+
|
37
|
+
output.gsub(/0x\w+/, "").gsub(/@.+_test/, "").must_equal %{|-- #<Trailblazer::Activity::Start:>
|
38
|
+
|-- Create.task.a
|
39
|
+
|-- MyNested
|
40
|
+
| |-- #<Trailblazer::Activity::Start:>
|
41
|
+
| |-- B.task.b
|
42
|
+
| |-- B.task.e
|
43
|
+
| `-- #<Trailblazer::Operation::Railway::End::Success:>
|
44
|
+
|-- Create.task.c
|
45
|
+
|-- Create.task.params
|
46
|
+
`-- #<Trailblazer::Operation::Railway::End::Failure:>}
|
47
|
+
end
|
48
|
+
|
49
|
+
it "Operation::trace" do
|
50
|
+
result = Create.trace({ "params" => { x: 1 }, a_return: true })
|
51
|
+
result.wtf.gsub(/0x\w+/, "").gsub(/@.+_test/, "").must_equal %{|-- #<Trailblazer::Activity::Start:>
|
52
|
+
|-- Create.task.a
|
53
|
+
|-- MyNested
|
54
|
+
| |-- #<Trailblazer::Activity::Start:>
|
55
|
+
| |-- B.task.b
|
56
|
+
| |-- B.task.e
|
57
|
+
| `-- #<Trailblazer::Operation::Railway::End::Success:>
|
58
|
+
|-- Create.task.c
|
59
|
+
|-- Create.task.params
|
60
|
+
`-- #<Trailblazer::Operation::Railway::End::Success:>}
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
# Test input- and output filter for specific tasks.
|
4
|
+
# These are task wrap steps added before and after the task.
|
5
|
+
class VariableMappingTest < Minitest::Spec
|
6
|
+
# first task
|
7
|
+
Model = ->((options, flow), **o) do
|
8
|
+
options["a"] = options["a"] * 2 # rename to model.a
|
9
|
+
options["model.nonsense"] = true # filter me out
|
10
|
+
|
11
|
+
[Activity::Right, [options, flow]]
|
12
|
+
end
|
13
|
+
|
14
|
+
# second task
|
15
|
+
Uuid = ->((options, flow), **o) do
|
16
|
+
options["a"] = options["a"] + options["model.a"] # rename to uuid.a
|
17
|
+
options["uuid.nonsense"] = false # filter me out
|
18
|
+
|
19
|
+
[Activity::Right, [options, flow]]
|
20
|
+
end
|
21
|
+
|
22
|
+
let (:activity) do
|
23
|
+
Activity.build do
|
24
|
+
task Model
|
25
|
+
task Uuid
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "input/output" do
|
30
|
+
|
31
|
+
it do
|
32
|
+
model_input = ->(options) { { "a" => options["a"]+1 } }
|
33
|
+
model_output = ->(options) { { "model.a" => options["a"] } }
|
34
|
+
uuid_input = ->(options) { { "a" => options["a"]*3, "model.a" => options["model.a"] } }
|
35
|
+
uuid_output = ->(options) { { "uuid.a" => options["a"] } }
|
36
|
+
|
37
|
+
runtime = Hash.new([])
|
38
|
+
|
39
|
+
# add filters around Model.
|
40
|
+
runtime[ Model ] = Activity::Magnetic::Builder::Path.plan do
|
41
|
+
task Activity::Wrap::Input.new( model_input ), id: "task_wrap.input", before: "task_wrap.call_task"
|
42
|
+
task Activity::Wrap::Output.new( model_output ), id: "task_wrap.output", before: "End.success", group: :end
|
43
|
+
end
|
44
|
+
|
45
|
+
# add filters around Uuid.
|
46
|
+
runtime[ Uuid ] = Activity::Magnetic::Builder::Path.plan do
|
47
|
+
task Activity::Wrap::Input.new( uuid_input ), id: "task_wrap.input", before: "task_wrap.call_task"
|
48
|
+
task Activity::Wrap::Output.new( uuid_output ), id: "task_wrap.output", before: "End.success", group: :end
|
49
|
+
end
|
50
|
+
|
51
|
+
signal, (options, flow_options) = activity.(
|
52
|
+
[
|
53
|
+
options = { "a" => 1 },
|
54
|
+
{},
|
55
|
+
],
|
56
|
+
|
57
|
+
wrap_runtime: runtime, # dynamic additions from the outside (e.g. tracing), also per task.
|
58
|
+
runner: Activity::Wrap::Runner,
|
59
|
+
wrap_static: Hash.new( Activity::Wrap.initial_activity ), # per activity?
|
60
|
+
)
|
61
|
+
|
62
|
+
signal.must_equal activity.outputs[:success].signal
|
63
|
+
options.must_equal({"a"=>1, "model.a"=>4, "uuid.a" => 7 })
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/test/wire_test.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# require "test_helper"
|
2
|
+
# # require "trailblazer/developer"
|
3
|
+
|
4
|
+
# class WireTest < Minitest::Spec
|
5
|
+
# Circuit = Trailblazer::Circuit
|
6
|
+
# ExceptionFromD = Class.new # custom signal
|
7
|
+
|
8
|
+
# D = ->((options, *args), *) do
|
9
|
+
# options["D"] = [ options["a"], options["b"], options["c"] ]
|
10
|
+
|
11
|
+
# signal = options["D_return"]
|
12
|
+
# [ signal, [ options, *args ] ]
|
13
|
+
# end
|
14
|
+
|
15
|
+
# #---
|
16
|
+
# #- step providing all :outputs manually.
|
17
|
+
# class Create < Trailblazer::Operation
|
18
|
+
# step ->(options, **) { options["a"] = 1 }
|
19
|
+
# step ->(options, **) { options["b"] = 2 }, name: "b"
|
20
|
+
|
21
|
+
# step( { task: D,
|
22
|
+
# outputs: { Circuit::Right => :success, Circuit::Left => :failure, ExceptionFromD => :exception }, # any outputs and their polarization, generic.
|
23
|
+
# id: :d,
|
24
|
+
# },
|
25
|
+
# :exception => MyEnd = End("End.ExceptionFromD_happened")
|
26
|
+
# )
|
27
|
+
|
28
|
+
# fail ->(options, **) { options["f"] = 4 }, id: "f"
|
29
|
+
# step ->(options, **) { options["c"] = 3 }, id: "c"
|
30
|
+
# end
|
31
|
+
|
32
|
+
# # myend ==> d
|
33
|
+
# it { Trailblazer::Operation::Inspect.(Create).gsub(/0x.+?wire_test.rb/, "").must_equal %{[>#<Proc::18 (lambda)>,>b,>d,<<f,>c]} }
|
34
|
+
|
35
|
+
# # normal flow as D sits on the Right track.
|
36
|
+
# it do
|
37
|
+
# result = Create.({}, "D_return" => Circuit::Right)
|
38
|
+
|
39
|
+
# result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:true [1, 2, 3, [1, 2, nil], nil] >}
|
40
|
+
# result.event.must_equal Create.outputs.keys[1]
|
41
|
+
# end
|
42
|
+
|
43
|
+
# # ends on MyEnd, without hitting fail.
|
44
|
+
# it do
|
45
|
+
# result = Create.({}, "D_return" => ExceptionFromD)
|
46
|
+
|
47
|
+
# result.event.must_equal Create::MyEnd
|
48
|
+
# result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:false [1, 2, nil, [1, 2, nil], nil] >}
|
49
|
+
# end
|
50
|
+
|
51
|
+
# # normal flow to left track.
|
52
|
+
# it do
|
53
|
+
# result = Create.({}, "D_return" => Circuit::Left)
|
54
|
+
|
55
|
+
# result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:false [1, 2, nil, [1, 2, nil], 4] >}
|
56
|
+
# result.event.must_equal Create.outputs.keys[0]
|
57
|
+
# end
|
58
|
+
|
59
|
+
# #---
|
60
|
+
# #- step with Merge
|
61
|
+
# class CreateWithDefaults < Trailblazer::Operation
|
62
|
+
# step ->(options, **) { options["a"] = 1 }
|
63
|
+
# step ->(options, **) { options["b"] = 2 }, name: "b"
|
64
|
+
|
65
|
+
# step( { task: D,
|
66
|
+
# outputs: Merge( ExceptionFromD => { role: :exception } ), # any outputs and their polarization, generic.
|
67
|
+
# id: :d,
|
68
|
+
# },
|
69
|
+
# :exception => MyEnd = End("End.ExceptionFromD_happened")
|
70
|
+
# )
|
71
|
+
|
72
|
+
# fail ->(options, **) { options["f"] = 4 }, id: "f"
|
73
|
+
# step ->(options, **) { options["c"] = 3 }, id: "c"
|
74
|
+
# end
|
75
|
+
|
76
|
+
# # normal flow as D sits on the Right track.
|
77
|
+
# it do
|
78
|
+
# result = CreateWithDefaults.({}, "D_return" => Circuit::Right)
|
79
|
+
|
80
|
+
# result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:true [1, 2, 3, [1, 2, nil], nil] >}
|
81
|
+
# result.event.must_equal CreateWithDefaults.outputs.keys[1]
|
82
|
+
# end
|
83
|
+
|
84
|
+
# # ends on MyEnd, without hitting fail.
|
85
|
+
# it do
|
86
|
+
# result = CreateWithDefaults.({}, "D_return" => ExceptionFromD)
|
87
|
+
|
88
|
+
# result.event.must_equal CreateWithDefaults::MyEnd
|
89
|
+
# result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:false [1, 2, nil, [1, 2, nil], nil] >}
|
90
|
+
# end
|
91
|
+
|
92
|
+
# # normal flow to left track.
|
93
|
+
# it do
|
94
|
+
# result = CreateWithDefaults.({}, "D_return" => Circuit::Left)
|
95
|
+
|
96
|
+
# result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:false [1, 2, nil, [1, 2, nil], 4] >}
|
97
|
+
# result.event.must_equal CreateWithDefaults.outputs.keys[0]
|
98
|
+
# end
|
99
|
+
|
100
|
+
# end
|
101
|
+
|
102
|
+
# class WireExceptionTest < Minitest::Spec
|
103
|
+
# # role in :outputs can't be connected because not in :connect_to.
|
104
|
+
# it do
|
105
|
+
# exception = assert_raises do
|
106
|
+
# class Create < Trailblazer::Operation
|
107
|
+
# step :a, outputs: { "some" => { role: :success } }, connect_to: { :not_existent => "End.success" }
|
108
|
+
# end
|
109
|
+
# end
|
110
|
+
|
111
|
+
# exception.message.must_equal %{Couldn't map output role :success for {:not_existent=>"End.success"}}
|
112
|
+
# end
|
113
|
+
# end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
# class WireDefaultsTest < Minitest::Spec
|
4
|
+
# class C < Trailblazer::Operation
|
5
|
+
# # here, D has a step interface!
|
6
|
+
# D = ->(options, a:raise, b:raise, **) {
|
7
|
+
# options["D"] = [ a, b, options["c"] ]
|
8
|
+
|
9
|
+
# options["D_return"]
|
10
|
+
# }
|
11
|
+
|
12
|
+
# ExceptionFromD = Class.new(Circuit::Signal) # for steps, return value has to be subclass of Signal to be passed through as a signal and not a boolean.
|
13
|
+
# MyEnd = Class.new(Circuit::End)
|
14
|
+
|
15
|
+
# step ->(options, **) { options["a"] = 1 }, id: "a"
|
16
|
+
# step ->(options, **) { options["b"] = 2 }, id: "b"
|
17
|
+
|
18
|
+
# attach MyEnd.new(:myend), id: "End.myend"
|
19
|
+
|
20
|
+
# # step provides defaults:
|
21
|
+
# step D,
|
22
|
+
# outputs: Merge( ExceptionFromD => { role: :exception } ),
|
23
|
+
# connect_to: Merge( exception: "End.myend" ),
|
24
|
+
# id: "d"
|
25
|
+
|
26
|
+
# fail ->(options, **) { options["f"] = 4 }, id: "f"
|
27
|
+
# step ->(options, **) { options["c"] = 3 }, id: "c"
|
28
|
+
# end
|
29
|
+
|
30
|
+
# # normal flow as D sits on the Right track.
|
31
|
+
# it { C.( "D_return" => Circuit::Right).inspect("a", "b", "c", "D", "f").must_equal %{<Result:true [1, 2, 3, [1, 2, nil], nil] >} }
|
32
|
+
# # ends on MyEnd, without hitting fail.
|
33
|
+
# it { C.( "D_return" => C::ExceptionFromD).inspect("a", "b", "c", "D", "f").must_equal %{<Result:false [1, 2, nil, [1, 2, nil], nil] >} } # todo: HOW TO CHECK End instance?
|
34
|
+
# it { C.( "D_return" => Circuit::Left).inspect("a", "b", "c", "D", "f").must_equal %{<Result:false [1, 2, nil, [1, 2, nil], 4] >} } # todo: HOW TO CHECK End instance?
|
35
|
+
# it do
|
36
|
+
# step1 = C["__sequence__"][0].instructions[0].last[:node][0]
|
37
|
+
# step2 = C["__sequence__"][1].instructions[0].last[:node][0]
|
38
|
+
# step3 = C["__sequence__"][3].instructions[0].last[:node][0] # D
|
39
|
+
# step4 = C["__sequence__"][4].instructions[0].last[:node][0]
|
40
|
+
# step5 = C["__sequence__"][5].instructions[0].last[:node][0]
|
41
|
+
|
42
|
+
# require "trailblazer/activity/schema"
|
43
|
+
|
44
|
+
# Output = Trailblazer::Activity::Schema::Output
|
45
|
+
|
46
|
+
# steps = [
|
47
|
+
# [ [:success], step1, [Output.new(Circuit::Right, :success), Output.new(Circuit::Left, :failure)] ],
|
48
|
+
# [ [:success], step2, [Output.new(Circuit::Right, :success), Output.new(Circuit::Left, :failure)] ],
|
49
|
+
|
50
|
+
# [ [:success], step3, [Output.new(Circuit::Right, :success), Output.new(Circuit::Left, :failure), Output.new(C::ExceptionFromD, :exception)] ],
|
51
|
+
# [ [:exception], C::MyEnd.new(:myend), [] ],
|
52
|
+
|
53
|
+
# [ [:failure], step4, [Output.new(Circuit::Right, :failure), Output.new(Circuit::Left, :failure)] ],
|
54
|
+
# [ [:success], step5, [Output.new(Circuit::Right, :success), Output.new(Circuit::Left, :failure)] ],
|
55
|
+
# ]
|
56
|
+
|
57
|
+
# ends = [
|
58
|
+
# [ [:success], Trailblazer::Operation::Railway::End::Success.new(:success), [] ],
|
59
|
+
# [ [:failure], Trailblazer::Operation::Railway::End::Failure.new(:failure), [] ],
|
60
|
+
# ]
|
61
|
+
|
62
|
+
|
63
|
+
# graph = Trailblazer::Activity::Schema.bla(steps + ends)
|
64
|
+
# circuit = Trailblazer::Activity.new(graph)
|
65
|
+
# # pp schema
|
66
|
+
|
67
|
+
# C["__activity__"] = circuit # this is so wrong
|
68
|
+
# C.( "D_return" => Circuit::Right).inspect("a", "b", "c", "D", "f").must_equal %{<Result:true [1, 2, 3, [1, 2, nil], nil] >}
|
69
|
+
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
|
73
|
+
# # step :a
|
74
|
+
# # fail :b, connect_to: { Circuit::Right => "End.success" }
|
75
|
+
# # fail :c, connect_to: { Circuit::Right => "End.success" }
|
76
|
+
|
77
|
+
# Connect failure steps to right track, allowing to append steps after.
|
78
|
+
# @see https://github.com/trailblazer/trailblazer/issues/190#issuecomment-326992255
|
79
|
+
class WireDefaultsEarlyExitSuccessTest < Minitest::Spec
|
80
|
+
class Create < Trailblazer::Operation
|
81
|
+
step :a
|
82
|
+
fail :b, Output(:success) => :success #{}"End.success"
|
83
|
+
fail :c, Output(:success) => :success
|
84
|
+
|
85
|
+
Test.step(self, :a, :b, :c)
|
86
|
+
end
|
87
|
+
|
88
|
+
# a => true
|
89
|
+
it { Create.( a_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a]] >} }
|
90
|
+
# b => true
|
91
|
+
it { Create.( a_return: false, b_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a, :b]] >} }
|
92
|
+
# c => true
|
93
|
+
it { Create.( a_return: false, b_return: false, c_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a, :b, :c]] >} }
|
94
|
+
# a => b => c => false
|
95
|
+
it { Create.( a_return: false, b_return: false, c_return: false, data: []).inspect(:data).must_equal %{<Result:false [[:a, :b, :c]] >} }
|
96
|
+
|
97
|
+
# # require "trailblazer/developer"
|
98
|
+
# # it { Trailblazer::Developer::Client.push( operation: Create, name: "ushi" ) }
|
99
|
+
|
100
|
+
|
101
|
+
# #---
|
102
|
+
# # with => :success, steps can still be added before End.success and they will be executed.
|
103
|
+
class Update < Create
|
104
|
+
pass :d
|
105
|
+
|
106
|
+
def d(options, data:, **)
|
107
|
+
data << :d
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# a => true
|
112
|
+
it { Update.( a_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a, :d]] >} }
|
113
|
+
# b => true
|
114
|
+
it { Update.( a_return: false, b_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a, :b, :d]] >} }
|
115
|
+
# c => true
|
116
|
+
it { Update.( a_return: false, b_return: false, c_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a, :b, :c, :d]] >} }
|
117
|
+
# a => b => c => false
|
118
|
+
it { Update.( a_return: false, b_return: false, c_return: false, data: []).inspect(:data).must_equal %{<Result:false [[:a, :b, :c]] >} }
|
119
|
+
|
120
|
+
#---
|
121
|
+
# failure steps reference End.success and not just the polarization. This won't call #d in failure=>success case.
|
122
|
+
class Delete < Trailblazer::Operation
|
123
|
+
step :a
|
124
|
+
fail :b, Output(:success) => "End.success"
|
125
|
+
fail :c, Output(:success) => "End.success"
|
126
|
+
pass :d
|
127
|
+
|
128
|
+
Test.step(self, :a, :b, :c)
|
129
|
+
|
130
|
+
def d(options, data:, **)
|
131
|
+
data << :d
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# a => true
|
136
|
+
it { Delete.( a_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a, :d]] >} }
|
137
|
+
# b => true
|
138
|
+
it { Delete.( a_return: false, b_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a, :b]] >} }
|
139
|
+
# c => true
|
140
|
+
it { Delete.( a_return: false, b_return: false, c_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a, :b, :c]] >} }
|
141
|
+
# a => b => c => false
|
142
|
+
it { Delete.( a_return: false, b_return: false, c_return: false, data: []).inspect(:data).must_equal %{<Result:false [[:a, :b, :c]] >} }
|
143
|
+
|
144
|
+
#---
|
145
|
+
# |----|
|
146
|
+
# a --> b c--d --> E.s
|
147
|
+
# |_____|_|_______ E.f
|
148
|
+
class Connect < Trailblazer::Operation
|
149
|
+
step :a
|
150
|
+
step :b, Output(:success) => "d"
|
151
|
+
step :c, magnetic_to: [] # otherwise :success will be an open input!
|
152
|
+
pass :d, id: "d"
|
153
|
+
|
154
|
+
Test.step(self, :a, :b, :c)
|
155
|
+
|
156
|
+
def d(options, data:, **)
|
157
|
+
data << :d
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
it { puts Trailblazer::Activity::Magnetic::Introspect.seq( Connect ) }
|
162
|
+
|
163
|
+
# a => true
|
164
|
+
it { Connect.( a_return: true, b_return: true,data: []).inspect(:data).must_equal %{<Result:true [[:a, :b, :d]] >} }
|
165
|
+
# a => false
|
166
|
+
it { Connect.( a_return: false, data: []).inspect(:data).must_equal %{<Result:false [[:a]] >} }
|
167
|
+
# b => false
|
168
|
+
it { Connect.( a_return: true, b_return: false, data: []).inspect(:data).must_equal %{<Result:false [[:a, :b]] >} }
|
169
|
+
|
170
|
+
#---
|
171
|
+
# |---------|
|
172
|
+
# | V
|
173
|
+
# a c----d --
|
174
|
+
# |\ ^\ \
|
175
|
+
# | \ / V
|
176
|
+
# |__f____g----E.f
|
177
|
+
class Post < Trailblazer::Operation
|
178
|
+
step :a, Output(:success) => "d", id: "a"
|
179
|
+
fail :f, Output(:success) => "c"
|
180
|
+
step :c, magnetic_to: [], id: "c" # otherwise :success will be an open input!
|
181
|
+
fail :g
|
182
|
+
step :d, id: "d"
|
183
|
+
|
184
|
+
Test.step(self, :a, :f, :c, :g, :d)
|
185
|
+
end
|
186
|
+
|
187
|
+
pp Post["__sequence__"]
|
188
|
+
|
189
|
+
# a => true
|
190
|
+
it { Post.( a_return: true, d_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a, :d]] >} }
|
191
|
+
# a => false
|
192
|
+
it { Post.( a_return: false, f_return: false, g_return: nil, data: []).inspect(:data).must_equal %{<Result:false [[:a, :f, :g]] >} }
|
193
|
+
# a => false, f => true
|
194
|
+
it { Post.( a_return: false, f_return: true, c_return: true, d_return: true, data: []).inspect(:data).must_equal %{<Result:true [[:a, :f, :c, :d]] >} }
|
195
|
+
# a => false, f => true, c => false
|
196
|
+
it { Post.( a_return: false, f_return: true, c_return: false, g_return: true, data: []).inspect(:data).must_equal %{<Result:false [[:a, :f, :c, :g]] >} }
|
197
|
+
end
|