From 1eb25f236f449ada23a868422f44693a6ef84f7f Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Fri, 6 Oct 2023 14:42:32 -0400 Subject: [PATCH] Abort if StartAt or next_state is not valid I was running a workflow with an invalid StartAt This caused a strange error before ------ ``` lib/floe/workflow.rb:76:in `step_nonblock': undefined method `run_nonblock!' for nil:NilClass (NoMethodError) current_state.run_nonblock! ^^^^^^^^^^^^^^ from lib/floe/workflow.rb:63:in `step' from lib/floe/workflow.rb:58:in `run!' from exe/floe:37:in `' ``` after ----- ``` {"Error"=>"States.Runtime", "Cause"=>"State \"FirstState\" does not exist"} ``` --- lib/floe/workflow.rb | 18 ++++++++++++++++-- spec/workflow_spec.rb | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/floe/workflow.rb b/lib/floe/workflow.rb index 5f288f31..9fa6c791 100644 --- a/lib/floe/workflow.rb +++ b/lib/floe/workflow.rb @@ -71,8 +71,8 @@ def run_nonblock def step_nonblock return Errno::EPERM if end? + return 0 unless step_next - step_next current_state.run_nonblock! end @@ -103,7 +103,21 @@ def current_state private def step_next - context.state = {"Name" => context.next_state, "Input" => context.output} if context.next_state + desired_state = context.next_state || context.state_name + if !@states_by_name.key?(desired_state) + context.state["Error"] = "States.Runtime" + context.state["Cause"] = "State \"#{desired_state}\" does not exist" + context.output = {"Error" => context.state["Error"], "Cause" => context.state["Cause"]} + context.execution["StartTime"] ||= Time.now.utc + context.execution["EndTime"] = Time.now.utc.iso8601 + return false + end + + if context.next_state + context.state = {"Name" => context.next_state, "Input" => context.output} + end + + true end end end diff --git a/spec/workflow_spec.rb b/spec/workflow_spec.rb index 8eb854c7..2f6fa7d2 100644 --- a/spec/workflow_spec.rb +++ b/spec/workflow_spec.rb @@ -93,6 +93,26 @@ expect(ctx.running?).to eq(true) expect(ctx.ended?).to eq(false) end + + it "detects invalid StartAt" do + workflow = Floe::Workflow.new({"StartAt" => "Bogus", "States" => {"FirstState" => {"Type" => "Succeed"}}}, ctx, {}) + + workflow.run_nonblock + + expect(ctx.running?).to eq(false) + expect(ctx.ended?).to eq(true) + expect(ctx.status).to eq("failure") + end + + it "detects invalid Next" do + workflow = Floe::Workflow.new({"StartAt" => "FirstState", "States" => {"FirstState" => {"Type" => "Pass", "Next" => "Bogus"}}}, ctx, {}) + + workflow.run_nonblock + + expect(ctx.running?).to eq(false) + expect(ctx.ended?).to eq(true) + expect(ctx.status).to eq("failure") + end end describe "#step" do