From 913c20486c33344a27df54ace1ab1f23813c6672 Mon Sep 17 00:00:00 2001 From: Nathan Glass Date: Wed, 15 Dec 2021 18:21:04 -0800 Subject: [PATCH 1/2] Make error deserialization more resilient --- lib/temporal/workflow/errors.rb | 3 +- .../unit/lib/temporal/workflow/errors_spec.rb | 38 ++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/temporal/workflow/errors.rb b/lib/temporal/workflow/errors.rb index d7c294f5..cea7f471 100644 --- a/lib/temporal/workflow/errors.rb +++ b/lib/temporal/workflow/errors.rb @@ -25,7 +25,7 @@ def self.generate_error(failure, default_exception_class = StandardError) begin exception = exception_class.new(message) - rescue ArgumentError => deserialization_error + rescue => deserialization_error # We don't currently support serializing/deserializing exceptions with more than one argument. message = "#{exception_class}: #{message}" exception = default_exception_class.new(message) @@ -33,6 +33,7 @@ def self.generate_error(failure, default_exception_class = StandardError) "Could not instantiate original error. Defaulting to StandardError.", { original_error: failure.application_failure_info.type, + instantiation_error_class: deserialization_error.class.to_s, instantiation_error_message: deserialization_error.message, }, ) diff --git a/spec/unit/lib/temporal/workflow/errors_spec.rb b/spec/unit/lib/temporal/workflow/errors_spec.rb index a9e053f6..13937473 100644 --- a/spec/unit/lib/temporal/workflow/errors_spec.rb +++ b/spec/unit/lib/temporal/workflow/errors_spec.rb @@ -4,6 +4,14 @@ class ErrorWithTwoArgs < StandardError def initialize(message, another_argument); end end +class ErrorThatRaisesInInitialize < StandardError + def initialize(message) + # This class simulates an error class that has bugs in its initialize method, or where + # the arg isn't a string. It raises TypeError (String can't be coerced into Integer) + 1 + message + end +end + class SomeError < StandardError; end describe Temporal::Workflow::Errors do @@ -51,7 +59,7 @@ class SomeError < StandardError; end end - it "falls back to StandardError when the client can't initialize the error class" do + it "falls back to StandardError when the client can't initialize the error class due to arity" do allow(Temporal.logger).to receive(:error) message = "An error message" @@ -73,10 +81,38 @@ class SomeError < StandardError; end 'Could not instantiate original error. Defaulting to StandardError.', { original_error: "ErrorWithTwoArgs", + instantiation_error_class: "ArgumentError", instantiation_error_message: "wrong number of arguments (given 1, expected 2)", }, ) end + it "falls back to StandardError when the client can't initialize the error class when initialize doesn't take a string" do + allow(Temporal.logger).to receive(:error) + + message = "An error message" + stack_trace = ["a fake backtrace"] + failure = Fabricate( + :api_application_failure, + message: message, + backtrace: stack_trace, + error_class: ErrorThatRaisesInInitialize.to_s, + ) + + e = Temporal::Workflow::Errors.generate_error(failure) + expect(e).to be_a(StandardError) + expect(e.message).to eq("ErrorThatRaisesInInitialize: An error message") + expect(e.backtrace).to eq(stack_trace) + expect(Temporal.logger) + .to have_received(:error) + .with( + 'Could not instantiate original error. Defaulting to StandardError.', + { + original_error: "ErrorThatRaisesInInitialize", + instantiation_error_class: "TypeError", + instantiation_error_message: "String can't be coerced into Integer", + }, + ) + end end end From 0dbd46634dd0871d4da568d5456ef26a5af07afc Mon Sep 17 00:00:00 2001 From: Nathan Glass Date: Wed, 5 Jan 2022 10:17:37 -0800 Subject: [PATCH 2/2] Raise TypeError directly in the test --- spec/unit/lib/temporal/workflow/errors_spec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/unit/lib/temporal/workflow/errors_spec.rb b/spec/unit/lib/temporal/workflow/errors_spec.rb index 13937473..05d5f82a 100644 --- a/spec/unit/lib/temporal/workflow/errors_spec.rb +++ b/spec/unit/lib/temporal/workflow/errors_spec.rb @@ -7,8 +7,9 @@ def initialize(message, another_argument); end class ErrorThatRaisesInInitialize < StandardError def initialize(message) # This class simulates an error class that has bugs in its initialize method, or where - # the arg isn't a string. It raises TypeError (String can't be coerced into Integer) - 1 + message + # the arg isn't a string. It raises the sort of TypeError that would happen if you wrote + # 1 + message + raise TypeError.new("String can't be coerced into Integer") end end