Skip to content

Commit

Permalink
start working on Collaboration.advance.
Browse files Browse the repository at this point in the history
  • Loading branch information
apotonick committed Dec 10, 2023
1 parent 61ad8f5 commit b190615
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 6 deletions.
111 changes: 111 additions & 0 deletions lib/trailblazer/workflow/collaboration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
module Trailblazer
module Workflow
class Collaboration
class Schema
def initialize(lanes:, message_flow:, options:{})
@lanes = lanes
@message_flow = message_flow
# @initial_lane_positions = Synchronous.initial_lane_positions(lanes.values)
# @options = options # FIXME: test me!!!
end

# attr_reader :initial_lane_positions
# attr_reader :message_flow
# attr_reader :lanes # @private

def to_h
{
message_flow: @message_flow,
# initial_lane_positions: @initial_lane_positions, # DISCUSS: do we really nee
lanes: @lanes,
}
end
end # Schema

class Position < Struct.new(:activity, :task)
def to_h
{
activity: activity,
task: task
}
end
end

# DISCUSS: rename to State or something better matching?
# Keeps the collaboration lane positions after running, it's a "state"
class Configuration < Struct.new(:lane_positions, :signal, :ctx, :flow_options, keyword_init: true) # DISCUSS: should we keep ctx/flow_options?
end

module Synchronous # DISCUSS: (file) location.
module_function

# @private
def initial_lane_positions(lanes)
lanes.collect do |activity|
[
activity,
{resume_events: [activity.to_h[:circuit].to_h[:start_task]]} # We deliberately have *one* position per lane, we're Synchronous.
]
end
.to_h
end

# Triggers the {start_task} event and runs the entire collaboration until message is sent and
# the throwing activity stops in a suspend or End terminus.
# @private
def advance(collaboration, (ctx, flow), circuit_options, lane_positions:, start_position:, message_flow:)
signal = nil

# start_task, activity,
loop do
start_position = start_position.to_h

Synchronous.validate_targeted_position(lane_positions, **start_position)

circuit_options = circuit_options.merge(start_task: start_position[:task])

signal, (ctx, flow) = Activity::TaskWrap.invoke(start_position[:activity], [ctx, flow], **circuit_options)

# now we have :throw, or not
# @returns Event::Throw::Queued

# now, "log" the collaboration's state.
lane_positions = advance_position(lane_positions, start_position[:activity], signal)

break unless flow[:throw].any?
break if (@options[:skip_message_from] || []).include?(flow[:throw][-1][0]) # FIXME: untested!

flow, start_position = receiver_task(flow, message_flow)
# every time we "deliver" a message, we should check if it's allow (meaning the receiving activity is actually in the targeted catch event)
end

return Configuration.new(
lane_positions: lane_positions,
signal: signal,
),
[ctx, flow]
end

# @private
# every time we "deliver" a message, we should check if it's allowed (meaning the receiving activity is actually in the targeted catch event)
# {:activity} and {:task} are the targeted position.
def validate_targeted_position(lane_positions, activity:, task:)
receiver_position = lane_positions[activity] # receiver should always be in a suspend task/event gateway.
# puts "@@@@@ #{start_task} ? #{receiver_position.inspect}"

if possible_catch_events = receiver_position.to_h[:resume_events]
return true if possible_catch_events.include?(task)
end

raise "Message can't be passed to #{task} because #{activity} is not in appropriate position"
end

# @private
# @param signal Workflow::Event::Suspend
def advance_position(lane_positions, activity, suspend_event)
lane_positions.merge(activity => suspend_event)
end
end # Synchronous
end
end
end
57 changes: 51 additions & 6 deletions test/collaboration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,31 @@

class CollaborationTest < Minitest::Spec
it "what" do
ui_create_form = "Activity_0wc2mcq" # TODO: this is from pro-rails tests.
ui_create = "Activity_1psp91r"
ui_create_valid = "Event_0km79t5"
ui_create_invalid = "Event_0co8ygx"
ui_update_form = 'Activity_1165bw9'
ui_update = "Activity_0j78uzd"
ui_update_valid = "Event_1vf88fn"
ui_update_invalid = "Event_1nt0djb"
ui_notify_approver = "Activity_1dt5di5"
ui_accepted = "Event_1npw1tg"
ui_delete_form = "Activity_0ha7224"
ui_delete = "Activity_15nnysv"
ui_cancel = "Activity_1uhozy1"
ui_publish = "Activity_0bsjggk"
ui_archive = "Activity_0fy41qq"
ui_revise_form = "Activity_0zsock2"
ui_revise = "Activity_1wiumzv"
ui_revise_valid = "Event_1bz3ivj"
ui_revise_invalid = "Event_1wly6jj"
ui_revise_form_with_errors = "Activity_19m1lnz"
ui_create_form_with_errors = "Activity_08p0cun"
ui_update_form_with_errors = "Activity_00kfo8w"
ui_rejected = "Event_1vb197y"


moderation_json = File.read("test/fixtures/v1/moderation.json")
signal, (ctx, _) = Trailblazer::Workflow::Generate.invoke([{json_document: moderation_json}, {}])

Expand Down Expand Up @@ -64,18 +89,38 @@ class CollaborationTest < Minitest::Spec
id_to_lane
)

pp message_flow

Trailblazer::Workflow::Collaboration::Schema.new(
schema = Trailblazer::Workflow::Collaboration::Schema.new(
lanes: {
lifecycle: lane_activity,
ui: lane_activity_ui
},
messages: Trailblazer::Workflow::Collaboration.Messages(

)
message_flow: message_flow,
)

schema_hash = schema.to_h

# raise schema_hash.keys.inspect

initial_lane_positions = Trailblazer::Workflow::Collaboration::Synchronous.initial_lane_positions(schema_hash[:lanes].values)

# TODO: do this in the State layer.
# start_task = [lane_activity_ui, initial_lane_positions[lane_activity_ui][:resume_events].first]
start_position = Trailblazer::Workflow::Collaboration::Position.new(lane_activity_ui, initial_lane_positions[lane_activity_ui][:resume_events].first)

configuration, (ctx, flow) = Trailblazer::Workflow::Collaboration::Synchronous.advance(
schema,
[{seq: []}, {throw: []}],
{}, # circuit_options

start_position: start_position,
lane_positions: initial_lane_positions, # current position/"state"

message_flow: schema_hash[:message_flow],
)

assert_equal configuration.lane_positions.keys, [lane_activity, lane_activity_ui]
assert_equal configuration.lane_positions.values.inspect, %([{:resume_events=>[#<Trailblazer::Workflow::Event::Catch start_task=true type=:catch_event semantic=[:catch, \"catch-before-Activity_0wwfenp\"]>]}, \
#<Trailblazer::Workflow::Event::Suspend resumes=[\"catch-before-#{ui_create}\"] type=:suspend semantic=[:suspend, \"suspend-Gateway_14h0q7a\"]>])
assert_equal ctx.inspect, %({:seq=>[:create_form]})
end
end

0 comments on commit b190615

Please sign in to comment.