TD-677: Add entity ID check before creation (#20)

* TD-677: Add entity ID check before creation

* Fix compile

* Fix spec and format

* Add mock get

* Fix tests

* Add tests

* Fix dialyzer
This commit is contained in:
ndiezel0 2023-08-15 02:29:41 +05:00 committed by GitHub
parent e84319bb13
commit 7216d3217d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 458 additions and 63 deletions

View File

@ -47,7 +47,12 @@ generate_id(Params, ResourceThrift, HandlerContext) ->
},
case wapi_backend_utils:gen_id(destination, NewParams, HandlerContext) of
{ok, ID} ->
{ok, ID};
case is_id_unknown(ID, Params, HandlerContext) of
true ->
{ok, ID};
false ->
generate_id(Params, ResourceThrift, HandlerContext)
end;
{error, {external_id_conflict, ID}} ->
% Delete after deploy
ExternalID = maps:get(<<"externalID">>, Params, undefined),
@ -58,12 +63,42 @@ generate_id(Params, ResourceThrift, HandlerContext) ->
generate_id_legacy(Params, HandlerContext) ->
case wapi_backend_utils:gen_id(destination, Params, HandlerContext) of
{ok, ID} ->
{ok, ID};
case is_id_unknown(ID, Params, HandlerContext) of
true ->
{ok, ID};
false ->
generate_id_legacy(Params, HandlerContext)
end;
{error, {external_id_conflict, ID}} ->
ExternalID = maps:get(<<"externalID">>, Params, undefined),
{error, {external_id_conflict, {ID, ExternalID}}}
end.
is_id_unknown(
ID,
#{
<<"identity">> := IdentityID,
<<"currency">> := CurrencyID,
<<"name">> := Name
},
HandlerContext
) ->
case get(ID, HandlerContext) of
{error, {destination, notfound}} ->
true;
{ok,
#{
<<"id">> := ID,
<<"identity">> := IdentityID,
<<"currency">> := CurrencyID,
<<"name">> := Name
},
_Owner} ->
true;
{ok, _NonMatchingDestination, _Owner} ->
false
end.
create_request(ID, Params, ResourceThrift, HandlerContext) ->
% mixing the attributes needed for marshaling
MarshaledParams = marshal(destination_params, Params#{

View File

@ -9,8 +9,8 @@
-export_type([identity_state/0]).
-export([create_identity/2]).
-export([get_identity/2]).
-export([create/2]).
-export([get/2]).
-export([get_thrift_identity/2]).
-export([get_identity_withdrawal_methods/2]).
@ -21,10 +21,10 @@
%% Pipeline
-spec get_identity(id(), handler_context()) ->
-spec get(id(), handler_context()) ->
{ok, response_data(), id()}
| {error, {identity, notfound}}.
get_identity(IdentityID, HandlerContext) ->
get(IdentityID, HandlerContext) ->
case get_thrift_identity(IdentityID, HandlerContext) of
{ok, IdentityThrift} ->
{ok, Owner} = wapi_backend_utils:get_entity_owner(identity, IdentityThrift),
@ -33,7 +33,7 @@ get_identity(IdentityID, HandlerContext) ->
Error
end.
-spec create_identity(params(), handler_context()) ->
-spec create(params(), handler_context()) ->
result(
map(),
{provider, notfound}
@ -41,14 +41,42 @@ get_identity(IdentityID, HandlerContext) ->
| inaccessible
| _Unexpected
).
create_identity(Params, HandlerContext) ->
case create_id(identity, Params, HandlerContext) of
create(Params, HandlerContext) ->
case wapi_backend_utils:gen_id(identity, Params, HandlerContext) of
{ok, ID} ->
create_identity(ID, Params, HandlerContext);
case is_id_unknown(ID, Params, HandlerContext) of
true ->
create_identity(ID, Params, HandlerContext);
false ->
create(Params, HandlerContext)
end;
{error, {external_id_conflict, _}} = Error ->
Error
end.
is_id_unknown(
ID,
#{
<<"name">> := Name,
<<"provider">> := Provider
},
HandlerContext
) ->
case get(ID, HandlerContext) of
{error, {identity, notfound}} ->
true;
{ok,
#{
<<"id">> := ID,
<<"name">> := Name,
<<"provider">> := Provider
},
_Owner} ->
true;
{ok, _NonMatchingIdentity, _Owner} ->
false
end.
create_identity(ID, Params, HandlerContext) ->
IdentityParams = marshal(identity_params, Params#{<<"id">> => ID}),
Request = {fistful_identity, 'Create', {IdentityParams, marshal(context, create_context(Params))}},
@ -94,13 +122,6 @@ get_identity_withdrawal_methods(IdentityID, HandlerContext) ->
%% Internal
%%
create_id(Type, Params, HandlerContext) ->
wapi_backend_utils:gen_id(
Type,
Params,
HandlerContext
).
create_context(Params) ->
KV = {<<"name">>, maps:get(<<"name">>, Params, undefined)},
wapi_backend_utils:add_to_ctx(KV, wapi_backend_utils:make_ctx(Params)).

View File

@ -1,4 +1,4 @@
-module(wapi_w2w_backend).
-module(wapi_w2w_transfer_backend).
-type request_data() :: wapi_wallet_handler:request_data().
-type handler_context() :: wapi_handler_utils:handler_context().
@ -7,31 +7,61 @@
-type id() :: binary().
-type external_id() :: id().
-export([create_transfer/2]).
-export([get_transfer/2]).
-export([create/2]).
-export([get/2]).
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
-include_lib("fistful_proto/include/fistful_w2w_transfer_thrift.hrl").
-include_lib("fistful_proto/include/fistful_w2w_status_thrift.hrl").
-spec create_transfer(request_data(), handler_context()) -> {ok, response_data()} | {error, CreateError} when
-spec create(request_data(), handler_context()) -> {ok, response_data()} | {error, CreateError} when
CreateError ::
{external_id_conflict, external_id()}
| {wallet_from | wallet_to, notfound | inaccessible}
| bad_w2w_transfer_amount
| not_allowed_currency
| inconsistent_currency.
create_transfer(Params, HandlerContext) ->
create(Params, HandlerContext) ->
case wapi_backend_utils:gen_id(w2w_transfer, Params, HandlerContext) of
{ok, ID} ->
Context = wapi_backend_utils:make_ctx(Params),
create_transfer(ID, Params, Context, HandlerContext);
case is_id_unknown(ID, Params, HandlerContext) of
true ->
Context = wapi_backend_utils:make_ctx(Params),
create(ID, Params, Context, HandlerContext);
false ->
create(Params, HandlerContext)
end;
{error, {external_id_conflict, _}} = Error ->
Error
end.
create_transfer(ID, Params, Context, HandlerContext) ->
is_id_unknown(
ID,
#{
<<"sender">> := SenderID,
<<"receiver">> := ReceiverID,
<<"body">> := Body
},
HandlerContext
) ->
case get(ID, HandlerContext) of
{error, {w2w_transfer, {unknown_w2w_transfer, ID}}} ->
true;
{ok,
#{
<<"id">> := ID,
<<"sender">> := SenderID,
<<"receiver">> := ReceiverID,
<<"body">> := Body
},
_Owner} ->
true;
{ok, _NonMatchingIdentity, _Owner} ->
false
end.
create(ID, Params, Context, HandlerContext) ->
TransferParams = marshal(transfer_params, Params#{<<"id">> => ID}),
Request = {fistful_w2w_transfer, 'Create', {TransferParams, marshal(context, Context)}},
case service_call(Request, HandlerContext) of
@ -49,9 +79,9 @@ create_transfer(ID, Params, Context, HandlerContext) ->
{error, bad_w2w_transfer_amount}
end.
-spec get_transfer(id(), handler_context()) -> {ok, response_data(), id()} | {error, GetError} when
-spec get(id(), handler_context()) -> {ok, response_data(), id()} | {error, GetError} when
GetError :: {w2w_transfer, {unknown_w2w_transfer, id()}}.
get_transfer(ID, HandlerContext) ->
get(ID, HandlerContext) ->
EventRange = #'fistful_base_EventRange'{},
Request = {fistful_w2w_transfer, 'Get', {ID, EventRange}},
case service_call(Request, HandlerContext) of

View File

@ -27,12 +27,42 @@
create(Params, HandlerContext) ->
case wapi_backend_utils:gen_id(wallet, Params, HandlerContext) of
{ok, ID} ->
Context = wapi_backend_utils:make_ctx(Params),
create(ID, Params, Context, HandlerContext);
case is_id_unknown(ID, Params, HandlerContext) of
true ->
Context = wapi_backend_utils:make_ctx(Params),
create(ID, Params, Context, HandlerContext);
false ->
create(Params, HandlerContext)
end;
{error, {external_id_conflict, _}} = Error ->
Error
end.
is_id_unknown(
ID,
#{
<<"name">> := Name,
<<"identity">> := IdentityID,
<<"currency">> := CurrencyID
},
HandlerContext
) ->
case get(ID, HandlerContext) of
{error, {wallet, notfound}} ->
true;
{ok,
#{
<<"id">> := ID,
<<"name">> := Name,
<<"identity">> := IdentityID,
<<"currency">> := CurrencyID
},
_Owner} ->
true;
{ok, _NonMatchingIdentity, _Owner} ->
false
end.
create(WalletID, Params, Context, HandlerContext) ->
WalletParams = marshal(wallet_params, Params#{<<"id">> => WalletID}),
Request = {fistful_wallet, 'Create', {WalletParams, marshal(context, Context)}},

View File

@ -122,7 +122,7 @@ prepare(OperationID = 'ListIdentities', Req, Context, _Opts) ->
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetWithdrawalMethods', #{'identityID' := IdentityId}, Context, _Opts) ->
{ResultIdentity, ResultOwner} =
case wapi_identity_backend:get_identity(IdentityId, Context) of
case wapi_identity_backend:get(IdentityId, Context) of
{ok, Identity, Owner} -> {Identity, Owner};
{error, {identity, notfound}} -> {undefined, undefined}
end,
@ -145,7 +145,7 @@ prepare(OperationID = 'GetWithdrawalMethods', #{'identityID' := IdentityId}, Con
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetIdentity', #{'identityID' := IdentityId}, Context, _Opts) ->
{ResultIdentity, ResultOwner} =
case wapi_identity_backend:get_identity(IdentityId, Context) of
case wapi_identity_backend:get(IdentityId, Context) of
{ok, Identity, Owner} -> {Identity, Owner};
{error, {identity, notfound}} -> {undefined, undefined}
end,
@ -180,7 +180,7 @@ prepare(OperationID = 'CreateIdentity', #{'Identity' := Params}, Context, Opts)
{ok, Resolution}
end,
Process = fun() ->
case wapi_identity_backend:create_identity(Params#{<<"partyID">> => PartyID}, Context) of
case wapi_identity_backend:create(Params#{<<"partyID">> => PartyID}, Context) of
{ok, Identity = #{<<"id">> := IdentityId}} ->
wapi_handler_utils:reply_ok(201, Identity, get_location('GetIdentity', [IdentityId], Context, Opts));
{error, {inaccessible, _}} ->
@ -936,7 +936,7 @@ prepare(
{ok, Resolution}
end,
Process = fun() ->
case wapi_w2w_backend:create_transfer(add_party_id_to(PartyID, Params), Context) of
case wapi_w2w_transfer_backend:create(add_party_id_to(PartyID, Params), Context) of
{ok, W2WTransfer} ->
wapi_handler_utils:reply_ok(202, W2WTransfer);
{error, {wallet_from, notfound}} ->
@ -979,7 +979,7 @@ prepare(
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetW2WTransfer', #{'w2wTransferID' := W2WTransferId}, Context, _Opts) ->
{ResultW2WTransfer, ResultW2WTransferOwner} =
case wapi_w2w_backend:get_transfer(W2WTransferId, Context) of
case wapi_w2w_transfer_backend:get(W2WTransferId, Context) of
{ok, W2WTransfer, Owner} -> {W2WTransfer, Owner};
{error, {w2w_transfer, {unknown_w2w_transfer, _ID}}} -> {undefined, undefined}
end,
@ -1293,7 +1293,7 @@ build_auth_context([H | T], Acc, Context) ->
build_auth_context({identity, IdentityID}, Context) ->
{ResultIdentity, ResultIdentityOwner} =
case wapi_identity_backend:get_identity(IdentityID, Context) of
case wapi_identity_backend:get(IdentityID, Context) of
{ok, Identity, Owner} -> {Identity, Owner};
{error, {identity, notfound}} -> {undefined, undefined}
end,

View File

@ -69,6 +69,7 @@ create(Params0, HandlerContext) ->
end.
create(Params, Context, HandlerContext) ->
ct:log("Create params: ~p", [Params]),
Request = {fistful_withdrawal, 'Create', {Params, Context}},
case service_call(Request, HandlerContext) of
{ok, Withdrawal} ->
@ -258,10 +259,47 @@ check_withdrawal_params(Params0, HandlerContext) ->
do(fun() ->
Params1 = unwrap(try_decode_quote_token(Params0)),
Params2 = unwrap(maybe_check_quote_token(Params1, HandlerContext)),
ID = unwrap(wapi_backend_utils:gen_id(withdrawal, Params2, HandlerContext)),
Params2#{<<"id">> => ID}
unwrap(generate_id(Params2, HandlerContext))
end).
generate_id(Params, HandlerContext) ->
case wapi_backend_utils:gen_id(withdrawal, Params, HandlerContext) of
{ok, GenID} ->
case is_id_unknown(GenID, Params, HandlerContext) of
true ->
{ok, Params#{<<"id">> => GenID}};
false ->
generate_id(Params, HandlerContext)
end;
{error, E} ->
{error, E}
end.
is_id_unknown(
ID,
#{
<<"wallet">> := WalletID,
<<"destination">> := DestinationID,
<<"body">> := Body
},
HandlerContext
) ->
case get(ID, HandlerContext) of
{error, {withdrawal, notfound}} ->
true;
{ok,
#{
<<"id">> := ID,
<<"wallet">> := WalletID,
<<"destination">> := DestinationID,
<<"body">> := Body
},
_Owner} ->
true;
{ok, _NonMatchingIdentity, _Owner} ->
false
end.
try_decode_quote_token(Params = #{<<"quoteToken">> := QuoteToken}) ->
do(fun() ->
{_, _, Data} = unwrap(uac_authorizer_jwt:verify(QuoteToken, #{})),

View File

@ -135,8 +135,8 @@ start_app({dmt_client = AppName, SupPid}) ->
Urls = mock_services_(
[
{domain_config, fun
('Checkout', _) -> #domain_conf_Snapshot{version = 1, domain = #{}};
('PullRange', _) -> #{}
('Checkout', _) -> {ok, #domain_conf_Snapshot{version = 1, domain = #{}}};
('PullRange', _) -> {ok, #{}}
end}
],
SupPid
@ -254,6 +254,7 @@ mock_services_(Services, SupPid) when is_pid(SupPid) ->
{_IP, Port} = woody_server:get_addr(ServerID, WoodyOpts),
lists:foldl(
fun(Service, Acc) ->
ct:log("mocking: ~p", [Service]),
ServiceName = get_service_name(Service),
case ServiceName of
bouncer ->

View File

@ -38,6 +38,7 @@
-export([bitcoin_resource_test/1]).
-export([digital_wallet_resource_test/1]).
-export([digital_wallet_w_token_resource_test/1]).
-export([check_unknown_destination_id/1]).
-define(GENERIC_RESOURCE_TYPE, <<"BankTransferGeneric">>).
-define(GENERIC_RESOURCE_NAME, <<"GenericBankAccount">>).
@ -76,7 +77,8 @@ groups() ->
bank_card_resource_test,
bitcoin_resource_test,
digital_wallet_resource_test,
digital_wallet_w_token_resource_test
digital_wallet_w_token_resource_test,
check_unknown_destination_id
]}
].
@ -363,8 +365,11 @@ digital_wallet_w_token_resource_test(C) ->
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?IDENTITY(PartyID)}
end},
{fistful_destination, fun('Create', _) ->
{ok, ?DESTINATION(PartyID, ?RESOURCE_DIGITAL_WALLET)}
{fistful_destination, fun
('Create', _) ->
{ok, ?DESTINATION(PartyID, ?RESOURCE_DIGITAL_WALLET)};
('Get', _) ->
{throwing, #fistful_DestinationNotFound{}}
end}
],
C
@ -384,6 +389,45 @@ digital_wallet_w_token_resource_test(C) ->
error('missing token storage interaction')
end.
-spec check_unknown_destination_id(config()) -> _.
check_unknown_destination_id(C) ->
PartyID = ?config(party, C),
_ = wapi_ct_helper_bouncer:mock_assert_identity_op_ctx(<<"CreateDestination">>, ?STRING, PartyID, C),
CounterRef = counters:new(1, []),
ID0 = <<"Test0">>,
ID1 = <<"Test1">>,
Destination0 = ?DESTINATION(PartyID)#destination_DestinationState{id = ID1},
Destination1 = Destination0#destination_DestinationState{id = ID0, name = ?STRING2},
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) ->
CID = counters:get(CounterRef, 1),
BinaryCID = erlang:integer_to_binary(CID),
ok = counters:add(CounterRef, 1, 1),
{ok, ?GENERATE_ID_RESULT(<<"Test", BinaryCID/binary>>)}
end},
{fistful_identity, fun
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?IDENTITY(PartyID)}
end},
{fistful_destination, fun
('Create', _) ->
{ok, Destination0};
('Get', {WID, _}) when WID =:= ID0 ->
{ok, Destination1};
('Get', {WID, _}) when WID =:= ID1 ->
{throwing, #fistful_DestinationNotFound{}}
end}
],
C
),
?assertMatch(
{ok, #{<<"id">> := ID1}},
create_destination_call_api(C, Destination0)
).
%%
do_destination_lifecycle(ResourceType, C) ->
@ -621,7 +665,10 @@ create_destination_start_mocks(C, CreateDestinationResult) ->
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?IDENTITY(PartyID)}
end},
{fistful_destination, fun('Create', _) -> CreateDestinationResult end}
{fistful_destination, fun
('Create', _) -> CreateDestinationResult;
('Get', _) -> {throwing, #fistful_DestinationNotFound{}}
end}
],
C
).

View File

@ -30,7 +30,8 @@
get_identity/1,
get_identity_notfound/1,
get_identity_withdrawal_methods/1,
get_identity_withdrawal_methods_notfound/1
get_identity_withdrawal_methods_notfound/1,
check_unknown_identity_id/1
]).
-type test_case_name() :: atom().
@ -62,7 +63,8 @@ groups() ->
get_identity,
get_identity_notfound,
get_identity_withdrawal_methods,
get_identity_withdrawal_methods_notfound
get_identity_withdrawal_methods_notfound,
check_unknown_identity_id
]}
].
@ -112,7 +114,10 @@ create_identity(C) ->
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end},
{fistful_identity, fun('Create', _) -> {ok, ?IDENTITY(PartyID)} end}
{fistful_identity, fun
('Create', _) -> {ok, ?IDENTITY(PartyID)};
('Get', _) -> {throwing, #fistful_IdentityNotFound{}}
end}
],
C
),
@ -126,7 +131,10 @@ create_identity_with_party_id(C) ->
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end},
{fistful_identity, fun('Create', _) -> {ok, ?IDENTITY(PartyID)} end}
{fistful_identity, fun
('Create', _) -> {ok, ?IDENTITY(PartyID)};
('Get', _) -> {throwing, #fistful_IdentityNotFound{}}
end}
],
C
),
@ -139,7 +147,10 @@ create_identity_provider_notfound(C) ->
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end},
{fistful_identity, fun('Create', _) -> {throwing, #fistful_ProviderNotFound{}} end}
{fistful_identity, fun
('Create', _) -> {throwing, #fistful_ProviderNotFound{}};
('Get', _) -> {throwing, #fistful_IdentityNotFound{}}
end}
],
C
),
@ -155,7 +166,10 @@ create_identity_party_notfound(C) ->
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end},
{fistful_identity, fun('Create', _) -> {throwing, #fistful_PartyNotFound{}} end}
{fistful_identity, fun
('Create', _) -> {throwing, #fistful_PartyNotFound{}};
('Get', _) -> {throwing, #fistful_IdentityNotFound{}}
end}
],
C
),
@ -171,7 +185,10 @@ create_identity_party_inaccessible(C) ->
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end},
{fistful_identity, fun('Create', _) -> {throwing, #fistful_PartyInaccessible{}} end}
{fistful_identity, fun
('Create', _) -> {throwing, #fistful_PartyInaccessible{}};
('Get', _) -> {throwing, #fistful_IdentityNotFound{}}
end}
],
C
),
@ -187,7 +204,10 @@ create_identity_thrift_name(C) ->
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end},
{fistful_identity, fun('Create', _) -> {ok, ?IDENTITY(PartyID, ?DEFAULT_CONTEXT_NO_NAME(PartyID))} end}
{fistful_identity, fun
('Create', _) -> {ok, ?IDENTITY(PartyID, ?DEFAULT_CONTEXT_NO_NAME(PartyID))};
('Get', _) -> {throwing, #fistful_IdentityNotFound{}}
end}
],
C
),
@ -252,6 +272,38 @@ get_identity_withdrawal_methods_notfound(C) ->
get_identity_call_api(C)
).
-spec check_unknown_identity_id(config()) -> _.
check_unknown_identity_id(C) ->
PartyID = ?config(party, C),
_ = wapi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"CreateIdentity">>, PartyID, C),
CounterRef = counters:new(1, []),
ID0 = <<"Test0">>,
ID1 = <<"Test1">>,
Identity0 = ?IDENTITY(PartyID)#identity_IdentityState{id = ID1},
Identity1 = Identity0#identity_IdentityState{id = ID0, name = ?STRING2},
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) ->
CID = counters:get(CounterRef, 1),
BinaryCID = erlang:integer_to_binary(CID),
ok = counters:add(CounterRef, 1, 1),
{ok, ?GENERATE_ID_RESULT(<<"Test", BinaryCID/binary>>)}
end},
{fistful_identity, fun
('Create', _) ->
{ok, Identity0};
('Get', {WID, _}) when WID =:= ID0 ->
{ok, Identity1};
('Get', {WID, _}) when WID =:= ID1 ->
{throwing, #fistful_IdentityNotFound{}}
end}
],
C
),
{ok, #{
<<"id">> := ID1
}} = create_identity_call_api(C).
%%
create_identity_call_api(C) ->

View File

@ -33,7 +33,8 @@
create_fail_inconsistent_w2w_transfer_currency_test/1,
create_fail_wallet_inaccessible_test/1,
get_ok_test/1,
get_fail_w2w_notfound_test/1
get_fail_w2w_notfound_test/1,
check_unknown_w2w_id/1
]).
-define(EMPTY_RESP(Code), {error, {Code, #{}}}).
@ -66,7 +67,8 @@ groups() ->
create_fail_inconsistent_w2w_transfer_currency_test,
create_fail_wallet_inaccessible_test,
get_ok_test,
get_fail_w2w_notfound_test
get_fail_w2w_notfound_test,
check_unknown_w2w_id
]}
].
@ -218,6 +220,42 @@ get_fail_w2w_notfound_test(C) ->
get_w2_w_transfer_call_api(C)
).
-spec check_unknown_w2w_id(config()) -> _.
check_unknown_w2w_id(C) ->
PartyID = ?config(party, C),
_ = wapi_ct_helper_bouncer:mock_assert_wallet_op_ctx(<<"CreateW2WTransfer">>, ?STRING, PartyID, C),
CounterRef = counters:new(1, []),
ID0 = <<"Test0">>,
ID1 = <<"Test1">>,
W2WTransfer0 = ?W2W_TRANSFER(PartyID)#w2w_transfer_W2WTransferState{id = ID1},
W2WTransfer1 = W2WTransfer0#w2w_transfer_W2WTransferState{id = ID0, wallet_from_id = ?STRING2},
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) ->
CID = counters:get(CounterRef, 1),
BinaryCID = erlang:integer_to_binary(CID),
ok = counters:add(CounterRef, 1, 1),
{ok, ?GENERATE_ID_RESULT(<<"Test", BinaryCID/binary>>)}
end},
{fistful_wallet, fun
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?WALLET(PartyID)}
end},
{fistful_w2w_transfer, fun
('Create', _) ->
{ok, W2WTransfer0};
('Get', {WID, _}) when WID =:= ID0 ->
{ok, W2WTransfer1};
('Get', {WID, _}) when WID =:= ID1 ->
{throwing, #fistful_W2WNotFound{}}
end}
],
C
),
{ok, #{
<<"id">> := ID1
}} = create_w2_w_transfer_call_api(C).
%%
-spec call_api(function(), map(), wapi_client_lib:context()) -> {ok, term()} | {error, term()}.
@ -263,7 +301,10 @@ create_w2_w_transfer_start_mocks(C, CreateResultFun) ->
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?WALLET(PartyID)}
end},
{fistful_w2w_transfer, fun('Create', _) -> CreateResultFun() end}
{fistful_w2w_transfer, fun
('Create', _) -> CreateResultFun();
('Get', _) -> {throwing, #fistful_W2WNotFound{}}
end}
],
C
).

View File

@ -1,4 +1,5 @@
-define(STRING, <<"TEST">>).
-define(STRING2, <<"TEST2">>).
-define(RUB, <<"RUB">>).
-define(USD, <<"USD">>).
-define(BANKID_RU, <<"PUTIN">>).
@ -60,9 +61,11 @@
undefined
}).
-define(GENERATE_ID_RESULT, {
-define(GENERATE_ID_RESULT, ?GENERATE_ID_RESULT(?STRING)).
-define(GENERATE_ID_RESULT(ID), {
'bender_GenerationResult',
?STRING,
ID,
undefined,
undefined
}).

View File

@ -32,7 +32,8 @@
get_by_external_id_ok/1,
get_account_ok/1,
get_account_fail_get_context_wallet_notfound/1,
get_account_fail_get_accountbalance_wallet_notfound/1
get_account_fail_get_accountbalance_wallet_notfound/1,
check_unknown_wallet_id/1
]).
-define(EMPTY_RESP(Code), {error, {Code, #{}}}).
@ -66,7 +67,8 @@ groups() ->
get_by_external_id_ok,
get_account_ok,
get_account_fail_get_context_wallet_notfound,
get_account_fail_get_accountbalance_wallet_notfound
get_account_fail_get_accountbalance_wallet_notfound,
check_unknown_wallet_id
]}
].
@ -242,6 +244,42 @@ get_account_fail_get_accountbalance_wallet_notfound(C) ->
get_account_call_api(C)
).
-spec check_unknown_wallet_id(config()) -> _.
check_unknown_wallet_id(C) ->
PartyID = ?config(party, C),
_ = wapi_ct_helper_bouncer:mock_assert_identity_op_ctx(<<"CreateWallet">>, ?STRING, PartyID, C),
CounterRef = counters:new(1, []),
ID0 = <<"Test0">>,
ID1 = <<"Test1">>,
Wallet0 = ?WALLET(PartyID)#wallet_WalletState{id = ID1},
Wallet1 = Wallet0#wallet_WalletState{id = ID0, name = ?STRING2},
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) ->
CID = counters:get(CounterRef, 1),
BinaryCID = erlang:integer_to_binary(CID),
ok = counters:add(CounterRef, 1, 1),
{ok, ?GENERATE_ID_RESULT(<<"Test", BinaryCID/binary>>)}
end},
{fistful_identity, fun
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?IDENTITY(PartyID)}
end},
{fistful_wallet, fun
('Create', _) ->
{ok, Wallet0};
('Get', {WID, _}) when WID =:= ID0 ->
{ok, Wallet1};
('Get', {WID, _}) when WID =:= ID1 ->
{throwing, #fistful_WalletNotFound{}}
end}
],
C
),
{ok, #{
<<"id">> := ID1
}} = create_wallet_call_api(C).
%%
-spec call_api(function(), map(), wapi_client_lib:context()) -> {ok, term()} | {error, term()}.
@ -298,7 +336,10 @@ create_wallet_start_mocks(C, CreateResultFun) ->
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?IDENTITY(PartyID)}
end},
{fistful_wallet, fun('Create', _) -> CreateResultFun() end}
{fistful_wallet, fun
('Create', _) -> CreateResultFun();
('Get', _) -> {throwing, #fistful_WalletNotFound{}}
end}
],
C
).

View File

@ -56,7 +56,8 @@
get_quote_fail_identity_provider_mismatch/1,
get_event_ok/1,
get_events_ok/1,
get_events_fail_withdrawal_notfound/1
get_events_fail_withdrawal_notfound/1,
check_unknown_withdrawal_id/1
]).
-type test_case_name() :: atom().
@ -108,7 +109,8 @@ groups() ->
get_quote_fail_identity_provider_mismatch,
get_event_ok,
get_events_ok,
get_events_fail_withdrawal_notfound
get_events_fail_withdrawal_notfound,
check_unknown_withdrawal_id
]}
].
@ -126,7 +128,7 @@ end_per_suite(C) ->
ok.
-spec init_per_group(group_name(), config()) -> config().
init_per_group(Group, Config) when Group =:= base ->
init_per_group(Group, Config) when Group =:= base; Group =:= base2 ->
Party = genlib:bsuuid(),
Config1 = [{party, Party} | Config],
GroupSup = wapi_ct_helper:start_mocked_service_sup(?MODULE),
@ -577,6 +579,57 @@ get_events_fail_withdrawal_notfound(C) ->
)
).
-spec check_unknown_withdrawal_id(config()) -> _.
check_unknown_withdrawal_id(C) ->
PartyID = ?config(party, C),
_ = wapi_ct_helper_bouncer:mock_assert_generic_op_ctx(
[
{destination, ?STRING, PartyID},
{wallet, ?STRING, PartyID}
],
?CTX_WAPI(#ctx_v1_WalletAPIOperation{
id = <<"CreateWithdrawal">>,
destination = ?STRING,
wallet = ?STRING
}),
C
),
CounterRef = counters:new(1, []),
ID0 = <<"Test0">>,
ID1 = <<"Test1">>,
Withdrawal0 = ?WITHDRAWAL(PartyID)#wthd_WithdrawalState{id = ID1},
Withdrawal1 = Withdrawal0#wthd_WithdrawalState{id = ID0, wallet_id = ?STRING2},
_ = wapi_ct_helper:mock_services(
[
{bender, fun('GenerateID', _) ->
CID = counters:get(CounterRef, 1),
BinaryCID = erlang:integer_to_binary(CID),
ok = counters:add(CounterRef, 1, 1),
{ok, ?GENERATE_ID_RESULT(<<"Test", BinaryCID/binary>>)}
end},
{fistful_wallet, fun
('Get', _) -> {ok, ?WALLET(PartyID)};
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)}
end},
{fistful_destination, fun
('Get', _) -> {ok, ?DESTINATION(PartyID)};
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)}
end},
{fistful_withdrawal, fun
('Create', _) ->
{ok, Withdrawal0};
('Get', {WID, _}) when WID =:= ID0 ->
{ok, Withdrawal1};
('Get', {WID, _}) when WID =:= ID1 ->
{throwing, #fistful_WithdrawalNotFound{}}
end}
],
C
),
{ok, #{
<<"id">> := ID1
}} = create_withdrawal_call_api(C).
%%
-spec call_api(function(), map(), wapi_client_lib:context()) -> {ok, term()} | {error, term()}.
@ -644,7 +697,10 @@ create_withdrawal_start_mocks(C, CreateWithdrawalResultFun) ->
('Get', _) -> {ok, ?DESTINATION(PartyID)};
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)}
end},
{fistful_withdrawal, fun('Create', _) -> CreateWithdrawalResultFun() end}
{fistful_withdrawal, fun
('Create', _) -> CreateWithdrawalResultFun();
('Get', _) -> {throwing, #fistful_WithdrawalNotFound{}}
end}
],
C
).