Skip to content

Commit

Permalink
introduce Iteration::Set as an intermediate structure between discovery
Browse files Browse the repository at this point in the history
and tools like state table. implement serialize.
  • Loading branch information
apotonick committed Feb 20, 2024
1 parent b5f093a commit 0da0302
Show file tree
Hide file tree
Showing 5 changed files with 1,302 additions and 43 deletions.
2 changes: 2 additions & 0 deletions lib/trailblazer/workflow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ module Workflow
require "trailblazer/workflow/discovery/present/state_table"
require "trailblazer/workflow/discovery/present/event_table"
require "terminal-table" # TODO: only require when discovery is "loaded".

require "trailblazer/workflow/iteration"
100 changes: 100 additions & 0 deletions lib/trailblazer/workflow/iteration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
module Trailblazer
module Workflow
# An {Iteration} represents the "path" from a triggered event to its suspend configuration of a collaboration.
# It is usually generated from a discovery process.
# A {Set} of {Iteration}s comprises of all possible events and outcomes. This is the interface
# for higher-level tools such as Advance, state tables, test plans or outcome deciders to work with.
#
# DISCUSS: maybe the naming/namespace will change.
# maybe Introspect::Iteration?
class Iteration < Struct.new(:id, :event_label, :start_position, :start_positions, :suspend_positions, :outcome)
class Set
def self.from_discovered_states(discovered_states, **options)
iterations = discovered_states.collect do |row|
triggered_catch_event_position = row[:positions_before][1]

id = Discovery::Present.id_for_task(triggered_catch_event_position)
event_label = Test::Plan::CommentHeader.start_position_label(row[:positions_before][1], row, **options)

Iteration.new(
id,
event_label,
row[:positions_before][1],
row[:positions_before][0],
row[:suspend_configuration].lane_positions,
row[:outcome],
)
end

Set.new(iterations, **options)
end

def initialize(iterations, lanes_cfg:)
@iterations = iterations
@lanes_cfg = lanes_cfg
end

# An Iteration::Set is usually serialized to a JSON document, so we don't have
# to re-run the discovery every time we use the collaboration.
def to_hash()
@iterations.collect do |iteration|
attributes = {
id: iteration.id,
event_label: iteration.event_label,
start_task: Serialize.serialize_position(*iteration.start_position.to_a, lanes_cfg: @lanes_cfg),
start_positions: Serialize.serialize_suspend_positions(iteration.start_positions, lanes_cfg: @lanes_cfg),
suspend_positions: Serialize.serialize_suspend_positions(iteration.suspend_positions, lanes_cfg: @lanes_cfg),
outcome: iteration.outcome,
}
end
end

module Serialize
module_function

def serialize_suspend_positions(start_positions, **options)
start_positions.collect do |activity, suspend|
serialize_suspend_position(activity, suspend, **options)
end
end

def id_tuple_for(activity, task, lanes_cfg:)
activity_id = lanes_cfg.values.find { |cfg| cfg[:activity] == activity }[:label]
task_id = Trailblazer::Activity::Introspect.Nodes(activity, task: task).id

return activity_id, task_id
end

# A lane position is always a {Suspend} (or a terminus).
def self.serialize_suspend_position(activity, suspend, **options)
position_tuple = id_tuple_for(activity, suspend, **options) # usually, this is a suspend. sometimes a terminus {End}.

comment =
if suspend.to_h["resumes"].nil? # FIXME: for termini.
comment = [:terminus, suspend.to_h[:semantic]]
else
[:before, Discovery::Present.readable_name_for_suspend_or_terminus(activity, suspend, **options)]
end

{
tuple: position_tuple,
comment: comment,
}
end

# TODO: merge with serialize_suspend_position.
def serialize_position(activity, catch_event, **options)
position_tuple = id_tuple_for(activity, catch_event, **options)

comment = [:before, Discovery::Present.readable_name_for_catch_event(activity, catch_event, **options)]

{
tuple: position_tuple,
comment: comment,
}
end
end
end
end # Iteration
end
end
40 changes: 0 additions & 40 deletions lib/trailblazer/workflow/test/plan.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,47 +64,7 @@ def position_from_tuple(lane_label, task_id)
end
end

def serialize_configuration(start_positions, **options)
start_positions.collect do |activity, suspend|
serialize_suspend_position(activity, suspend, **options)
end
end

def id_tuple_for(activity, task, lanes_cfg:)
activity_id = lanes_cfg.values.find { |cfg| cfg[:activity] == activity }[:label]
task_id = Trailblazer::Activity::Introspect.Nodes(activity, task: task).id

return activity_id, task_id
end

# A lane position is always a {Suspend} (or a terminus).
def self.serialize_suspend_position(activity, suspend, **options)
position_tuple = id_tuple_for(activity, suspend, **options) # usually, this is a suspend. sometimes a terminus {End}.

comment =
if suspend.to_h["resumes"].nil? # FIXME: for termini.
comment = [:terminus, suspend.to_h[:semantic]]
else
[:before, Discovery::Present.readable_name_for_suspend_or_terminus(activity, suspend, **options)]
end

{
tuple: position_tuple,
comment: comment,
}
end

# TODO: merge with serialize_suspend_position.
def serialize_position(activity, catch_event, **options)
position_tuple = id_tuple_for(activity, catch_event, **options)

comment = [:before, Discovery::Present.readable_name_for_catch_event(activity, catch_event, **options)]

{
tuple: position_tuple,
comment: comment,
}
end
end

def render_comment_header(discovered_states, **options)
Expand Down
16 changes: 13 additions & 3 deletions test/discovery_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,19 @@ def self.states
assert_nil states[15]
end

it "Iteration::Set" do
states, lanes_sorted, lanes_cfg = self.class.states

iteration_set = Trailblazer::Workflow::Iteration::Set.from_discovered_states(states, lanes_cfg: lanes_cfg)

testing_json = JSON.pretty_generate(iteration_set.to_hash)
# File.write "test/iteration_json.json", testing_json
assert_equal testing_json, File.read("test/iteration_json.json")


# assert_equal iteration_set.to_hash, %(asdf)
end

# Asserts
# * that positions are always sorted by activity.
def assert_position_before(actual_positions, expected_ids, start_id:, lanes:)
Expand Down Expand Up @@ -232,9 +245,6 @@ def assert_position_after(actual_configuration, expected_ids, lanes:)
it "{#render_cli_state_table}" do
states, lanes_sorted, lanes_cfg = self.class.states()

# DISCUSS: technically, this is an event table, not a state table.
# state_table = Trailblazer::Workflow::State::Discovery.generate_state_table(states, lanes: lanes_cfg)

cli_state_table = Trailblazer::Workflow::Discovery::Present::StateTable.(states, lanes_cfg: lanes_cfg)
puts cli_state_table
assert_equal cli_state_table,
Expand Down
Loading

0 comments on commit 0da0302

Please sign in to comment.