Skip to content

Commit

Permalink
chore: Fix test builds with meck incompatibilities. (#135)
Browse files Browse the repository at this point in the history
Works around: eproxus/meck#248
  • Loading branch information
kinyoklion authored Oct 21, 2024
1 parent 259ea60 commit f487151
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 18 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ doc:

tests:
docker run --name ld-test-redis -p 6379:6379 -d redis
@$(REBAR3) ct --dir="test,test-redis" --logdir logs/ct --cover
@$(REBAR3) ct --dir="test,test-redis" --logdir logs/ct
docker rm --force ld-test-redis

#This is used in running releaser. In this environment we do not want to run the redis tests.
Expand Down
29 changes: 18 additions & 11 deletions src/ldclient_backoff.erl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
-module(ldclient_backoff).

%% API
-export([init/4, fail/1, succeed/1, fire/1]).
-export([init/4, init/5, fail/1, succeed/1, fire/1]).

%% Types

Expand All @@ -19,7 +19,8 @@
active_since => integer() | undefined,
destination => pid(),
value => term(),
max_exp => float()
max_exp => float(),
uniform => fun(() -> float())
}.

-define(JITTER_RATIO, 0.5).
Expand All @@ -36,6 +37,11 @@

-spec init(Initial :: non_neg_integer(), Max :: non_neg_integer(), Destination :: pid(), Value :: term()) -> backoff().
init(Initial, Max, Destination, Value) ->
init(Initial, Max, Destination, Value, fun() -> rand:uniform() end).

%% This version of the function exists for testing and allows injecting the random number source.
-spec init(Initial :: non_neg_integer(), Max :: non_neg_integer(), Destination :: pid(), Value :: term(), Uniform :: fun(() -> float())) -> backoff().
init(Initial, Max, Destination, Value, Uniform) ->
SafeInitial = lists:max([Initial, 1]),
#{
initial => SafeInitial, %% Do not allow initial delay to be 0 or negative.
Expand All @@ -47,10 +53,12 @@ init(Initial, Max, Destination, Value) ->
value => Value,
%% The exponent at which the backoff delay will exceed the maximum.
%% Beyond this limit the backoff can be set to the max.
max_exp => math:ceil(math:log2(Max/SafeInitial))
max_exp => math:ceil(math:log2(Max/SafeInitial)),
%% For reasonable values this should ensure we never overflow.
%% Note that while integers can be arbitrarily large the math library uses C functions
%% that are implemented with floats.
%% Allow for alternate random number source.
uniform => Uniform
}.

%% @doc Get an updated backoff with updated delay. Does not start a timer automatically.
Expand Down Expand Up @@ -98,17 +106,16 @@ update_backoff(#{attempt := Attempt} = Backoff, _ActiveDuration) ->
Backoff#{current => delay(NewAttempt, Backoff), attempt => NewAttempt, active_since => undefined}.

-spec delay(Attempt :: non_neg_integer(), Backoff :: backoff()) -> non_neg_integer().
delay(Attempt, #{initial := Initial, max := Max, max_exp := MaxExp} = _Backoff)
delay(Attempt, #{initial := Initial, max := Max, max_exp := MaxExp, uniform := Uniform} = _Backoff)
when Attempt - 1 < MaxExp ->
jitter(min(backoff(Initial, Attempt), Max));
delay(_Attempt, #{max := Max} = _Backoff) ->
jitter(Max).
jitter(min(backoff(Initial, Attempt), Max), Uniform);
delay(_Attempt, #{max := Max, uniform := Uniform} = _Backoff) ->
jitter(Max, Uniform).

-spec backoff(Initial :: non_neg_integer(), Attempt :: non_neg_integer()) -> non_neg_integer().
backoff(Initial, Attempt) ->
trunc(Initial * (math:pow(2, Attempt - 1))).

-spec jitter(Value :: non_neg_integer()) -> non_neg_integer().
jitter(Value) ->
trunc(Value - (rand:uniform() * ?JITTER_RATIO * Value)).

-spec jitter(Value :: non_neg_integer(), Uniform :: fun(() -> float())) -> non_neg_integer().
jitter(Value, Uniform) ->
trunc(Value - (Uniform() * ?JITTER_RATIO * Value)).
10 changes: 4 additions & 6 deletions test/ldclient_backoff_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ end_per_testcase(_, _Config) ->
%%====================================================================

backoff_client(InitialDelay, Ratio) ->
meck:new(rand, [unstick]),
meck:expect(rand, uniform, fun() -> Ratio end),
ldclient_backoff:init(InitialDelay, 30000, 0, listen).
ldclient_backoff:init(InitialDelay, 30000, 0, listen, fun() -> Ratio end).

backoff_client(InitialDelay) ->
backoff_client(InitialDelay, 0).
Expand Down Expand Up @@ -100,7 +98,7 @@ delay_doubles_consecutive_failures(_) ->
#{current := 16000} = FifthUpdate,
SixthUpdate = ldclient_backoff:fail(FifthUpdate),
#{current := 30000} = SixthUpdate.


backoff_respects_max(_) ->
Backoff =
Expand Down Expand Up @@ -166,15 +164,15 @@ handles_initial_greater_than_max(_) ->
30000 = ldclient_backoff:delay(1, Backoff),
30000 = ldclient_backoff:delay(2, Backoff).

handles_bad_initial_retry(_) ->
handles_bad_initial_retry(_) ->
Backoff = backoff_client(0),
1 = ldclient_backoff:delay(1, Backoff),
2 = ldclient_backoff:delay(2, Backoff),
4 = ldclient_backoff:delay(3, Backoff),
16384 = ldclient_backoff:delay(15, Backoff),
30000 = ldclient_backoff:delay(16, Backoff),
%% Second backoff we do not use backoff_client as meck is already setup.
Backoff2 = ldclient_backoff:init(-100, 30000, 0, listen),
Backoff2 = backoff_client(-100),
1 = ldclient_backoff:delay(1, Backoff2),
2 = ldclient_backoff:delay(2, Backoff2),
4 = ldclient_backoff:delay(3, Backoff2),
Expand Down

0 comments on commit f487151

Please sign in to comment.