добавил тест для большого deposit;
код для проверки лимитов кошелька убрал в ff_party
	изменено:      apps/ff_cth/src/ct_payment_system.erl
	новый файл:    apps/ff_server/rebar.config
	изменено:      apps/ff_server/src/ff_server.erl
	изменено:      apps/ff_transfer/rebar.config
	изменено:      apps/ff_transfer/src/ff_deposit.erl
	изменено:      apps/ff_transfer/src/ff_withdrawal.erl
	изменено:      apps/ff_transfer/test/ff_transfer_SUITE.erl
	изменено:      apps/fistful/rebar.config
	изменено:      apps/fistful/src/ff_party.erl
This commit is contained in:
0x42 2018-12-17 16:18:47 +03:00
parent 4bb7bec5e9
commit 21bb7e71e6
9 changed files with 120 additions and 43 deletions

View File

@ -64,7 +64,16 @@ start_processing_apps(Options) ->
client => ff_woody_client:new(<<"http://machinegun:8022/v1/automaton">>) client => ff_woody_client:new(<<"http://machinegun:8022/v1/automaton">>)
}}, }},
{StartedApps, _StartupCtx} = ct_helper:start_apps([ {StartedApps, _StartupCtx} = ct_helper:start_apps([
lager, {lager, [
{error_logger_hwm, 600},
% {log_root, "/var/log/fistful-server"},
{crash_log, "crash.log"},
{handlers, [
{lager_console_backend, [
{level, warning}
]}
]}
]},
scoper, scoper,
woody, woody,
dmt_client, dmt_client,

View File

@ -0,0 +1,3 @@
{erl_opts, [
{parse_transform, lager_transform}
]}.

View File

@ -34,7 +34,7 @@ start() ->
application:ensure_all_started(?MODULE). application:ensure_all_started(?MODULE).
%% Application %% Application
-spec start(normal, any()) -> -spec start(normal, any()) ->
{ok, pid()} | {error, any()}. {ok, pid()} | {error, any()}.

View File

@ -0,0 +1,3 @@
{erl_opts, [
{parse_transform, lager_transform}
]}.

View File

@ -154,7 +154,7 @@ events(ID, Range) ->
process_transfer(Deposit) -> process_transfer(Deposit) ->
Activity = deduce_activity(Deposit), Activity = deduce_activity(Deposit),
do_process_transfer(Activity, Deposit). do_process_transfer(Activity, Deposit).
-spec process_failure(any(), deposit()) -> -spec process_failure(any(), deposit()) ->
{ok, process_result()} | {ok, process_result()} |
@ -220,8 +220,16 @@ create_p_transfer(Deposit) ->
-spec finish_transfer(deposit()) -> -spec finish_transfer(deposit()) ->
{ok, {ff_transfer_machine:action(), [ff_transfer_machine:event(ff_transfer:event())]}} | {ok, {ff_transfer_machine:action(), [ff_transfer_machine:event(ff_transfer:event())]}} |
{error, _Reason}. {error, _Reason}.
finish_transfer(_Deposit) -> finish_transfer(Deposit) ->
{ok, {continue, [{status_changed, succeeded}]}}. Body = body(Deposit),
#{
wallet_id := WalletID,
wallet_account := WalletAccount
} = params(Deposit),
do(fun () ->
valid = ff_party:validate_wallet_limits(WalletID, Body, WalletAccount),
{continue, [{status_changed, succeeded}]}
end).
-spec construct_p_transfer_id(id()) -> id(). -spec construct_p_transfer_id(id()) -> id().
construct_p_transfer_id(ID) -> construct_p_transfer_id(ID) ->

View File

@ -62,16 +62,13 @@
-type id() :: ff_transfer_machine:id(). -type id() :: ff_transfer_machine:id().
-type body() :: ff_transfer:body(). -type body() :: ff_transfer:body().
-type wallet() :: ff_wallet:wallet().
-type account() :: ff_account:account(). -type account() :: ff_account:account().
-type provider() :: ff_withdrawal_provider:provider(). -type provider() :: ff_withdrawal_provider:provider().
-type wallet_id() :: ff_wallet:id(). -type wallet_id() :: ff_wallet:id().
-type timestamp() :: ff_time:timestamp_ms().
-type cash_flow_plan() :: ff_cash_flow:cash_flow_plan(). -type cash_flow_plan() :: ff_cash_flow:cash_flow_plan().
-type destination_id() :: ff_destination:id(). -type destination_id() :: ff_destination:id().
-type process_result() :: {ff_transfer_machine:action(), [event()]}. -type process_result() :: {ff_transfer_machine:action(), [event()]}.
-type final_cash_flow() :: ff_cash_flow:final_cash_flow(). -type final_cash_flow() :: ff_cash_flow:final_cash_flow().
-type withdrawal_terms() :: dmsl_domain_thrift:'WithdrawalServiceTerms'().
%% Accessors %% Accessors
@ -121,7 +118,7 @@ create(ID, #{wallet_id := WalletID, destination_id := DestinationID, body := Bod
unwrap(destination, ff_destination:get_machine(DestinationID)) unwrap(destination, ff_destination:get_machine(DestinationID))
), ),
ok = unwrap(destination, valid(authorized, ff_destination:status(Destination))), ok = unwrap(destination, valid(authorized, ff_destination:status(Destination))),
Terms = unwrap(contract, get_contract_terms(Wallet, Body, ff_time:now())), Terms = unwrap(contract, ff_party:get_contract_terms(Wallet, Body, ff_time:now())),
valid = unwrap(terms, ff_party:validate_withdrawal_creation(Terms, Body, WalletAccount)), valid = unwrap(terms, ff_party:validate_withdrawal_creation(Terms, Body, WalletAccount)),
CashFlowPlan = unwrap(cash_flow_plan, ff_party:get_withdrawal_cash_flow_plan(Terms)), CashFlowPlan = unwrap(cash_flow_plan, ff_party:get_withdrawal_cash_flow_plan(Terms)),
@ -271,7 +268,7 @@ create_session(Withdrawal) ->
destination_account := DestinationAccount destination_account := DestinationAccount
} = params(Withdrawal), } = params(Withdrawal),
do(fun () -> do(fun () ->
valid = validate_wallet_limits(WalletID, Body, WalletAccount), valid = ff_party:validate_wallet_limits(WalletID, Body, WalletAccount),
#{provider_id := ProviderID} = route(Withdrawal), #{provider_id := ProviderID} = route(Withdrawal),
SenderSt = unwrap(ff_identity_machine:get(ff_account:identity(WalletAccount))), SenderSt = unwrap(ff_identity_machine:get(ff_account:identity(WalletAccount))),
ReceiverSt = unwrap(ff_identity_machine:get(ff_account:identity(DestinationAccount))), ReceiverSt = unwrap(ff_identity_machine:get(ff_account:identity(DestinationAccount))),
@ -316,29 +313,6 @@ poll_session_completion(Withdrawal) ->
end end
end). end).
-spec get_contract_terms(wallet(), body(), timestamp()) -> Result when
Result :: {ok, withdrawal_terms()} | {error, Error},
Error ::
{party_not_found, id()} |
{party_not_exists_yet, id()} |
{exception, any()}.
get_contract_terms(Wallet, Body, Timestamp) ->
WalletID = ff_wallet:id(Wallet),
IdentityID = ff_wallet:identity(Wallet),
do(fun() ->
IdentityMachine = unwrap(ff_identity_machine:get(IdentityID)),
Identity = ff_identity_machine:identity(IdentityMachine),
ContractID = ff_identity:contract(Identity),
PartyID = ff_identity:party(Identity),
{_Amount, CurrencyID} = Body,
TermVarset = #{
amount => Body,
wallet_id => WalletID,
currency_id => CurrencyID
},
unwrap(ff_party:get_contract_terms(PartyID, ContractID, TermVarset, Timestamp))
end).
-spec get_route_provider(route()) -> {ok, provider()}. -spec get_route_provider(route()) -> {ok, provider()}.
get_route_provider(#{provider_id := ProviderID}) -> get_route_provider(#{provider_id := ProviderID}) ->
ff_withdrawal_provider:get(ProviderID). ff_withdrawal_provider:get(ProviderID).
@ -364,11 +338,6 @@ finalize_cash_flow(CashFlowPlan, WalletAccount, DestinationAccount, SystemAccoun
}), }),
ff_cash_flow:finalize(CashFlowPlan, Accounts, Constants). ff_cash_flow:finalize(CashFlowPlan, Accounts, Constants).
validate_wallet_limits(WalletID, Body, Account) ->
Wallet = ff_wallet_machine:wallet(unwrap(wallet, ff_wallet_machine:get(WalletID))),
Terms = unwrap(contract, get_contract_terms(Wallet, Body, ff_time:now())),
unwrap(wallet_limit, ff_party:validate_wallet_limits(Account, Terms)).
-spec maybe_migrate(ff_transfer:event() | ff_transfer:legacy_event()) -> -spec maybe_migrate(ff_transfer:event() | ff_transfer:legacy_event()) ->
ff_transfer:event(). ff_transfer:event().
maybe_migrate(Ev) -> maybe_migrate(Ev) ->

View File

@ -15,6 +15,7 @@
-export([get_missing_fails/1]). -export([get_missing_fails/1]).
-export([deposit_via_admin_ok/1]). -export([deposit_via_admin_ok/1]).
-export([deposit_via_admin_bad/1]).
-export([deposit_withdrawal_ok/1]). -export([deposit_withdrawal_ok/1]).
-type config() :: ct_helper:config(). -type config() :: ct_helper:config().
@ -34,6 +35,7 @@ groups() ->
{default, [parallel], [ {default, [parallel], [
get_missing_fails, get_missing_fails,
deposit_via_admin_ok, deposit_via_admin_ok,
deposit_via_admin_bad,
deposit_withdrawal_ok deposit_withdrawal_ok
]} ]}
]. ].
@ -80,6 +82,7 @@ end_per_testcase(_Name, _C) ->
-spec get_missing_fails(config()) -> test_return(). -spec get_missing_fails(config()) -> test_return().
-spec deposit_via_admin_ok(config()) -> test_return(). -spec deposit_via_admin_ok(config()) -> test_return().
-spec deposit_via_admin_bad(config()) -> test_return().
-spec deposit_withdrawal_ok(config()) -> test_return(). -spec deposit_withdrawal_ok(config()) -> test_return().
get_missing_fails(_C) -> get_missing_fails(_C) ->
@ -131,6 +134,55 @@ deposit_via_admin_ok(C) ->
), ),
ok = await_wallet_balance({20000, <<"RUB">>}, WalID). ok = await_wallet_balance({20000, <<"RUB">>}, WalID).
deposit_via_admin_bad(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
WalID = create_wallet(IID, <<"HAHA NO">>, <<"RUB">>, C),
ok = await_wallet_balance({0, <<"RUB">>}, WalID),
% Create source
{ok, Src1} = admin_call('CreateSource', [#fistful_SourceParams{
name = <<"HAHA NO">>,
identity_id = IID,
currency = #'CurrencyRef'{symbolic_code = <<"RUB">>},
resource = #fistful_SourceResource{details = <<"Infinite source of cash">>}
}]),
unauthorized = Src1#fistful_Source.status,
SrcID = Src1#fistful_Source.id,
authorized = ct_helper:await(
authorized,
fun () ->
{ok, Src} = admin_call('GetSource', [SrcID]),
Src#fistful_Source.status
end
),
% Process deposit
% dbg:tracer(),
% dbg:tp(ff_transfer_machine, []),
% dbg:tp(ff_deposit, process_transfer, 1, []),
% dbg:p(all, c),
{ok, Dep1} = admin_call('CreateDeposit', [#fistful_DepositParams{
source = SrcID,
destination = WalID,
body = #'Cash'{
amount = 10000002,
currency = #'CurrencyRef'{symbolic_code = <<"RUB">>}
}
}]),
DepID = Dep1#fistful_Deposit.id,
{pending, _} = Dep1#fistful_Deposit.status,
failed = ct_helper:await(
failed,
fun () ->
{ok, Dep} = admin_call('GetDeposit', [DepID]),
{Status, _} = Dep#fistful_Deposit.status,
Status
end,
genlib_retry:linear(15, 1000)
),
ok = await_wallet_balance({0, <<"RUB">>}, WalID).
deposit_withdrawal_ok(C) -> deposit_withdrawal_ok(C) ->
Party = create_party(C), Party = create_party(C),
IID = create_person_identity(Party, C), IID = create_person_identity(Party, C),
@ -145,7 +197,7 @@ deposit_withdrawal_ok(C) ->
DestID = create_destination(IID, C), DestID = create_destination(IID, C),
pass_identification(ICID, IID, C), pass_identification(ICID, IID, C),
process_withdrawal(WalID, DestID). process_withdrawal(WalID, DestID).
create_party(_C) -> create_party(_C) ->

View File

@ -0,0 +1,3 @@
{erl_opts, [
{parse_transform, lager_transform}
]}.

View File

@ -43,12 +43,13 @@
-export([validate_account_creation/2]). -export([validate_account_creation/2]).
-export([validate_withdrawal_creation/3]). -export([validate_withdrawal_creation/3]).
-export([validate_wallet_limits/2]). -export([validate_wallet_limits/2]).
-export([validate_wallet_limits/3]).
-export([get_contract_terms/3]).
-export([get_contract_terms/4]). -export([get_contract_terms/4]).
-export([get_withdrawal_cash_flow_plan/1]). -export([get_withdrawal_cash_flow_plan/1]).
%% Internal types %% Internal types
-type body() :: ff_transfer:body().
-type cash() :: ff_transaction:body(). -type cash() :: ff_transaction:body().
-type terms() :: dmsl_domain_thrift:'TermSet'(). -type terms() :: dmsl_domain_thrift:'TermSet'().
-type wallet_terms() :: dmsl_domain_thrift:'WalletServiceTerms'() | undefined. -type wallet_terms() :: dmsl_domain_thrift:'WalletServiceTerms'() | undefined.
@ -58,6 +59,7 @@
-type domain_cash() :: dmsl_domain_thrift:'Cash'(). -type domain_cash() :: dmsl_domain_thrift:'Cash'().
-type cash_range() :: dmsl_domain_thrift:'CashRange'(). -type cash_range() :: dmsl_domain_thrift:'CashRange'().
-type timestamp() :: ff_time:timestamp_ms(). -type timestamp() :: ff_time:timestamp_ms().
-type wallet() :: ff_wallet:wallet().
-type currency_validation_error() :: {terms_violation, {not_allowed_currency, _Details}}. -type currency_validation_error() :: {terms_violation, {not_allowed_currency, _Details}}.
-type withdrawal_currency_error() :: {invalid_withdrawal_currency, currency_id(), {wallet_currency, currency_id()}}. -type withdrawal_currency_error() :: {invalid_withdrawal_currency, currency_id(), {wallet_currency, currency_id()}}.
@ -65,7 +67,7 @@
%% Pipeline %% Pipeline
-import(ff_pipeline, [do/1, unwrap/1]). -import(ff_pipeline, [do/1, unwrap/1, unwrap/2]).
%% %%
@ -133,7 +135,28 @@ change_contractor_level(ID, ContractID, ContractorLevel) ->
ok ok
end). end).
%% -spec get_contract_terms(wallet(), body(), timestamp()) -> Result when
Result :: {ok, wallet_terms()} | {error, Error},
Error ::
{party_not_found, id()} |
{party_not_exists_yet, id()} |
{exception, any()}.
get_contract_terms(Wallet, Body, Timestamp) ->
WalletID = ff_wallet:id(Wallet),
IdentityID = ff_wallet:identity(Wallet),
do(fun() ->
IdentityMachine = unwrap(ff_identity_machine:get(IdentityID)),
Identity = ff_identity_machine:identity(IdentityMachine),
ContractID = ff_identity:contract(Identity),
PartyID = ff_identity:party(Identity),
{_Amount, CurrencyID} = Body,
TermVarset = #{
amount => Body,
wallet_id => WalletID,
currency_id => CurrencyID
},
unwrap(get_contract_terms(PartyID, ContractID, TermVarset, Timestamp))
end).
-spec get_contract_terms(id(), contract_id(), term_varset(), timestamp()) -> Result when -spec get_contract_terms(id(), contract_id(), term_varset(), timestamp()) -> Result when
Result :: {ok, terms()} | {error, Error}, Result :: {ok, terms()} | {error, Error},
@ -448,6 +471,13 @@ validate_wallet_limits(Account, #domain_TermSet{wallets = WalletTerms}) ->
valid = unwrap(validate_cash_range(ExpMaxCash, CashRange)) valid = unwrap(validate_cash_range(ExpMaxCash, CashRange))
end). end).
-spec validate_wallet_limits(machinery:id(), body(), ff_account:account()) ->
valid | {error, cash_range_validation_error()}.
validate_wallet_limits(WalletID, Body, Account) ->
Wallet = ff_wallet_machine:wallet(unwrap(wallet, ff_wallet_machine:get(WalletID))),
Terms = unwrap(contract, get_contract_terms(Wallet, Body, ff_time:now())),
unwrap(wallet_limit, validate_wallet_limits(Account, Terms)).
-spec validate_wallet_limits_terms_is_reduced(wallet_terms()) -> -spec validate_wallet_limits_terms_is_reduced(wallet_terms()) ->
{ok, valid} | {error, {invalid_terms, _Details}}. {ok, valid} | {error, {invalid_terms, _Details}}.
validate_wallet_limits_terms_is_reduced(Terms) -> validate_wallet_limits_terms_is_reduced(Terms) ->