From 7e626b4ab8a733fb40aca8f1deeb1c4aab9afa36 Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Fri, 1 Dec 2023 15:31:16 +0300 Subject: [PATCH 1/5] TD-820: Adds support for nested unknown errors --- src/payproc_errors.erl | 6 ++++++ test/payproc_errors_SUITE.erl | 28 +++++++++++++++++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/payproc_errors.erl b/src/payproc_errors.erl index 43a19e6..b0cc5d8 100644 --- a/src/payproc_errors.erl +++ b/src/payproc_errors.erl @@ -148,6 +148,12 @@ join(Code, Sub) -> [Code, $:, Sub]. %% -spec type_by_field(static_code(), type()) -> atom() | undefined. +type_by_field({unknown_error, DynamicCode}, _Type) -> + try + binary_to_existing_atom(DynamicCode) + catch + error:badarg -> unknown_error + end; type_by_field(Code, Type) -> case [Field || Field = {FCode, _} <- struct_info(Type), Code =:= FCode] of [{_, SubType}] -> SubType; diff --git a/test/payproc_errors_SUITE.erl b/test/payproc_errors_SUITE.erl index 0363305..7901b07 100644 --- a/test/payproc_errors_SUITE.erl +++ b/test/payproc_errors_SUITE.erl @@ -6,8 +6,8 @@ -export([all/0]). -export([known_error_test/1]). --export([unknown_error_test/1]). -export([unknown_error_atom_test/1]). +-export([unknown_error_nested_test/1]). -export([bad_static_type_test/1]). -export([formatting_test/1]). -export([from_notation_test/1]). @@ -23,8 +23,8 @@ all() -> [ known_error_test, - unknown_error_test, unknown_error_atom_test, + unknown_error_nested_test, bad_static_type_test, formatting_test, from_notation_test, @@ -62,13 +62,27 @@ unknown_error_atom_test(_C) -> DE = payproc_errors:construct('PaymentFailure', SE), ok = payproc_errors:match('PaymentFailure', DE, fun(E) when SE =:= E -> ok end). --spec unknown_error_test(config()) -> _. -unknown_error_test(_C) -> - UnknownCode = erlang:atom_to_binary(bad_error_code, utf8), +-spec unknown_error_nested_test(config()) -> _. +unknown_error_nested_test(_C) -> DE = #domain_Failure{ - code = UnknownCode + code = <<"no_route_found">>, + sub = #domain_SubFailure{ + code = <<"forbidden">>, + sub = #domain_SubFailure{ + code = <<"rejected_routes">>, + sub = #domain_SubFailure{ + code = <<"limit_hold_reject">> + } + } + } }, - SE = {{unknown_error, UnknownCode}, #payproc_error_GeneralFailure{}}, + SE = + {no_route_found, + {forbidden, + { + {unknown_error, <<"rejected_routes">>}, + {{unknown_error, <<"limit_hold_reject">>}, #payproc_error_GeneralFailure{}} + }}}, DE = payproc_errors:construct('PaymentFailure', SE), ok = payproc_errors:match('PaymentFailure', DE, fun(E) when SE =:= E -> ok end). From 498bec1ac0da1e1f6d3efb97917acb3b79804f79 Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Fri, 1 Dec 2023 15:42:35 +0300 Subject: [PATCH 2/5] Extends testcase with equivalent static error match check --- test/payproc_errors_SUITE.erl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/payproc_errors_SUITE.erl b/test/payproc_errors_SUITE.erl index 7901b07..8b17b84 100644 --- a/test/payproc_errors_SUITE.erl +++ b/test/payproc_errors_SUITE.erl @@ -77,6 +77,15 @@ unknown_error_nested_test(_C) -> } }, SE = + {no_route_found, + { + {unknown_error, <<"forbidden">>}, + { + {unknown_error, <<"rejected_routes">>}, + {{unknown_error, <<"limit_hold_reject">>}, #payproc_error_GeneralFailure{}} + } + }}, + EquivalentSE = {no_route_found, {forbidden, { @@ -84,7 +93,7 @@ unknown_error_nested_test(_C) -> {{unknown_error, <<"limit_hold_reject">>}, #payproc_error_GeneralFailure{}} }}}, DE = payproc_errors:construct('PaymentFailure', SE), - ok = payproc_errors:match('PaymentFailure', DE, fun(E) when SE =:= E -> ok end). + ok = payproc_errors:match('PaymentFailure', DE, fun(E) when EquivalentSE =:= E -> ok end). -spec bad_static_type_test(config()) -> _. bad_static_type_test(_C) -> From d9f8d7c534bc3ac5c8caccb2171ec38d77fddf0e Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Fri, 1 Dec 2023 16:30:13 +0300 Subject: [PATCH 3/5] Adds more test cases for nested unknown errors --- src/payproc_errors.erl | 8 +++---- test/ *Minibuf-1* | 1 + test/payproc_errors_SUITE.erl | 44 ++++++++++++++++++++++------------- 3 files changed, 33 insertions(+), 20 deletions(-) create mode 100644 test/ *Minibuf-1* diff --git a/src/payproc_errors.erl b/src/payproc_errors.erl index b0cc5d8..ff5cce4 100644 --- a/src/payproc_errors.erl +++ b/src/payproc_errors.erl @@ -81,10 +81,10 @@ sub_error_to_static(Type, #domain_SubFailure{code = Code, sub = SDE}) -> to_static(Code, Type, SDE) -> StaticCode = code_to_static(Code), case type_by_field(StaticCode, Type) of - SubType when SubType =/= undefined -> - {StaticCode, sub_error_to_static(SubType, SDE)}; undefined -> - {{unknown_error, Code}, #payproc_error_GeneralFailure{}} + {{unknown_error, Code}, sub_error_to_static(undefined, SDE)}; + SubType -> + {StaticCode, sub_error_to_static(SubType, SDE)} end. -spec code_to_static(dynamic_code()) -> static_code(). @@ -150,7 +150,7 @@ join(Code, Sub) -> [Code, $:, Sub]. -spec type_by_field(static_code(), type()) -> atom() | undefined. type_by_field({unknown_error, DynamicCode}, _Type) -> try - binary_to_existing_atom(DynamicCode) + erlang:binary_to_existing_atom(DynamicCode, utf8) catch error:badarg -> unknown_error end; diff --git a/test/ *Minibuf-1* b/test/ *Minibuf-1* new file mode 100644 index 0000000..446faf5 --- /dev/null +++ b/test/ *Minibuf-1* @@ -0,0 +1 @@ +Yank from kill-ring: diff --git a/test/payproc_errors_SUITE.erl b/test/payproc_errors_SUITE.erl index 8b17b84..f800f63 100644 --- a/test/payproc_errors_SUITE.erl +++ b/test/payproc_errors_SUITE.erl @@ -8,6 +8,7 @@ -export([known_error_test/1]). -export([unknown_error_atom_test/1]). -export([unknown_error_nested_test/1]). +-export([unknown_error_nested_mixed_test/1]). -export([bad_static_type_test/1]). -export([formatting_test/1]). -export([from_notation_test/1]). @@ -25,6 +26,7 @@ all() -> known_error_test, unknown_error_atom_test, unknown_error_nested_test, + unknown_error_nested_mixed_test, bad_static_type_test, formatting_test, from_notation_test, @@ -62,8 +64,30 @@ unknown_error_atom_test(_C) -> DE = payproc_errors:construct('PaymentFailure', SE), ok = payproc_errors:match('PaymentFailure', DE, fun(E) when SE =:= E -> ok end). +-define(NESTED_UNKNOWN_SUBCODES, + { + {unknown_error, <<"rejected_routes">>}, + {{unknown_error, <<"limit_hold_reject">>}, #payproc_error_GeneralFailure{}} + } +). + -spec unknown_error_nested_test(config()) -> _. unknown_error_nested_test(_C) -> + DE = #domain_Failure{ + code = <<"forbidden">>, + sub = #domain_SubFailure{ + code = <<"rejected_routes">>, + sub = #domain_SubFailure{ + code = <<"limit_hold_reject">> + } + } + }, + SE = {{unknown_error, <<"forbidden">>}, ?NESTED_UNKNOWN_SUBCODES}, + DE = payproc_errors:construct('PaymentFailure', SE), + ok = payproc_errors:match('PaymentFailure', DE, fun(E) when SE =:= E -> ok end). + +-spec unknown_error_nested_mixed_test(config()) -> _. +unknown_error_nested_mixed_test(_C) -> DE = #domain_Failure{ code = <<"no_route_found">>, sub = #domain_SubFailure{ @@ -76,22 +100,8 @@ unknown_error_nested_test(_C) -> } } }, - SE = - {no_route_found, - { - {unknown_error, <<"forbidden">>}, - { - {unknown_error, <<"rejected_routes">>}, - {{unknown_error, <<"limit_hold_reject">>}, #payproc_error_GeneralFailure{}} - } - }}, - EquivalentSE = - {no_route_found, - {forbidden, - { - {unknown_error, <<"rejected_routes">>}, - {{unknown_error, <<"limit_hold_reject">>}, #payproc_error_GeneralFailure{}} - }}}, + SE = {no_route_found, {{unknown_error, <<"forbidden">>}, ?NESTED_UNKNOWN_SUBCODES}}, + EquivalentSE = {no_route_found, {forbidden, ?NESTED_UNKNOWN_SUBCODES}}, DE = payproc_errors:construct('PaymentFailure', SE), ok = payproc_errors:match('PaymentFailure', DE, fun(E) when EquivalentSE =:= E -> ok end). @@ -110,6 +120,8 @@ bad_static_type_test(_C) -> (catch payproc_errors:construct('RefundFailure', {preauthorization_failed, #payproc_error_GeneralFailure{}})), {'EXIT', {badarg, _}} = (catch payproc_errors:construct('RefundFailure', Bad)), + {'EXIT', {badarg, _}} = + (catch payproc_errors:construct('PaymentFailure', {{unknown_error, <<"forbidden">>}, Bad})), ok. -spec formatting_test(config()) -> _. From ec161a92338679f387adc06b0f534822a764ba0a Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Fri, 1 Dec 2023 16:30:52 +0300 Subject: [PATCH 4/5] Oooopsie --- test/ *Minibuf-1* | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test/ *Minibuf-1* diff --git a/test/ *Minibuf-1* b/test/ *Minibuf-1* deleted file mode 100644 index 446faf5..0000000 --- a/test/ *Minibuf-1* +++ /dev/null @@ -1 +0,0 @@ -Yank from kill-ring: From 2dbf09871c2aa5661da25fb2cd798c6ac91f1767 Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Mon, 4 Dec 2023 11:44:41 +0300 Subject: [PATCH 5/5] Fixes support of '{unknown_error, _}' --- rebar.lock | 2 +- src/payproc_errors.erl | 12 +++++------- test/payproc_errors_SUITE.erl | 8 ++++++++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/rebar.lock b/rebar.lock index 5d15125..33c4ee2 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,4 +1,4 @@ [{<<"damsel">>, {git,"https://github.com/valitydev/damsel.git", - {ref,"dac2cb599499cc0701e60856f4092c9ab283eedf"}}, + {ref,"38a420da68166d876153ea9d5e8701f636c11a0e"}}, 0}]. diff --git a/src/payproc_errors.erl b/src/payproc_errors.erl index ff5cce4..d87dc87 100644 --- a/src/payproc_errors.erl +++ b/src/payproc_errors.erl @@ -81,7 +81,7 @@ sub_error_to_static(Type, #domain_SubFailure{code = Code, sub = SDE}) -> to_static(Code, Type, SDE) -> StaticCode = code_to_static(Code), case type_by_field(StaticCode, Type) of - undefined -> + SubType when SubType =:= undefined orelse SubType =:= unknown_error -> {{unknown_error, Code}, sub_error_to_static(undefined, SDE)}; SubType -> {StaticCode, sub_error_to_static(SubType, SDE)} @@ -148,12 +148,10 @@ join(Code, Sub) -> [Code, $:, Sub]. %% -spec type_by_field(static_code(), type()) -> atom() | undefined. -type_by_field({unknown_error, DynamicCode}, _Type) -> - try - erlang:binary_to_existing_atom(DynamicCode, utf8) - catch - error:badarg -> unknown_error - end; +type_by_field(_Code, undefined) -> + undefined; +type_by_field({unknown_error, _DynamicCode}, _Type) -> + unknown_error; type_by_field(Code, Type) -> case [Field || Field = {FCode, _} <- struct_info(Type), Code =:= FCode] of [{_, SubType}] -> SubType; diff --git a/test/payproc_errors_SUITE.erl b/test/payproc_errors_SUITE.erl index f800f63..99790c0 100644 --- a/test/payproc_errors_SUITE.erl +++ b/test/payproc_errors_SUITE.erl @@ -73,6 +73,10 @@ unknown_error_atom_test(_C) -> -spec unknown_error_nested_test(config()) -> _. unknown_error_nested_test(_C) -> + %% NOTE Ensure atoms exist + _ = rejected_routes, + _ = limit_hold_reject, + DE = #domain_Failure{ code = <<"forbidden">>, sub = #domain_SubFailure{ @@ -88,6 +92,10 @@ unknown_error_nested_test(_C) -> -spec unknown_error_nested_mixed_test(config()) -> _. unknown_error_nested_mixed_test(_C) -> + %% NOTE Ensure atoms exist + _ = rejected_routes, + _ = limit_hold_reject, + DE = #domain_Failure{ code = <<"no_route_found">>, sub = #domain_SubFailure{