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 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}; {ok, ID};
false ->
generate_id(Params, ResourceThrift, HandlerContext)
end;
{error, {external_id_conflict, ID}} -> {error, {external_id_conflict, ID}} ->
% Delete after deploy % Delete after deploy
ExternalID = maps:get(<<"externalID">>, Params, undefined), ExternalID = maps:get(<<"externalID">>, Params, undefined),
@ -58,12 +63,42 @@ generate_id(Params, ResourceThrift, HandlerContext) ->
generate_id_legacy(Params, HandlerContext) -> generate_id_legacy(Params, HandlerContext) ->
case wapi_backend_utils:gen_id(destination, Params, HandlerContext) of 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}; {ok, ID};
false ->
generate_id_legacy(Params, HandlerContext)
end;
{error, {external_id_conflict, ID}} -> {error, {external_id_conflict, ID}} ->
ExternalID = maps:get(<<"externalID">>, Params, undefined), ExternalID = maps:get(<<"externalID">>, Params, undefined),
{error, {external_id_conflict, {ID, ExternalID}}} {error, {external_id_conflict, {ID, ExternalID}}}
end. 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) -> create_request(ID, Params, ResourceThrift, HandlerContext) ->
% mixing the attributes needed for marshaling % mixing the attributes needed for marshaling
MarshaledParams = marshal(destination_params, Params#{ MarshaledParams = marshal(destination_params, Params#{

View File

@ -9,8 +9,8 @@
-export_type([identity_state/0]). -export_type([identity_state/0]).
-export([create_identity/2]). -export([create/2]).
-export([get_identity/2]). -export([get/2]).
-export([get_thrift_identity/2]). -export([get_thrift_identity/2]).
-export([get_identity_withdrawal_methods/2]). -export([get_identity_withdrawal_methods/2]).
@ -21,10 +21,10 @@
%% Pipeline %% Pipeline
-spec get_identity(id(), handler_context()) -> -spec get(id(), handler_context()) ->
{ok, response_data(), id()} {ok, response_data(), id()}
| {error, {identity, notfound}}. | {error, {identity, notfound}}.
get_identity(IdentityID, HandlerContext) -> get(IdentityID, HandlerContext) ->
case get_thrift_identity(IdentityID, HandlerContext) of case get_thrift_identity(IdentityID, HandlerContext) of
{ok, IdentityThrift} -> {ok, IdentityThrift} ->
{ok, Owner} = wapi_backend_utils:get_entity_owner(identity, IdentityThrift), {ok, Owner} = wapi_backend_utils:get_entity_owner(identity, IdentityThrift),
@ -33,7 +33,7 @@ get_identity(IdentityID, HandlerContext) ->
Error Error
end. end.
-spec create_identity(params(), handler_context()) -> -spec create(params(), handler_context()) ->
result( result(
map(), map(),
{provider, notfound} {provider, notfound}
@ -41,14 +41,42 @@ get_identity(IdentityID, HandlerContext) ->
| inaccessible | inaccessible
| _Unexpected | _Unexpected
). ).
create_identity(Params, HandlerContext) -> create(Params, HandlerContext) ->
case create_id(identity, Params, HandlerContext) of case wapi_backend_utils:gen_id(identity, Params, HandlerContext) of
{ok, ID} -> {ok, ID} ->
case is_id_unknown(ID, Params, HandlerContext) of
true ->
create_identity(ID, Params, HandlerContext); create_identity(ID, Params, HandlerContext);
false ->
create(Params, HandlerContext)
end;
{error, {external_id_conflict, _}} = Error -> {error, {external_id_conflict, _}} = Error ->
Error Error
end. 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) -> create_identity(ID, Params, HandlerContext) ->
IdentityParams = marshal(identity_params, Params#{<<"id">> => ID}), IdentityParams = marshal(identity_params, Params#{<<"id">> => ID}),
Request = {fistful_identity, 'Create', {IdentityParams, marshal(context, create_context(Params))}}, Request = {fistful_identity, 'Create', {IdentityParams, marshal(context, create_context(Params))}},
@ -94,13 +122,6 @@ get_identity_withdrawal_methods(IdentityID, HandlerContext) ->
%% Internal %% Internal
%% %%
create_id(Type, Params, HandlerContext) ->
wapi_backend_utils:gen_id(
Type,
Params,
HandlerContext
).
create_context(Params) -> create_context(Params) ->
KV = {<<"name">>, maps:get(<<"name">>, Params, undefined)}, KV = {<<"name">>, maps:get(<<"name">>, Params, undefined)},
wapi_backend_utils:add_to_ctx(KV, wapi_backend_utils:make_ctx(Params)). 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 request_data() :: wapi_wallet_handler:request_data().
-type handler_context() :: wapi_handler_utils:handler_context(). -type handler_context() :: wapi_handler_utils:handler_context().
@ -7,31 +7,61 @@
-type id() :: binary(). -type id() :: binary().
-type external_id() :: id(). -type external_id() :: id().
-export([create_transfer/2]). -export([create/2]).
-export([get_transfer/2]). -export([get/2]).
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl"). -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_fistful_thrift.hrl").
-include_lib("fistful_proto/include/fistful_w2w_transfer_thrift.hrl"). -include_lib("fistful_proto/include/fistful_w2w_transfer_thrift.hrl").
-include_lib("fistful_proto/include/fistful_w2w_status_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 :: CreateError ::
{external_id_conflict, external_id()} {external_id_conflict, external_id()}
| {wallet_from | wallet_to, notfound | inaccessible} | {wallet_from | wallet_to, notfound | inaccessible}
| bad_w2w_transfer_amount | bad_w2w_transfer_amount
| not_allowed_currency | not_allowed_currency
| inconsistent_currency. | inconsistent_currency.
create_transfer(Params, HandlerContext) -> create(Params, HandlerContext) ->
case wapi_backend_utils:gen_id(w2w_transfer, Params, HandlerContext) of case wapi_backend_utils:gen_id(w2w_transfer, Params, HandlerContext) of
{ok, ID} -> {ok, ID} ->
case is_id_unknown(ID, Params, HandlerContext) of
true ->
Context = wapi_backend_utils:make_ctx(Params), Context = wapi_backend_utils:make_ctx(Params),
create_transfer(ID, Params, Context, HandlerContext); create(ID, Params, Context, HandlerContext);
false ->
create(Params, HandlerContext)
end;
{error, {external_id_conflict, _}} = Error -> {error, {external_id_conflict, _}} = Error ->
Error Error
end. 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}), TransferParams = marshal(transfer_params, Params#{<<"id">> => ID}),
Request = {fistful_w2w_transfer, 'Create', {TransferParams, marshal(context, Context)}}, Request = {fistful_w2w_transfer, 'Create', {TransferParams, marshal(context, Context)}},
case service_call(Request, HandlerContext) of case service_call(Request, HandlerContext) of
@ -49,9 +79,9 @@ create_transfer(ID, Params, Context, HandlerContext) ->
{error, bad_w2w_transfer_amount} {error, bad_w2w_transfer_amount}
end. 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()}}. GetError :: {w2w_transfer, {unknown_w2w_transfer, id()}}.
get_transfer(ID, HandlerContext) -> get(ID, HandlerContext) ->
EventRange = #'fistful_base_EventRange'{}, EventRange = #'fistful_base_EventRange'{},
Request = {fistful_w2w_transfer, 'Get', {ID, EventRange}}, Request = {fistful_w2w_transfer, 'Get', {ID, EventRange}},
case service_call(Request, HandlerContext) of case service_call(Request, HandlerContext) of

View File

@ -27,12 +27,42 @@
create(Params, HandlerContext) -> create(Params, HandlerContext) ->
case wapi_backend_utils:gen_id(wallet, Params, HandlerContext) of case wapi_backend_utils:gen_id(wallet, Params, HandlerContext) of
{ok, ID} -> {ok, ID} ->
case is_id_unknown(ID, Params, HandlerContext) of
true ->
Context = wapi_backend_utils:make_ctx(Params), Context = wapi_backend_utils:make_ctx(Params),
create(ID, Params, Context, HandlerContext); create(ID, Params, Context, HandlerContext);
false ->
create(Params, HandlerContext)
end;
{error, {external_id_conflict, _}} = Error -> {error, {external_id_conflict, _}} = Error ->
Error Error
end. 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) -> create(WalletID, Params, Context, HandlerContext) ->
WalletParams = marshal(wallet_params, Params#{<<"id">> => WalletID}), WalletParams = marshal(wallet_params, Params#{<<"id">> => WalletID}),
Request = {fistful_wallet, 'Create', {WalletParams, marshal(context, Context)}}, 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}}; {ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetWithdrawalMethods', #{'identityID' := IdentityId}, Context, _Opts) -> prepare(OperationID = 'GetWithdrawalMethods', #{'identityID' := IdentityId}, Context, _Opts) ->
{ResultIdentity, ResultOwner} = {ResultIdentity, ResultOwner} =
case wapi_identity_backend:get_identity(IdentityId, Context) of case wapi_identity_backend:get(IdentityId, Context) of
{ok, Identity, Owner} -> {Identity, Owner}; {ok, Identity, Owner} -> {Identity, Owner};
{error, {identity, notfound}} -> {undefined, undefined} {error, {identity, notfound}} -> {undefined, undefined}
end, end,
@ -145,7 +145,7 @@ prepare(OperationID = 'GetWithdrawalMethods', #{'identityID' := IdentityId}, Con
{ok, #{authorize => Authorize, process => Process}}; {ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetIdentity', #{'identityID' := IdentityId}, Context, _Opts) -> prepare(OperationID = 'GetIdentity', #{'identityID' := IdentityId}, Context, _Opts) ->
{ResultIdentity, ResultOwner} = {ResultIdentity, ResultOwner} =
case wapi_identity_backend:get_identity(IdentityId, Context) of case wapi_identity_backend:get(IdentityId, Context) of
{ok, Identity, Owner} -> {Identity, Owner}; {ok, Identity, Owner} -> {Identity, Owner};
{error, {identity, notfound}} -> {undefined, undefined} {error, {identity, notfound}} -> {undefined, undefined}
end, end,
@ -180,7 +180,7 @@ prepare(OperationID = 'CreateIdentity', #{'Identity' := Params}, Context, Opts)
{ok, Resolution} {ok, Resolution}
end, end,
Process = fun() -> 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}} -> {ok, Identity = #{<<"id">> := IdentityId}} ->
wapi_handler_utils:reply_ok(201, Identity, get_location('GetIdentity', [IdentityId], Context, Opts)); wapi_handler_utils:reply_ok(201, Identity, get_location('GetIdentity', [IdentityId], Context, Opts));
{error, {inaccessible, _}} -> {error, {inaccessible, _}} ->
@ -936,7 +936,7 @@ prepare(
{ok, Resolution} {ok, Resolution}
end, end,
Process = fun() -> 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} -> {ok, W2WTransfer} ->
wapi_handler_utils:reply_ok(202, W2WTransfer); wapi_handler_utils:reply_ok(202, W2WTransfer);
{error, {wallet_from, notfound}} -> {error, {wallet_from, notfound}} ->
@ -979,7 +979,7 @@ prepare(
{ok, #{authorize => Authorize, process => Process}}; {ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetW2WTransfer', #{'w2wTransferID' := W2WTransferId}, Context, _Opts) -> prepare(OperationID = 'GetW2WTransfer', #{'w2wTransferID' := W2WTransferId}, Context, _Opts) ->
{ResultW2WTransfer, ResultW2WTransferOwner} = {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}; {ok, W2WTransfer, Owner} -> {W2WTransfer, Owner};
{error, {w2w_transfer, {unknown_w2w_transfer, _ID}}} -> {undefined, undefined} {error, {w2w_transfer, {unknown_w2w_transfer, _ID}}} -> {undefined, undefined}
end, end,
@ -1293,7 +1293,7 @@ build_auth_context([H | T], Acc, Context) ->
build_auth_context({identity, IdentityID}, Context) -> build_auth_context({identity, IdentityID}, Context) ->
{ResultIdentity, ResultIdentityOwner} = {ResultIdentity, ResultIdentityOwner} =
case wapi_identity_backend:get_identity(IdentityID, Context) of case wapi_identity_backend:get(IdentityID, Context) of
{ok, Identity, Owner} -> {Identity, Owner}; {ok, Identity, Owner} -> {Identity, Owner};
{error, {identity, notfound}} -> {undefined, undefined} {error, {identity, notfound}} -> {undefined, undefined}
end, end,

View File

@ -69,6 +69,7 @@ create(Params0, HandlerContext) ->
end. end.
create(Params, Context, HandlerContext) -> create(Params, Context, HandlerContext) ->
ct:log("Create params: ~p", [Params]),
Request = {fistful_withdrawal, 'Create', {Params, Context}}, Request = {fistful_withdrawal, 'Create', {Params, Context}},
case service_call(Request, HandlerContext) of case service_call(Request, HandlerContext) of
{ok, Withdrawal} -> {ok, Withdrawal} ->
@ -258,10 +259,47 @@ check_withdrawal_params(Params0, HandlerContext) ->
do(fun() -> do(fun() ->
Params1 = unwrap(try_decode_quote_token(Params0)), Params1 = unwrap(try_decode_quote_token(Params0)),
Params2 = unwrap(maybe_check_quote_token(Params1, HandlerContext)), Params2 = unwrap(maybe_check_quote_token(Params1, HandlerContext)),
ID = unwrap(wapi_backend_utils:gen_id(withdrawal, Params2, HandlerContext)), unwrap(generate_id(Params2, HandlerContext))
Params2#{<<"id">> => ID}
end). 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}) -> try_decode_quote_token(Params = #{<<"quoteToken">> := QuoteToken}) ->
do(fun() -> do(fun() ->
{_, _, Data} = unwrap(uac_authorizer_jwt:verify(QuoteToken, #{})), {_, _, Data} = unwrap(uac_authorizer_jwt:verify(QuoteToken, #{})),

View File

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

View File

@ -38,6 +38,7 @@
-export([bitcoin_resource_test/1]). -export([bitcoin_resource_test/1]).
-export([digital_wallet_resource_test/1]). -export([digital_wallet_resource_test/1]).
-export([digital_wallet_w_token_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_TYPE, <<"BankTransferGeneric">>).
-define(GENERIC_RESOURCE_NAME, <<"GenericBankAccount">>). -define(GENERIC_RESOURCE_NAME, <<"GenericBankAccount">>).
@ -76,7 +77,8 @@ groups() ->
bank_card_resource_test, bank_card_resource_test,
bitcoin_resource_test, bitcoin_resource_test,
digital_wallet_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)}; ('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?IDENTITY(PartyID)} ('Get', _) -> {ok, ?IDENTITY(PartyID)}
end}, end},
{fistful_destination, fun('Create', _) -> {fistful_destination, fun
{ok, ?DESTINATION(PartyID, ?RESOURCE_DIGITAL_WALLET)} ('Create', _) ->
{ok, ?DESTINATION(PartyID, ?RESOURCE_DIGITAL_WALLET)};
('Get', _) ->
{throwing, #fistful_DestinationNotFound{}}
end} end}
], ],
C C
@ -384,6 +389,45 @@ digital_wallet_w_token_resource_test(C) ->
error('missing token storage interaction') error('missing token storage interaction')
end. 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) -> do_destination_lifecycle(ResourceType, C) ->
@ -621,7 +665,10 @@ create_destination_start_mocks(C, CreateDestinationResult) ->
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)}; ('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?IDENTITY(PartyID)} ('Get', _) -> {ok, ?IDENTITY(PartyID)}
end}, end},
{fistful_destination, fun('Create', _) -> CreateDestinationResult end} {fistful_destination, fun
('Create', _) -> CreateDestinationResult;
('Get', _) -> {throwing, #fistful_DestinationNotFound{}}
end}
], ],
C C
). ).

View File

@ -30,7 +30,8 @@
get_identity/1, get_identity/1,
get_identity_notfound/1, get_identity_notfound/1,
get_identity_withdrawal_methods/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(). -type test_case_name() :: atom().
@ -62,7 +63,8 @@ groups() ->
get_identity, get_identity,
get_identity_notfound, get_identity_notfound,
get_identity_withdrawal_methods, 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( _ = wapi_ct_helper:mock_services(
[ [
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end}, {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 C
), ),
@ -126,7 +131,10 @@ create_identity_with_party_id(C) ->
_ = wapi_ct_helper:mock_services( _ = wapi_ct_helper:mock_services(
[ [
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end}, {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 C
), ),
@ -139,7 +147,10 @@ create_identity_provider_notfound(C) ->
_ = wapi_ct_helper:mock_services( _ = wapi_ct_helper:mock_services(
[ [
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end}, {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 C
), ),
@ -155,7 +166,10 @@ create_identity_party_notfound(C) ->
_ = wapi_ct_helper:mock_services( _ = wapi_ct_helper:mock_services(
[ [
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end}, {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 C
), ),
@ -171,7 +185,10 @@ create_identity_party_inaccessible(C) ->
_ = wapi_ct_helper:mock_services( _ = wapi_ct_helper:mock_services(
[ [
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end}, {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 C
), ),
@ -187,7 +204,10 @@ create_identity_thrift_name(C) ->
_ = wapi_ct_helper:mock_services( _ = wapi_ct_helper:mock_services(
[ [
{bender, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end}, {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 C
), ),
@ -252,6 +272,38 @@ get_identity_withdrawal_methods_notfound(C) ->
get_identity_call_api(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) -> create_identity_call_api(C) ->

View File

@ -33,7 +33,8 @@
create_fail_inconsistent_w2w_transfer_currency_test/1, create_fail_inconsistent_w2w_transfer_currency_test/1,
create_fail_wallet_inaccessible_test/1, create_fail_wallet_inaccessible_test/1,
get_ok_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, #{}}}). -define(EMPTY_RESP(Code), {error, {Code, #{}}}).
@ -66,7 +67,8 @@ groups() ->
create_fail_inconsistent_w2w_transfer_currency_test, create_fail_inconsistent_w2w_transfer_currency_test,
create_fail_wallet_inaccessible_test, create_fail_wallet_inaccessible_test,
get_ok_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) 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()}. -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)}; ('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?WALLET(PartyID)} ('Get', _) -> {ok, ?WALLET(PartyID)}
end}, end},
{fistful_w2w_transfer, fun('Create', _) -> CreateResultFun() end} {fistful_w2w_transfer, fun
('Create', _) -> CreateResultFun();
('Get', _) -> {throwing, #fistful_W2WNotFound{}}
end}
], ],
C C
). ).

View File

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

View File

@ -32,7 +32,8 @@
get_by_external_id_ok/1, get_by_external_id_ok/1,
get_account_ok/1, get_account_ok/1,
get_account_fail_get_context_wallet_notfound/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, #{}}}). -define(EMPTY_RESP(Code), {error, {Code, #{}}}).
@ -66,7 +67,8 @@ groups() ->
get_by_external_id_ok, get_by_external_id_ok,
get_account_ok, get_account_ok,
get_account_fail_get_context_wallet_notfound, 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) 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()}. -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)}; ('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)};
('Get', _) -> {ok, ?IDENTITY(PartyID)} ('Get', _) -> {ok, ?IDENTITY(PartyID)}
end}, end},
{fistful_wallet, fun('Create', _) -> CreateResultFun() end} {fistful_wallet, fun
('Create', _) -> CreateResultFun();
('Get', _) -> {throwing, #fistful_WalletNotFound{}}
end}
], ],
C C
). ).

View File

@ -56,7 +56,8 @@
get_quote_fail_identity_provider_mismatch/1, get_quote_fail_identity_provider_mismatch/1,
get_event_ok/1, get_event_ok/1,
get_events_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(). -type test_case_name() :: atom().
@ -108,7 +109,8 @@ groups() ->
get_quote_fail_identity_provider_mismatch, get_quote_fail_identity_provider_mismatch,
get_event_ok, get_event_ok,
get_events_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. ok.
-spec init_per_group(group_name(), config()) -> config(). -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(), Party = genlib:bsuuid(),
Config1 = [{party, Party} | Config], Config1 = [{party, Party} | Config],
GroupSup = wapi_ct_helper:start_mocked_service_sup(?MODULE), 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()}. -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)}; ('Get', _) -> {ok, ?DESTINATION(PartyID)};
('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)} ('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)}
end}, end},
{fistful_withdrawal, fun('Create', _) -> CreateWithdrawalResultFun() end} {fistful_withdrawal, fun
('Create', _) -> CreateWithdrawalResultFun();
('Get', _) -> {throwing, #fistful_WithdrawalNotFound{}}
end}
], ],
C C
). ).