TD-303: Add multiscope support (#7)

As of valitydev/limiter-proto@d390910.

Co-authored-by: Артем <WWW_cool@inbox.ru>
This commit is contained in:
Andrew Mayorov 2022-06-03 11:41:44 +03:00 committed by GitHub
parent 3b10d1cbf3
commit b1cd093ffb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 250 additions and 109 deletions

View File

@ -103,19 +103,19 @@ marshal_context_type(payment_processing) ->
marshal_type(turnover) -> marshal_type(turnover) ->
{turnover, #limiter_config_LimitTypeTurnover{}}. {turnover, #limiter_config_LimitTypeTurnover{}}.
marshal_scope({scope, Type}) -> marshal_scope(Types) ->
{scope, marshal_scope_type(Type)}; {multi, ordsets:from_list(lists:map(fun marshal_scope_type/1, ordsets:to_list(Types)))}.
marshal_scope(global) ->
{scope_global, #limiter_config_LimitScopeGlobal{}}.
marshal_scope_type(party) -> marshal_scope_type(party) ->
{party, #limiter_config_LimitScopeTypeParty{}}; {party, #limiter_config_LimitScopeEmptyDetails{}};
marshal_scope_type(shop) -> marshal_scope_type(shop) ->
{shop, #limiter_config_LimitScopeTypeShop{}}; {shop, #limiter_config_LimitScopeEmptyDetails{}};
marshal_scope_type(wallet) -> marshal_scope_type(wallet) ->
{wallet, #limiter_config_LimitScopeTypeWallet{}}; {wallet, #limiter_config_LimitScopeEmptyDetails{}};
marshal_scope_type(identity) -> marshal_scope_type(identity) ->
{identity, #limiter_config_LimitScopeTypeIdentity{}}. {identity, #limiter_config_LimitScopeEmptyDetails{}};
marshal_scope_type(payment_tool) ->
{payment_tool, #limiter_config_LimitScopeEmptyDetails{}}.
%% %%
@ -239,10 +239,10 @@ unmarshal_context_type({payment_processing, #limiter_config_LimitContextTypePaym
unmarshal_type({turnover, #limiter_config_LimitTypeTurnover{}}) -> unmarshal_type({turnover, #limiter_config_LimitTypeTurnover{}}) ->
turnover. turnover.
unmarshal_scope({scope, Type}) -> unmarshal_scope({single, Type}) ->
{scope, unmarshal_scope_type(Type)}; ordsets:from_list([unmarshal_scope_type(Type)]);
unmarshal_scope({scope_global, #limiter_config_LimitScopeGlobal{}}) -> unmarshal_scope({multi, Types}) ->
global. ordsets:from_list(lists:map(fun unmarshal_scope_type/1, ordsets:to_list(Types))).
unmarshal_scope_type({party, _}) -> unmarshal_scope_type({party, _}) ->
party; party;
@ -251,7 +251,9 @@ unmarshal_scope_type({shop, _}) ->
unmarshal_scope_type({wallet, _}) -> unmarshal_scope_type({wallet, _}) ->
wallet; wallet;
unmarshal_scope_type({identity, _}) -> unmarshal_scope_type({identity, _}) ->
identity. identity;
unmarshal_scope_type({payment_tool, _}) ->
payment_tool.
%% %%
@ -274,7 +276,7 @@ marshal_unmarshal_created_test() ->
time_range_type => {calendar, day}, time_range_type => {calendar, day},
context_type => payment_processing, context_type => payment_processing,
type => turnover, type => turnover,
scope => {scope, party}, scope => ordsets:from_list([party, shop]),
description => <<"description">> description => <<"description">>
}}, }},
Event = {ev, lim_time:machinery_now(), Created}, Event = {ev, lim_time:machinery_now(), Created},

View File

@ -39,7 +39,8 @@
-type description() :: binary(). -type description() :: binary().
-type limit_type() :: turnover. -type limit_type() :: turnover.
-type limit_scope() :: global | {scope, party | shop | wallet | identity}. -type limit_scope() :: ordsets:ordset(limit_scope_type()).
-type limit_scope_type() :: party | shop | wallet | identity.
-type body_type() :: {cash, currency()} | amount. -type body_type() :: {cash, currency()} | amount.
-type shard_size() :: pos_integer(). -type shard_size() :: pos_integer().
-type shard_id() :: binary(). -type shard_id() :: binary().
@ -211,11 +212,11 @@ type(#{type := Value}) ->
type(_) -> type(_) ->
undefined. undefined.
-spec scope(config()) -> lim_maybe:maybe(limit_scope()). -spec scope(config()) -> limit_scope().
scope(#{scope := Value}) -> scope(#{scope := Value}) ->
Value; Value;
scope(_) -> scope(_) ->
undefined. ordsets:new().
-spec context_type(config()) -> context_type(). -spec context_type(config()) -> context_type().
context_type(#{context_type := Value}) -> context_type(#{context_type := Value}) ->
@ -448,7 +449,7 @@ calculate_calendar_shard_id(Range, Timestamp, StartedAt, ShardSize) ->
{CurrentDatetime, _USec1} = lim_range_codec:parse_timestamp(Timestamp), {CurrentDatetime, _USec1} = lim_range_codec:parse_timestamp(Timestamp),
Units = calculate_time_units(Range, CurrentDatetime, StartDatetime), Units = calculate_time_units(Range, CurrentDatetime, StartDatetime),
SignPrefix = mk_sign_prefix(Units), SignPrefix = mk_sign_prefix(Units),
RangePrefix = mk_prefix(Range), RangePrefix = mk_unit_prefix(Range),
mk_shard_id(<<SignPrefix/binary, "/", RangePrefix/binary>>, Units, ShardSize). mk_shard_id(<<SignPrefix/binary, "/", RangePrefix/binary>>, Units, ShardSize).
calculate_time_units(year, CurrentDatetime, StartDatetime) -> calculate_time_units(year, CurrentDatetime, StartDatetime) ->
@ -525,29 +526,65 @@ year({{Year, _, _}, _Time}) ->
month({{_Year, Month, _}, _Time}) -> month({{_Year, Month, _}, _Time}) ->
Month. Month.
mk_prefix(day) -> <<"day">>; mk_unit_prefix(day) -> <<"day">>;
mk_prefix(week) -> <<"week">>; mk_unit_prefix(week) -> <<"week">>;
mk_prefix(month) -> <<"month">>; mk_unit_prefix(month) -> <<"month">>;
mk_prefix(year) -> <<"year">>. mk_unit_prefix(year) -> <<"year">>.
mk_sign_prefix(Units) when Units >= 0 -> <<"future">>; mk_sign_prefix(Units) when Units >= 0 -> <<"future">>;
mk_sign_prefix(_) -> <<"past">>. mk_sign_prefix(_) -> <<"past">>.
mk_shard_id(Prefix, Units0, ShardSize) -> mk_shard_id(Prefix, Units, ShardSize) ->
Units1 = abs(Units0), ID = integer_to_binary(abs(Units) div ShardSize),
ID = list_to_binary(integer_to_list(Units1 div ShardSize)),
<<Prefix/binary, "/", ID/binary>>. <<Prefix/binary, "/", ID/binary>>.
-spec mk_scope_prefix(config(), lim_context()) -> {ok, prefix()}. -spec mk_scope_prefix(config(), lim_context()) -> prefix().
mk_scope_prefix(#{scope := global}, _LimitContext) -> mk_scope_prefix(Config, LimitContext) ->
{ok, <<>>}; mk_scope_prefix_impl(scope(Config), LimitContext).
mk_scope_prefix(#{scope := {scope, party}}, LimitContext) ->
{ok, PartyID} = lim_context:get_from_context(payment_processing, owner_id, invoice, LimitContext), -spec mk_scope_prefix_impl(limit_scope(), lim_context()) -> prefix().
{ok, <<"/", PartyID/binary>>}; mk_scope_prefix_impl(Scope, LimitContext) ->
mk_scope_prefix(#{scope := {scope, shop}}, LimitContext) -> Bits = enumerate_context_bits(Scope),
{ok, PartyID} = lim_context:get_from_context(payment_processing, owner_id, invoice, LimitContext), ordsets:fold(
{ok, ShopID} = lim_context:get_from_context(payment_processing, shop_id, invoice, LimitContext), fun(Bit, Acc) ->
{ok, <<"/", PartyID/binary, "/", ShopID/binary>>}. {ok, Value} = extract_context_bit(Bit, LimitContext),
append_prefix(Value, Acc)
end,
<<>>,
Bits
).
-spec append_prefix(binary(), prefix()) -> prefix().
append_prefix(Fragment, Acc) ->
<<Acc/binary, "/", Fragment/binary>>.
-type context_bit() ::
{from, lim_context:context_type(), _Name :: atom(), lim_context:context_operation()}
| {order, integer(), context_bit()}.
-spec enumerate_context_bits(limit_scope()) -> ordsets:ordset(context_bit()).
enumerate_context_bits(Types) ->
ordsets:fold(fun append_context_bits/2, ordsets:new(), Types).
append_context_bits(party, Bits) ->
ordsets:add_element(
{order, 1, {from, payment_processing, owner_id, invoice}},
Bits
);
append_context_bits(shop, Bits) ->
lists:foldl(fun ordsets:add_element/2, Bits, [
% NOTE
% Shop scope implies party scope.
% Also we need to preserve order between party / shop to ensure backwards compatibility.
{order, 1, {from, payment_processing, owner_id, invoice}},
{order, 2, {from, payment_processing, shop_id, invoice}}
]).
-spec extract_context_bit(context_bit(), lim_context()) -> {ok, binary()}.
extract_context_bit({order, _, Bit}, LimitContext) ->
extract_context_bit(Bit, LimitContext);
extract_context_bit({from, ContextType, ValueName, Op}, LimitContext) ->
lim_context:get_from_context(ContextType, ValueName, Op, LimitContext).
%%% Machinery callbacks %%% Machinery callbacks
@ -747,4 +784,33 @@ check_calculate_year_shard_id_test() ->
?assertEqual(<<"past/year/1">>, calculate_calendar_shard_id(year, <<"2000-01-01T00:00:00Z">>, StartedAt2, 1)), ?assertEqual(<<"past/year/1">>, calculate_calendar_shard_id(year, <<"2000-01-01T00:00:00Z">>, StartedAt2, 1)),
?assertEqual(<<"future/year/0">>, calculate_calendar_shard_id(year, <<"2001-01-01T00:00:00Z">>, StartedAt2, 1)). ?assertEqual(<<"future/year/0">>, calculate_calendar_shard_id(year, <<"2001-01-01T00:00:00Z">>, StartedAt2, 1)).
-define(LIMIT_CONTEXT, #{
context => #{
payment_processing => #{
op => invoice,
invoice => #{
owner_id => <<"OWNER">>,
shop_id => <<"SHLOP">>
}
}
}
}).
-spec global_scope_empty_prefix_test() -> _.
global_scope_empty_prefix_test() ->
?assertEqual(<<>>, mk_scope_prefix_impl(ordsets:new(), ?LIMIT_CONTEXT)).
-spec preserve_scope_prefix_order_test_() -> [_TestGen].
preserve_scope_prefix_order_test_() ->
[
?_assertEqual(
<<"/OWNER/SHLOP">>,
mk_scope_prefix_impl(ordsets:from_list([shop, party]), ?LIMIT_CONTEXT)
),
?_assertEqual(
<<"/OWNER/SHLOP">>,
mk_scope_prefix_impl(ordsets:from_list([shop]), ?LIMIT_CONTEXT)
)
].
-endif. -endif.

View File

@ -102,7 +102,7 @@ marshal_unmarshal_created_test() ->
time_range_type => {calendar, day}, time_range_type => {calendar, day},
context_type => payment_processing, context_type => payment_processing,
type => turnover, type => turnover,
scope => {scope, party}, scope => ordsets:from_list([party]),
description => <<"description">> description => <<"description">>
}}, }},
Context = #{machine_ref => ID, machine_ns => config}, Context = #{machine_ref => ID, machine_ns => config},

View File

@ -89,7 +89,7 @@ mk_limit_config(<<"ShopDayTurnover">>) ->
{ok, #{ {ok, #{
processor_type => <<"TurnoverProcessor">>, processor_type => <<"TurnoverProcessor">>,
type => turnover, type => turnover,
scope => {scope, shop}, scope => ordsets:from_list([shop]),
shard_size => 7, shard_size => 7,
context_type => payment_processing, context_type => payment_processing,
time_range_type => {calendar, day} time_range_type => {calendar, day}
@ -98,7 +98,7 @@ mk_limit_config(<<"PartyDayTurnover">>) ->
{ok, #{ {ok, #{
processor_type => <<"TurnoverProcessor">>, processor_type => <<"TurnoverProcessor">>,
type => turnover, type => turnover,
scope => {scope, party}, scope => ordsets:from_list([party]),
shard_size => 7, shard_size => 7,
context_type => payment_processing, context_type => payment_processing,
time_range_type => {calendar, day} time_range_type => {calendar, day}
@ -107,7 +107,7 @@ mk_limit_config(<<"ShopMonthTurnover">>) ->
{ok, #{ {ok, #{
processor_type => <<"TurnoverProcessor">>, processor_type => <<"TurnoverProcessor">>,
type => turnover, type => turnover,
scope => {scope, shop}, scope => ordsets:from_list([shop]),
shard_size => 12, shard_size => 12,
context_type => payment_processing, context_type => payment_processing,
time_range_type => {calendar, month} time_range_type => {calendar, month}
@ -116,7 +116,7 @@ mk_limit_config(<<"PartyMonthTurnover">>) ->
{ok, #{ {ok, #{
processor_type => <<"TurnoverProcessor">>, processor_type => <<"TurnoverProcessor">>,
type => turnover, type => turnover,
scope => {scope, party}, scope => ordsets:from_list([party]),
shard_size => 12, shard_size => 12,
context_type => payment_processing, context_type => payment_processing,
time_range_type => {calendar, month} time_range_type => {calendar, month}
@ -125,7 +125,7 @@ mk_limit_config(<<"GlobalMonthTurnover">>) ->
{ok, #{ {ok, #{
processor_type => <<"TurnoverProcessor">>, processor_type => <<"TurnoverProcessor">>,
type => turnover, type => turnover,
scope => global, scope => ordsets:new(),
shard_size => 12, shard_size => 12,
context_type => payment_processing, context_type => payment_processing,
time_range_type => {calendar, month} time_range_type => {calendar, month}

View File

@ -21,7 +21,7 @@
-type cash() :: lim_body:cash(). -type cash() :: lim_body:cash().
-type t() :: #{ -type t() :: #{
woody_context := woody_context(), woody_context => woody_context(),
context => context(), context => context(),
clock => clock() clock => clock()
}. }.

View File

@ -14,13 +14,6 @@
-define(LIMIT_CHANGE(ID), #limiter_LimitChange{id = ID}). -define(LIMIT_CHANGE(ID), #limiter_LimitChange{id = ID}).
-define(CASH(
Amount,
Currency
),
#limiter_base_Cash{amount = Amount, currency = #limiter_base_CurrencyRef{symbolic_code = Currency}}
).
%% %%
-spec handle_function(woody:func(), woody:args(), woody_context:ctx(), woody:options()) -> {ok, woody:result()}. -spec handle_function(woody:func(), woody:args(), woody_context:ctx(), woody:options()) -> {ok, woody:result()}.

View File

@ -122,7 +122,7 @@ construct_plan_id(#limiter_LimitChange{change_id = ChangeID}) ->
ChangeID. ChangeID.
construct_range_id(LimitID, Timestamp, Config, LimitContext) -> construct_range_id(LimitID, Timestamp, Config, LimitContext) ->
{ok, Prefix} = lim_config_machine:mk_scope_prefix(Config, LimitContext), Prefix = lim_config_machine:mk_scope_prefix(Config, LimitContext),
ShardID = lim_config_machine:calculate_shard_id(Timestamp, Config), ShardID = lim_config_machine:calculate_shard_id(Timestamp, Config),
<<LimitID/binary, Prefix/binary, "/", ShardID/binary>>. <<LimitID/binary, Prefix/binary, "/", ShardID/binary>>.

View File

@ -1,9 +1,9 @@
-module(lim_configurator_SUITE). -module(lim_configurator_SUITE).
-include_lib("stdlib/include/assert.hrl").
-include_lib("common_test/include/ct.hrl"). -include_lib("common_test/include/ct.hrl").
-include_lib("stdlib/include/assert.hrl").
-include_lib("limiter_proto/include/lim_configurator_thrift.hrl"). -include_lib("limiter_proto/include/lim_configurator_thrift.hrl").
-include("lim_ct_helper.hrl").
-export([all/0]). -export([all/0]).
@ -15,13 +15,12 @@
-export([legacy_create_config/1]). -export([legacy_create_config/1]).
-export([create_config/1]). -export([create_config/1]).
-export([create_config_single_scope/1]).
-export([get_config/1]). -export([get_config/1]).
-type group_name() :: atom(). -type group_name() :: atom().
-type test_case_name() :: atom(). -type test_case_name() :: atom().
-define(RATE_SOURCE_ID, <<"dummy_source_id">>).
%% tests descriptions %% tests descriptions
-spec all() -> [{group, group_name()}]. -spec all() -> [{group, group_name()}].
@ -36,6 +35,7 @@ groups() ->
{default, [], [ {default, [], [
legacy_create_config, legacy_create_config,
create_config, create_config,
create_config_single_scope,
get_config get_config
]} ]}
]. ].
@ -64,49 +64,88 @@ end_per_suite(Config) ->
_ = [application:stop(App) || App <- proplists:get_value(apps, Config)]. _ = [application:stop(App) || App <- proplists:get_value(apps, Config)].
-spec init_per_testcase(test_case_name(), config()) -> config(). -spec init_per_testcase(test_case_name(), config()) -> config().
init_per_testcase(_Name, C) -> init_per_testcase(Name, C) ->
C. [{limit_id, mk_limit_id(Name)} | C].
-spec end_per_testcase(test_case_name(), config()) -> ok. -spec end_per_testcase(test_case_name(), config()) -> ok.
end_per_testcase(_Name, _C) -> end_per_testcase(_Name, _C) ->
ok. ok.
mk_limit_id(Name) ->
genlib:format("~p/~B", [Name, erlang:system_time(millisecond)]).
%% %%
-spec legacy_create_config(config()) -> _. -spec legacy_create_config(config()) -> _.
legacy_create_config(_C) -> legacy_create_config(C) ->
Client = lim_client:new(), Client = lim_client:new(),
ID = ?config(limit_id, C),
Description = genlib:unique(),
Params = #limiter_cfg_LimitCreateParams{ Params = #limiter_cfg_LimitCreateParams{
id = <<"ID">>, id = ID,
name = <<"GlobalMonthTurnover">>, name = <<"GlobalMonthTurnover">>,
description = <<"description">>, description = Description,
started_at = <<"2000-01-01T00:00:00Z">>, started_at = <<"2000-01-01T00:00:00Z">>,
body_type = {cash, #limiter_config_LimitBodyTypeCash{currency = <<"RUB">>}} body_type = ?body_type_cash()
}, },
{ok, #limiter_config_LimitConfig{}} = lim_client:legacy_create_config(Params, Client). ?assertMatch(
{ok, #limiter_config_LimitConfig{
id = ID,
description = Description
}},
lim_client:legacy_create_config(Params, Client)
).
-spec create_config(config()) -> _. -spec create_config(config()) -> _.
create_config(_C) -> create_config(C) ->
Client = lim_client:new(),
ID = ?config(limit_id, C),
Description = genlib:unique(),
Params = #limiter_config_LimitConfigParams{
id = ?config(limit_id, C),
description = Description,
started_at = <<"2000-01-01T00:00:00Z">>,
body_type = ?body_type_cash(<<"RUB">>),
shard_size = 4,
time_range_type = ?time_range_week(),
type = ?lim_type_turnover(),
scope = ?scope([
?scope_shop(),
?scope_party()
]),
op_behaviour = ?op_behaviour(),
context_type = ?ctx_type_payproc()
},
?assertMatch(
{ok, #limiter_config_LimitConfig{
id = ID,
description = Description
}},
lim_client:create_config(Params, Client)
).
-spec create_config_single_scope(config()) -> _.
create_config_single_scope(C) ->
Client = lim_client:new(), Client = lim_client:new(),
Params = #limiter_config_LimitConfigParams{ Params = #limiter_config_LimitConfigParams{
id = <<"ID">>, id = ?config(limit_id, C),
description = <<"description">>,
started_at = <<"2000-01-01T00:00:00Z">>, started_at = <<"2000-01-01T00:00:00Z">>,
body_type = {cash, #limiter_config_LimitBodyTypeCash{currency = <<"RUB">>}}, body_type = ?body_type_cash(),
shard_size = 4, time_range_type = ?time_range_week(),
time_range_type = {calendar, {week, #time_range_TimeRangeTypeCalendarWeek{}}}, shard_size = 1,
type = {turnover, #limiter_config_LimitTypeTurnover{}}, type = ?lim_type_turnover(),
scope = {scope, {shop, #limiter_config_LimitScopeTypeShop{}}}, scope = {single, ?scope_party()},
op_behaviour = #limiter_config_OperationLimitBehaviour{ context_type = ?ctx_type_payproc(),
invoice_payment_refund = {addition, #limiter_config_Addition{}} op_behaviour = ?op_behaviour()
},
context_type = {payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}}
}, },
{ok, #limiter_config_LimitConfig{}} = lim_client:create_config(Params, Client). {ok, #limiter_config_LimitConfig{
scope = Scope
}} = lim_client:create_config(Params, Client),
?assertEqual(?scope([?scope_party()]), Scope).
-spec get_config(config()) -> _. -spec get_config(config()) -> _.
get_config(C) -> get_config(C) ->
ID = <<"ID">>, ID = ?config(limit_id, C),
#{client := Client} = prepare_environment(ID, <<"GlobalMonthTurnover">>, C), #{client := Client} = prepare_environment(ID, <<"GlobalMonthTurnover">>, C),
{ok, #limiter_config_LimitConfig{id = ID}} = lim_client:get_config(ID, Client). {ok, #limiter_config_LimitConfig{id = ID}} = lim_client:get_config(ID, Client).
@ -119,7 +158,7 @@ prepare_environment(ID, LimitName, _C) ->
name = LimitName, name = LimitName,
description = <<"description">>, description = <<"description">>,
started_at = <<"2000-01-01T00:00:00Z">>, started_at = <<"2000-01-01T00:00:00Z">>,
body_type = {cash, #limiter_config_LimitBodyTypeCash{currency = <<"RUB">>}} body_type = ?body_type_cash()
}, },
{ok, LimitConfig} = lim_client:legacy_create_config(Params, Client), {ok, LimitConfig} = lim_client:legacy_create_config(Params, Client),
#{config => LimitConfig, client => Client}. #{config => LimitConfig, client => Client}.

View File

@ -3,11 +3,51 @@
-include_lib("limiter_proto/include/lim_configurator_thrift.hrl"). -include_lib("limiter_proto/include/lim_configurator_thrift.hrl").
-define(cash(Amount), #limiter_base_Cash{ -define(currency, <<"RUB">>).
-define(cash(Amount), ?cash(Amount, ?currency)).
-define(cash(Amount, Currency), #limiter_base_Cash{
amount = Amount, amount = Amount,
currency = #limiter_base_CurrencyRef{symbolic_code = <<"RUB">>} currency = #limiter_base_CurrencyRef{symbolic_code = Currency}
}). }).
-define(scope(Types), {multi, ordsets:from_list(Types)}).
-define(global(), ?scope([])).
-define(scope_party(), {party, #limiter_config_LimitScopeEmptyDetails{}}).
-define(scope_shop(), {shop, #limiter_config_LimitScopeEmptyDetails{}}).
-define(body_type_cash(), ?body_type_cash(?currency)).
-define(body_type_cash(Currency),
{cash, #limiter_config_LimitBodyTypeCash{currency = Currency}}
).
-define(lim_type_turnover(),
{turnover, #limiter_config_LimitTypeTurnover{}}
).
-define(time_range_day(),
{calendar, {day, #time_range_TimeRangeTypeCalendarDay{}}}
).
-define(time_range_week(),
{calendar, {week, #time_range_TimeRangeTypeCalendarWeek{}}}
).
-define(time_range_month(),
{calendar, {month, #time_range_TimeRangeTypeCalendarMonth{}}}
).
-define(op_behaviour(), ?op_behaviour(?op_addition())).
-define(op_behaviour(Refund), #limiter_config_OperationLimitBehaviour{
invoice_payment_refund = Refund
}).
-define(op_addition(), {addition, #limiter_config_Addition{}}).
-define(op_subtraction(), {subtraction, #limiter_config_Subtraction{}}).
-define(ctx_type_payproc(),
{payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}}
).
-define(op_invoice_payment(), {invoice_payment, #limiter_context_PaymentProcessingOperationInvoicePayment{}}). -define(op_invoice_payment(), {invoice_payment, #limiter_context_PaymentProcessingOperationInvoicePayment{}}).
-define(ctx_invoice_payment(Cost, CaptureCost), ?ctx_invoice_payment(undefined, undefined, Cost, CaptureCost)). -define(ctx_invoice_payment(Cost, CaptureCost), ?ctx_invoice_payment(undefined, undefined, Cost, CaptureCost)).

View File

@ -129,7 +129,7 @@ end_per_testcase(_Name, C) ->
commit_with_default_exchange(C) -> commit_with_default_exchange(C) ->
Rational = #base_Rational{p = 1000000, q = 100}, Rational = #base_Rational{p = 1000000, q = 100},
_ = mock_exchange(Rational, C), _ = mock_exchange(Rational, C),
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_month(), ?global(), C),
ID = ?config(id, C), ID = ?config(id, C),
Context = #limiter_context_LimitContext{ Context = #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ payment_processing = #limiter_context_ContextPaymentProcessing{
@ -150,7 +150,7 @@ commit_with_default_exchange(C) ->
partial_commit_with_exchange(C) -> partial_commit_with_exchange(C) ->
Rational = #base_Rational{p = 800000, q = 100}, Rational = #base_Rational{p = 800000, q = 100},
_ = mock_exchange(Rational, C), _ = mock_exchange(Rational, C),
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_month(), ?global(), C),
ID = ?config(id, C), ID = ?config(id, C),
Context = #limiter_context_LimitContext{ Context = #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ payment_processing = #limiter_context_ContextPaymentProcessing{
@ -177,7 +177,7 @@ partial_commit_with_exchange(C) ->
commit_with_exchange(C) -> commit_with_exchange(C) ->
Rational = #base_Rational{p = 1000000, q = 100}, Rational = #base_Rational{p = 1000000, q = 100},
_ = mock_exchange(Rational, C), _ = mock_exchange(Rational, C),
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_month(), ?global(), C),
ID = ?config(id, C), ID = ?config(id, C),
Context = #limiter_context_LimitContext{ Context = #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ payment_processing = #limiter_context_ContextPaymentProcessing{
@ -214,7 +214,7 @@ get_rate(C) ->
-spec get_limit_notfound(config()) -> _. -spec get_limit_notfound(config()) -> _.
get_limit_notfound(C) -> get_limit_notfound(C) ->
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_month(), ?global(), C),
Context = #limiter_context_LimitContext{ Context = #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ payment_processing = #limiter_context_ContextPaymentProcessing{
op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}}, op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}},
@ -225,7 +225,7 @@ get_limit_notfound(C) ->
-spec hold_ok(config()) -> _. -spec hold_ok(config()) -> _.
hold_ok(C) -> hold_ok(C) ->
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_month(), ?global(), C),
ID = ?config(id, C), ID = ?config(id, C),
Context = #limiter_context_LimitContext{ Context = #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ payment_processing = #limiter_context_ContextPaymentProcessing{
@ -244,7 +244,7 @@ hold_ok(C) ->
-spec commit_ok(config()) -> _. -spec commit_ok(config()) -> _.
commit_ok(C) -> commit_ok(C) ->
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_month(), ?global(), C),
ID = ?config(id, C), ID = ?config(id, C),
Context = #limiter_context_LimitContext{ Context = #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ payment_processing = #limiter_context_ContextPaymentProcessing{
@ -263,7 +263,7 @@ commit_ok(C) ->
-spec rollback_ok(config()) -> _. -spec rollback_ok(config()) -> _.
rollback_ok(C) -> rollback_ok(C) ->
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_week(), ?global(), C),
ID = ?config(id, C), ID = ?config(id, C),
Context0 = ?ctx_invoice_payment(?cash(10), ?cash(10)), Context0 = ?ctx_invoice_payment(?cash(10), ?cash(10)),
Context1 = ?ctx_invoice_payment(?cash(10), ?cash(0)), Context1 = ?ctx_invoice_payment(?cash(10), ?cash(0)),
@ -277,7 +277,7 @@ refund_ok(C) ->
Client = ?config(client, C), Client = ?config(client, C),
OwnerID = <<"WWWcool Ltd">>, OwnerID = <<"WWWcool Ltd">>,
ShopID = <<"shop">>, ShopID = <<"shop">>,
_ = prepare_environment(<<"ShopDayTurnover">>, C), _ = configure_limit(?time_range_day(), ?scope([?scope_party(), ?scope_shop()]), C),
Context0 = ?ctx_invoice_payment(OwnerID, ShopID, ?cash(15), ?cash(15)), Context0 = ?ctx_invoice_payment(OwnerID, ShopID, ?cash(15), ?cash(15)),
RefundContext1 = ?ctx_invoice_payment_refund(OwnerID, ShopID, ?cash(10), ?cash(10), ?cash(10)), RefundContext1 = ?ctx_invoice_payment_refund(OwnerID, ShopID, ?cash(10), ?cash(10), ?cash(10)),
{ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID, <<"Payment">>), Context0, Client), {ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID, <<"Payment">>), Context0, Client),
@ -287,13 +287,13 @@ refund_ok(C) ->
-spec get_config_ok(config()) -> _. -spec get_config_ok(config()) -> _.
get_config_ok(C) -> get_config_ok(C) ->
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_week(), ?global(), C),
{ok, #limiter_config_LimitConfig{}} = lim_client:get_config(?config(id, C), ?config(client, C)). {ok, #limiter_config_LimitConfig{}} = lim_client:get_config(?config(id, C), ?config(client, C)).
-spec commit_inexistent_hold_fails(config()) -> _. -spec commit_inexistent_hold_fails(config()) -> _.
commit_inexistent_hold_fails(C) -> commit_inexistent_hold_fails(C) ->
ID = ?config(id, C), ID = ?config(id, C),
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_week(), ?global(), C),
Context = ?ctx_invoice_payment(?cash(42), undefined), Context = ?ctx_invoice_payment(?cash(42), undefined),
% NOTE % NOTE
% We do not expect `LimitChangeNotFound` here because we no longer reconcile with accounter % We do not expect `LimitChangeNotFound` here because we no longer reconcile with accounter
@ -304,7 +304,7 @@ commit_inexistent_hold_fails(C) ->
-spec partial_commit_inexistent_hold_fails(config()) -> _. -spec partial_commit_inexistent_hold_fails(config()) -> _.
partial_commit_inexistent_hold_fails(C) -> partial_commit_inexistent_hold_fails(C) ->
ID = ?config(id, C), ID = ?config(id, C),
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_week(), ?global(), C),
Context = ?ctx_invoice_payment(?cash(42), ?cash(21)), Context = ?ctx_invoice_payment(?cash(42), ?cash(21)),
% NOTE % NOTE
% We do not expect `LimitChangeNotFound` here because we no longer reconcile with accounter % We do not expect `LimitChangeNotFound` here because we no longer reconcile with accounter
@ -324,7 +324,7 @@ commit_multirange_limit_ok(C) ->
time_range_type = {calendar, {month, #time_range_TimeRangeTypeCalendarMonth{}}}, time_range_type = {calendar, {month, #time_range_TimeRangeTypeCalendarMonth{}}},
context_type = {payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}}, context_type = {payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}},
type = {turnover, #limiter_config_LimitTypeTurnover{}}, type = {turnover, #limiter_config_LimitTypeTurnover{}},
scope = {scope_global, #limiter_config_LimitScopeGlobal{}}, scope = ?scope([]),
op_behaviour = #limiter_config_OperationLimitBehaviour{} op_behaviour = #limiter_config_OperationLimitBehaviour{}
}, },
{ok, _LimitConfig} = lim_client:create_config(Params, Client), {ok, _LimitConfig} = lim_client:create_config(Params, Client),
@ -356,7 +356,7 @@ commit_multirange_limit_ok(C) ->
commit_processes_idempotently(C) -> commit_processes_idempotently(C) ->
ID = ?config(id, C), ID = ?config(id, C),
Client = ?config(client, C), Client = ?config(client, C),
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_week(), ?global(), C),
Context = ?ctx_invoice_payment(?cash(42), undefined), Context = ?ctx_invoice_payment(?cash(42), undefined),
Change = ?LIMIT_CHANGE(ID), Change = ?LIMIT_CHANGE(ID),
{ok, _} = lim_client:hold(Change, Context, Client), {ok, _} = lim_client:hold(Change, Context, Client),
@ -370,7 +370,7 @@ commit_processes_idempotently(C) ->
full_commit_processes_idempotently(C) -> full_commit_processes_idempotently(C) ->
ID = ?config(id, C), ID = ?config(id, C),
Client = ?config(client, C), Client = ?config(client, C),
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_week(), ?global(), C),
Cost = ?cash(42), Cost = ?cash(42),
Context = ?ctx_invoice_payment(Cost, Cost), Context = ?ctx_invoice_payment(Cost, Cost),
Change = ?LIMIT_CHANGE(ID), Change = ?LIMIT_CHANGE(ID),
@ -385,7 +385,7 @@ full_commit_processes_idempotently(C) ->
partial_commit_processes_idempotently(C) -> partial_commit_processes_idempotently(C) ->
ID = ?config(id, C), ID = ?config(id, C),
Client = ?config(client, C), Client = ?config(client, C),
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_week(), ?global(), C),
Context = ?ctx_invoice_payment(?cash(42), ?cash(40)), Context = ?ctx_invoice_payment(?cash(42), ?cash(40)),
Change = ?LIMIT_CHANGE(ID), Change = ?LIMIT_CHANGE(ID),
{ok, _} = lim_client:hold(Change, Context, Client), {ok, _} = lim_client:hold(Change, Context, Client),
@ -399,7 +399,7 @@ partial_commit_processes_idempotently(C) ->
rollback_processes_idempotently(C) -> rollback_processes_idempotently(C) ->
ID = ?config(id, C), ID = ?config(id, C),
Client = ?config(client, C), Client = ?config(client, C),
_ = prepare_environment(<<"GlobalMonthTurnover">>, C), _ = configure_limit(?time_range_week(), ?global(), C),
Context = ?ctx_invoice_payment(?cash(42), ?cash(0)), Context = ?ctx_invoice_payment(?cash(42), ?cash(0)),
Change = ?LIMIT_CHANGE(ID), Change = ?LIMIT_CHANGE(ID),
{ok, _} = lim_client:hold(Change, Context, Client), {ok, _} = lim_client:hold(Change, Context, Client),
@ -421,19 +421,20 @@ hold_and_commit(Change, Context, Client) ->
mock_exchange(Rational, C) -> mock_exchange(Rational, C) ->
lim_mock:mock_services([{xrates, fun('GetConvertedAmount', _) -> {ok, Rational} end}], C). lim_mock:mock_services([{xrates, fun('GetConvertedAmount', _) -> {ok, Rational} end}], C).
prepare_environment(LimitName, C) -> configure_limit(TimeRange, Scope, C) ->
ID = ?config(id, C), ID = ?config(id, C),
Params = #limiter_cfg_LimitCreateParams{ Params = #limiter_config_LimitConfigParams{
id = ID, id = ID,
name = LimitName,
description = <<"description">>,
started_at = <<"2000-01-01T00:00:00Z">>, started_at = <<"2000-01-01T00:00:00Z">>,
body_type = {cash, #limiter_config_LimitBodyTypeCash{currency = <<"RUB">>}}, body_type = ?body_type_cash(<<"RUB">>),
op_behaviour = #limiter_config_OperationLimitBehaviour{ time_range_type = TimeRange,
invoice_payment_refund = {subtraction, #limiter_config_Subtraction{}} shard_size = 1,
} type = ?lim_type_turnover(),
scope = Scope,
context_type = ?ctx_type_payproc(),
op_behaviour = ?op_behaviour(?op_subtraction())
}, },
{ok, _LimitConfig} = lim_client:legacy_create_config(Params, ?config(client, C)). {ok, _LimitConfig} = lim_client:create_config(Params, ?config(client, C)).
gen_unique_id(Prefix) -> gen_unique_id(Prefix) ->
genlib:format("~s/~B", [Prefix, lim_time:now()]). genlib:format("~s/~B", [Prefix, lim_time:now()]).

View File

@ -29,7 +29,7 @@
{damsel, {git, "https://github.com/valitydev/damsel.git", {branch, "master"}}}, {damsel, {git, "https://github.com/valitydev/damsel.git", {branch, "master"}}},
{limiter_proto, {git, "https://github.com/valitydev/limiter-proto.git", {branch, "master"}}}, {limiter_proto, {git, "https://github.com/valitydev/limiter-proto.git", {branch, "master"}}},
{xrates_proto, {git, "https://github.com/valitydev/xrates-proto.git", {branch, "master"}}}, {xrates_proto, {git, "https://github.com/valitydev/xrates-proto.git", {branch, "master"}}},
{machinery, {git, "https://github.com/valitydev/machinery.git", {branch, "master"}}}, {machinery, {git, "https://github.com/valitydev/machinery-erlang.git", {branch, "master"}}},
{erl_health, {git, "https://github.com/valitydev/erlang-health.git", {branch, "master"}}}, {erl_health, {git, "https://github.com/valitydev/erlang-health.git", {branch, "master"}}},
{genlib, {git, "https://github.com/valitydev/genlib.git", {branch, "master"}}}, {genlib, {git, "https://github.com/valitydev/genlib.git", {branch, "master"}}},
{scoper, {git, "https://github.com/valitydev/scoper.git", {branch, "master"}}}, {scoper, {git, "https://github.com/valitydev/scoper.git", {branch, "master"}}},

View File

@ -25,16 +25,16 @@
{<<"jsx">>,{pkg,<<"jsx">>,<<"3.1.0">>},1}, {<<"jsx">>,{pkg,<<"jsx">>,<<"3.1.0">>},1},
{<<"limiter_proto">>, {<<"limiter_proto">>,
{git,"https://github.com/valitydev/limiter-proto.git", {git,"https://github.com/valitydev/limiter-proto.git",
{ref,"2e2cdab859222648e389dc74867b5273e73583e9"}}, {ref,"d390910cd246f2356f10c2db410ecf93e55eff4d"}},
0}, 0},
{<<"machinery">>, {<<"machinery">>,
{git,"https://github.com/valitydev/machinery.git", {git,"https://github.com/valitydev/machinery-erlang.git",
{ref,"db7c94b9913451e9558afa19f2fe77bf48d391da"}}, {ref,"ff4cfefb616250f6905c25e79f74a7a30eb1aae5"}},
0}, 0},
{<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},2}, {<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},2},
{<<"mg_proto">>, {<<"mg_proto">>,
{git,"https://github.com/rbkmoney/machinegun_proto.git", {git,"https://github.com/valitydev/machinegun-proto.git",
{ref,"d814d6948d4ff13f6f41d12c6613f59c805750b2"}}, {ref,"b43d6fd0939ee4029ec8873dbd16f3c5fbe4a95c"}},
1}, 1},
{<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.2.0">>},2}, {<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.2.0">>},2},
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.1">>},2}, {<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.1">>},2},