Skip to content

Commit

Permalink
extract Assertions.
Browse files Browse the repository at this point in the history
apotonick committed Feb 19, 2024
1 parent a564c7c commit a956674
Showing 4 changed files with 193 additions and 98 deletions.
1 change: 1 addition & 0 deletions lib/trailblazer/workflow.rb
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ module Workflow
require "trailblazer/workflow/event"

require "trailblazer/workflow/test/plan"
require "trailblazer/workflow/test/assertions"

require "trailblazer/workflow/discovery"
require "trailblazer/workflow/discovery/present"
73 changes: 73 additions & 0 deletions lib/trailblazer/workflow/test/assertions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
module Trailblazer
module Workflow
module Test
module Assertions
def assert_positions(asserted_positions, expected_tuples, lanes:)
expected_positions =
expected_tuples.collect do |testing_row|
Trailblazer::Workflow::State::Discovery.position_from_tuple(lanes, *testing_row[:tuple])
end

sorting_block = ->(a, b) { a.activity.object_id <=> b.activity.object_id }

sorted_asserted_positions = asserted_positions.to_a.sort(&sorting_block)
sorted_expected_positions = expected_positions.sort(&sorting_block)

sorted_asserted_positions.collect.with_index do |position, index|
assert_equal position, sorted_expected_positions[index],
Assertions.error_message_for(position, sorted_expected_positions[index], lanes: lanes)
end

# FIXME: figure out why we can't just compare the entire array!
# assert_equal sorted_asserted_positions, sorted_expected_positions
end

# Compile error message when the expected lane position doesn't match the actual one.
def self.error_message_for(position, expected_position, lanes:) # TODO: test me.
# TODO: make the labels use UTF8 icons etc, as in the CLI rendering code.
expected_label = State::Discovery::Testing.serialize_lane_position(position, lanes: lanes)[:comment]
actual_label = State::Discovery::Testing.serialize_lane_position(expected_position, lanes: lanes)[:comment]

"Lane #{lanes.invert[position.activity].inspect}:\n expected #{expected_label}\n actual #{actual_label}"
end

# Grab the start_position and expected_lane_positions from the discovered plan, run
# the collaboration from there and check if it actually reached the expected configuration.
def assert_advance(event_label, test_plan:, lanes:, schema:, message_flow:, expected_ctx:, ctx: {seq: []}, **) # TODO: allow {ctx}
testing_row = test_plan.find { |row| row[:event_label] == event_label }

start_position = testing_row[:start_position]
start_tuple = start_position[:tuple] # #{start_position[:comment]}
start_position = Trailblazer::Workflow::State::Discovery.position_from_tuple(lanes, *start_tuple)

# current position.
#DISCUSS: here, we could also ask the State layer for the start configuration, on a different level.
lane_positions = testing_row[:start_configuration].collect do |row|
Trailblazer::Workflow::State::Discovery.position_from_tuple(lanes, *row[:tuple])
end

lane_positions = Trailblazer::Workflow::Collaboration::Positions.new(lane_positions)

ctx_for_advance = ctx

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

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

message_flow: message_flow,
)

assert_positions configuration[:lane_positions], testing_row[:expected_lane_positions], lanes: lanes

# assert_equal ctx.inspect, expected_ctx.inspect
ctx
end

end
end # Test
end
end
132 changes: 36 additions & 96 deletions lib/trailblazer/workflow/test/plan.rb
Original file line number Diff line number Diff line change
@@ -1,91 +1,20 @@
module Trailblazer
module Workflow
module Test
module Assertions
def assert_positions(asserted_positions, expected_tuples, lanes:)
expected_positions =
expected_tuples.collect do |testing_row|
Trailblazer::Workflow::State::Discovery.position_from_tuple(lanes, *testing_row[:tuple])
end

sorting_block = ->(a, b) { a.activity.object_id <=> b.activity.object_id }

sorted_asserted_positions = asserted_positions.to_a.sort(&sorting_block)
sorted_expected_positions = expected_positions.sort(&sorting_block)

sorted_asserted_positions.collect.with_index do |position, index|
assert_equal position, sorted_expected_positions[index],
Assertions.error_message_for(position, sorted_expected_positions[index], lanes: lanes)
end

# FIXME: figure out why we can't just compare the entire array!
# assert_equal sorted_asserted_positions, sorted_expected_positions
end

# Compile error message when the expected lane position doesn't match the actual one.
def self.error_message_for(position, expected_position, lanes:) # TODO: test me.
# TODO: make the labels use UTF8 icons etc, as in the CLI rendering code.
expected_label = State::Discovery::Testing.serialize_lane_position(position, lanes: lanes)[:comment]
actual_label = State::Discovery::Testing.serialize_lane_position(expected_position, lanes: lanes)[:comment]

"Lane #{lanes.invert[position.activity].inspect}:\n expected #{expected_label}\n actual #{actual_label}"
end

# Grab the start_position and expected_lane_positions from the discovered plan, run
# the collaboration from there and check if it actually reached the expected configuration.
def assert_advance(event_label, test_plan:, lanes:, schema:, message_flow:, expected_ctx:, ctx: {seq: []}, **) # TODO: allow {ctx}
testing_row = test_plan.find { |row| row[:event_label] == event_label }

start_position = testing_row[:start_position]
start_tuple = start_position[:tuple] # #{start_position[:comment]}
start_position = Trailblazer::Workflow::State::Discovery.position_from_tuple(lanes, *start_tuple)

# current position.
#DISCUSS: here, we could also ask the State layer for the start configuration, on a different level.
lane_positions = testing_row[:start_configuration].collect do |row|
Trailblazer::Workflow::State::Discovery.position_from_tuple(lanes, *row[:tuple])
end

lane_positions = Trailblazer::Workflow::Collaboration::Positions.new(lane_positions)

ctx_for_advance = ctx

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

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

message_flow: message_flow,
)

assert_positions configuration[:lane_positions], testing_row[:expected_lane_positions], lanes: lanes

# assert_equal ctx.inspect, expected_ctx.inspect
ctx
end

end

module Plan
module_function

# Code fragment with assertions for the discovered/configured test plan.
def for(test_structure, input:)
code_string = test_structure.collect do |row|


# raise row[:start_configuration].inspect
start_position = row[:start_position]

tuples_for_expected = row[:expected_lane_positions]
def for(discovered_states, input:, **options)
code_string = discovered_states.collect do |row|

# TODO: introduce a "test structure" that computes event label, and then links to the specific row of the {discovered_states}.
# that way, we only compute the "ID" once.
event_label = CommentHeader.start_position_label(row[:positions_before][1], row, **options)

%(
# test: #{row[:event_label]}
ctx = assert_advance "#{row[:event_label]}", expected_ctx: {}, test_plan: testing_structure, lanes: lanes, schema: schema, message_flow: message_flow
# test: #{event_label}
ctx = assert_advance "#{event_label}", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]
)
end
@@ -95,16 +24,8 @@ def for(test_structure, input:)
# don't change with code modifications.
module Structure
module_function
# {
# start_position: start_p___FIXME,
# start_configuration: serialized_start_configuration,
# expected_lane_positions: expected_lane_positions,

# expected_outcome: expected_outcome= additional_state_data[[state.state_from_discovery_fixme.object_id, :outcome]],

# event_label: default_event_label(start_p___FIXME, expected_outcome: expected_outcome, lane_icons: lane_icons)
# }
def call(discovered_states, **options)
def serialize(discovered_states, **options)
discovered_states.collect do |row|
{
event_label: CommentHeader.start_position_label(row[:positions_before][1], row, **options),
@@ -115,6 +36,34 @@ def call(discovered_states, **options)
end
end

def deserialize(id_structure, lanes_cfg:, **)
# DISCUSS: don't unserialize the entire thing at once, presently we only allow "lookups".
Deserialized.new(id_structure, lanes_cfg)
end

class Deserialized
def initialize(id_structure, lanes_cfg)
@id_structure = id_structure
@lanes_cfg = lanes_cfg

@lane_label_2_activity = lanes_cfg.values.collect { |cfg| [cfg[:label], cfg[:activity]] }.to_h
end

# Retrieve real tuple for id tuple.
def [](lane_label, task_id)
position_from_tuple(lane_label, task_id)
end

# "Deserialize" a {Position} from a serialized tuple.
# Opposite of {#id_tuple_for}.
def position_from_tuple(lane_label, task_id)
lane_activity = @lane_label_2_activity[lane_label]
task = Trailblazer::Activity::Introspect.Nodes(lane_activity, id: task_id).task

Collaboration::Position.new(lane_activity, task)
end
end

def serialize_configuration(start_positions, **options)
start_positions.collect do |activity, suspend|
serialize_position(activity, suspend, **options)
@@ -127,15 +76,6 @@ def id_tuple_for(activity, task, lanes_cfg:)

return activity_id, task_id
end
# FIXME: move me somewhere else!
# "Deserialize" a {Position} from a serialized tuple.
# Opposite of {#id_tuple_for}.
# def position_from_tuple(lanes, lane_id, task_id)
# lane_activity = lanes[lane_id]
# task = Trailblazer::Activity::Introspect.Nodes(lane_activity, id: task_id).task

# Collaboration::Position.new(lane_activity, task)
# end

# A lane position is always a {Suspend} (or a terminus).
def self.serialize_position(activity, suspend, **options)
85 changes: 83 additions & 2 deletions test/discovery_test.rb
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@ def self.states
}
)

return states, lanes_sorted, lanes_cfg
return states, lanes_sorted, lanes_cfg, schema, message_flow
end

it "Discovery.call" do
@@ -330,10 +330,91 @@ class DiscoveryTestPlanTest < Minitest::Spec
it "render structure" do
states, lanes_sorted, lanes_cfg = DiscoveryTest.states()

plan_structure = Trailblazer::Workflow::Test::Plan::Structure.(states, lanes_cfg: lanes_cfg)
plan_structure = Trailblazer::Workflow::Test::Plan::Structure.serialize(states, lanes_cfg: lanes_cfg)
# pp plan_structure
testing_json = JSON.pretty_generate(plan_structure)
# File.write "test/discovery_testing_json.json", testing_json
assert_equal testing_json, File.read("test/discovery_testing_json.json")

structure = Trailblazer::Workflow::Test::Plan::Structure.deserialize(plan_structure, lanes_cfg: lanes_cfg)

assert_equal structure.position_from_tuple("lifecycle", "suspend-gw-to-catch-before-Activity_0wwfenp").to_a,
[lifecycle = lanes_cfg.values[0][:activity], Trailblazer::Activity::Introspect.Nodes(lifecycle, id: "suspend-gw-to-catch-before-Activity_0wwfenp").task]


end
end

class TestPlanExecutionTest < Minitest::Spec
include Trailblazer::Workflow::Test::Assertions

it "run test plan" do
states, lanes_sorted, lanes_cfg, schema, message_flow = DiscoveryTest.states()

#@ Test plan
puts Trailblazer::Workflow::Test::Plan.for(states, lanes_cfg: lanes_cfg, input: {})

test_plan_structure = states

# test: ☝ ⏵︎Create form
ctx = assert_advance "☝ ⏵︎Create form", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Create
ctx = assert_advance "☝ ⏵︎Create", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Create ⛞
ctx = assert_advance "☝ ⏵︎Create ⛞", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Update form
ctx = assert_advance "☝ ⏵︎Update form", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Notify approver
ctx = assert_advance "☝ ⏵︎Notify approver", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Update
ctx = assert_advance "☝ ⏵︎Update", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Notify approver ⛞
ctx = assert_advance "☝ ⏵︎Notify approver ⛞", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Delete? form
ctx = assert_advance "☝ ⏵︎Delete? form", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Publish
ctx = assert_advance "☝ ⏵︎Publish", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Update ⛞
ctx = assert_advance "☝ ⏵︎Update ⛞", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Revise form
ctx = assert_advance "☝ ⏵︎Revise form", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Delete
ctx = assert_advance "☝ ⏵︎Delete", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Cancel
ctx = assert_advance "☝ ⏵︎Cancel", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Archive
ctx = assert_advance "☝ ⏵︎Archive", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

# test: ☝ ⏵︎Revise
ctx = assert_advance "☝ ⏵︎Revise", expected_ctx: {}, test_plan: test_plan_structure, lanes_cfg: lanes_cfg, schema: schema, message_flow: message_flow
assert_exposes ctx, seq: [:revise, :revise], reader: :[]

end
end

0 comments on commit a956674

Please sign in to comment.