fix: don't explode when one port fails

Phillip Davis created

Change summary

lib/port_repo.rb       | 18 ++++++++-------
test/test_port_repo.rb | 49 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+), 8 deletions(-)

Detailed changes

lib/port_repo.rb 🔗

@@ -134,13 +134,15 @@ class PortRepo
 protected
 
 	def tick(port)
-		@step_repo.find(port).then { |step|
-			@output.info(port.id, :class, step.class)
-			if @dry_run
-				@output.info("DRY", :dry, "Not taking action")
-			else
-				step.perform_next_step
-			end
-		}
+		EMPromise.resolve(nil).then {
+			@step_repo.find(port).then { |step|
+				@output.info(port.id, :class, step.class)
+				if @dry_run
+					@output.info("DRY", :dry, "Not taking action")
+				else
+					step.perform_next_step
+				end
+			}
+		}.catch { |e| @output.error(port.id, :catch, e) }
 	end
 end

test/test_port_repo.rb 🔗

@@ -58,6 +58,55 @@ class PortRepoDbTest < Minitest::Test
 	em :test_list_empty_when_no_rows
 end
 
+class PortRepoTickTest < Minitest::Test
+	def setup
+		@expected_output = Minitest::Mock.new
+		@output = MockOutputs.new(@expected_output)
+	end
+
+	def test_process_continues_after_individual_port_error
+		error = RuntimeError.new("port exploded")
+
+		failing_port = PortRepo::Fake::FakePort.new(
+			"T02", "COMPLETE", DateTime.now, DateTime.now,
+			"0001", "2223334444", "testroute"
+		)
+		ok_port = PortRepo::Fake::FakePort.new(
+			"T01", "SUBMITTED", nil, DateTime.now - 1,
+			"ignored", "9998887777", "testroute"
+		)
+
+		failing_step = Minitest::Mock.new(
+			PortingStepRepo::Frozen.new(failing_port, output: @output)
+		)
+		failing_step.expect(:perform_next_step, EMPromise.reject(error))
+
+		ok_step = Minitest::Mock.new(
+			PortingStepRepo::Frozen.new(ok_port, output: @output)
+		)
+		ok_step.expect(:perform_next_step, EMPromise.resolve(nil))
+
+		step_repo = Minitest::Mock.new(PortingStepRepo.new(output: @output))
+		step_repo.expect(:find, EMPromise.resolve(failing_step), [failing_port])
+		step_repo.expect(:find, EMPromise.resolve(ok_step), [ok_port])
+
+		@expected_output.expect(:error, nil, [failing_port.id, :catch, error])
+		@expected_output.expect(
+			:info, nil, [failing_port.id, :class, failing_step.class]
+		)
+		@expected_output.expect(:info, nil, [ok_port.id, :class, ok_step.class])
+
+		repo = PortRepo::Fake.new(@output)
+		repo.instance_variable_set(:@step_repo, step_repo)
+		repo.stub(:list, EMPromise.resolve([failing_port, ok_port])) do
+			repo.process.sync
+		end
+
+		@output.verify
+	end
+	em :test_process_continues_after_individual_port_error
+end
+
 class PortRepoBandwidthTest < Minitest::Test
 	def setup
 		@output = FullManual.new