From 61017aec2b7c2d4eecfa5d16b55ae87de9d27717 Mon Sep 17 00:00:00 2001 From: Nick Sutterer Date: Wed, 3 Apr 2024 11:07:22 +0200 Subject: [PATCH] Advance now has a `invalid_event` terminus instead of `not_authorized`. --- lib/trailblazer/workflow/advance.rb | 36 ++++++++++--------------- test/advance_test.rb | 41 ++++++++++++++++++++++++++--- test/test_helper.rb | 2 +- 3 files changed, 53 insertions(+), 26 deletions(-) diff --git a/lib/trailblazer/workflow/advance.rb b/lib/trailblazer/workflow/advance.rb index 898fcac..3f99cce 100644 --- a/lib/trailblazer/workflow/advance.rb +++ b/lib/trailblazer/workflow/advance.rb @@ -7,9 +7,10 @@ module Workflow # TODO: # * wire the event_valid? step to {invalid_state} terminus and handle that differently in the endpoint. class Advance < Trailblazer::Activity::Railway - step task: :compute_catch_event_tuple + terminus :invalid_event + + step task: :compute_catch_event_tuple, Output(:failure) => Track(:invalid_event) step task: :find_position_options - step task: :event_valid?, Output(:failure) => End(:not_authorized) step task: :advance def compute_catch_event_tuple((ctx, flow_options), **) @@ -19,16 +20,25 @@ def compute_catch_event_tuple((ctx, flow_options), **) # it's probably cleaner to have a dedicated state_table. # it should compute activity/start_task (catch event ID) from the event label. planned_iteration = iteration_set.to_a.find { |iteration| iteration.event_label == event_label } + return Activity::Left, [ctx, flow_options] unless planned_iteration # TODO: those positions could also be passed in manually, without using an Iteration::Set. position_options_FIXME = position_options_from_iteration(planned_iteration) # :start_task_position and :start_positions catch_event_tuple = Introspect::Iteration::Set::Serialize.id_tuple_for(*position_options_FIXME[:start_task_position].to_a, lanes_cfg: flow_options[:lanes]) # TODO: this should be done via state_table. - flow_options[:catch_event_tuple] = catch_event_tuple + flow_options[:catch_event_tuple] = catch_event_tuple return Activity::Right, [ctx, flow_options] end + # Computes {:start_task_position} and {:start_positions}. + def position_options_from_iteration(iteration) + { + start_task_position: iteration.start_task_position, # which event to trigger + lane_positions: iteration.start_positions # current position/"state" + } + end + # TODO: Position object with "tuple", resolved activity/task, comment, lane label, etc. Instead of recomputing it continuously. @@ -38,6 +48,7 @@ def find_position_options((ctx, flow_options), **) _, state_options = state_resolver.(*flow_options[:catch_event_tuple], [ctx], **ctx.to_hash) + # raise unless state_options # FIXME. lanes_cfg = flow_options[:lanes] fixme_tuples = state_options[:suspend_tuples].collect { |tuple| {"tuple" => tuple} } @@ -53,17 +64,6 @@ def find_position_options((ctx, flow_options), **) return Activity::Right, [ctx, flow_options] end - def event_valid?((ctx, flow_options), **) - # position_options = flow_options[:position_options] - # state_guards = flow_options[:state_guards] - - # result = state_guards.(ctx, start_task_position: position_options[:start_task_position]) - - result = flow_options[:position_options][:lane_positions].is_a? Trailblazer::Workflow::Collaboration::Positions # FIXME - - return result ? Activity::Right : Activity::Left, [ctx, flow_options] - end - # Needs Iteration::Set and an {event_label}. def advance((ctx, flow_options), **circuit_options) message_flow, position_options, iteration_set = flow_options[:message_flow], flow_options[:position_options], flow_options[:iteration_set] @@ -85,14 +85,6 @@ def advance((ctx, flow_options), **circuit_options) return signal, [ctx, flow_options]#, configuration end - # Computes {:start_task_position} and {:start_positions}. - def position_options_from_iteration(iteration) - { - start_task_position: iteration.start_task_position, # which event to trigger - lane_positions: iteration.start_positions # current position/"state" - } - end - def return_signal_for(configuration, iteration_set, start_task_position:, **) collaboration_signal = configuration.signal diff --git a/test/advance_test.rb b/test/advance_test.rb index 4316152..c7e05e0 100644 --- a/test/advance_test.rb +++ b/test/advance_test.rb @@ -1,7 +1,42 @@ require "test_helper" -# high-level unit test that shows the user's interface. +# low-level private test class AdvanceTest < Minitest::Spec + it "legal, modelless advance" do + iteration_set, lanes_cfg, schema = fixtures() + + ctx = {seq: []} + event_label = "☝ ⏵︎Create form" # TODO: "☝ ⏵︎Notify approver" + + ctx_for_advance = Trailblazer::Context(ctx, {}) + flow_options = { + event_label: event_label, + throw: [], + iteration_set: iteration_set, + **schema.to_h, + + lanes: lanes_cfg, # FIXME: why is this not part of schema.to_h? + state_guards: state_guards(), # TODO: rename to {state_resolver}? + } + + signal, (ctx, flow_options) = Trailblazer::Workflow::Advance.([ctx_for_advance, flow_options]) + + configuration = flow_options[:configuration] + + assert_equal signal.inspect, %(#) + + + #@ unknown event label + flow_options = flow_options.merge!(event_label: "XXX unknown ~~~") + + signal, (ctx, flow_options) = Trailblazer::Workflow::Advance.([ctx_for_advance, flow_options]) + + assert_equal signal.inspect, %(#) + end +end + +# high-level unit test that shows the user's interface. +class AdvanceEndpointTest < Minitest::Spec include BuildSchema include DiscoveredStates @@ -67,11 +102,11 @@ def policy(*) advance_protocol = Trailblazer::Endpoint.build_protocol(protocol_template, domain_activity: Trailblazer::Workflow::Advance, - protocol_block: ->(*) { {Trailblazer::Activity::Railway.Output(:not_authorized) => Trailblazer::Activity::Railway.Track(:not_authorized)} } + protocol_block: ->(*) { {Trailblazer::Activity::Railway.Output(:invalid_event) => Trailblazer::Activity::Railway.Track(:not_authorized)} } ) advance_protocol_with_model = Trailblazer::Endpoint.build_protocol(protocol_template_with_model, domain_activity: Trailblazer::Workflow::Advance, - protocol_block: ->(*) { {Trailblazer::Activity::Railway.Output(:not_authorized) => Trailblazer::Activity::Railway.Track(:not_authorized)} } + protocol_block: ->(*) { {Trailblazer::Activity::Railway.Output(:invalid_event) => Trailblazer::Activity::Railway.Track(:not_authorized)} } ) # action_protocol = Trailblazer::Endpoint.build_protocol(Protocol, domain_activity: Create, protocol_block: ->(*) { {Output(:not_found) => Track(:not_found)} }) diff --git a/test/test_helper.rb b/test/test_helper.rb index 27e4b72..5e7b83b 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -245,6 +245,6 @@ def fixtures states, lanes_sorted, lanes_cfg, schema, message_flow = states() iteration_set = Trailblazer::Workflow::Introspect::Iteration::Set.from_discovered_states(states, lanes_cfg: lanes_cfg) - @fixtures = [iteration_set, lanes_cfg] + @fixtures = [iteration_set, lanes_cfg, schema] end end