1defmodule DBConnection.BackoffTest do 2 use ExUnit.Case, async: true 3 4 alias DBConnection.Backoff 5 6 @moduletag backoff_min: 1_000 7 @moduletag backoff_max: 30_000 8 9 @tag backoff_type: :exp 10 test "exponential backoffs aways in [min, max]", context do 11 backoff = new(context) 12 {delays, _} = backoff(backoff, 20) 13 assert Enum.all?(delays, fn(delay) -> 14 delay >= context[:backoff_min] and delay <= context[:backoff_max] 15 end) 16 end 17 18 @tag backoff_type: :exp 19 test "exponential backoffs double until max", context do 20 backoff = new(context) 21 {delays, _} = backoff(backoff, 20) 22 Enum.reduce(delays, fn(next, prev) -> 23 assert div(next, 2) == prev or next == context[:backoff_max] 24 next 25 end) 26 end 27 28 @tag backoff_type: :exp 29 test "exponential backoffs reset to min", context do 30 backoff = new(context) 31 {[delay | _], backoff} = backoff(backoff, 20) 32 assert delay == context[:backoff_min] 33 34 backoff = Backoff.reset(backoff) 35 {[delay], _} = backoff(backoff, 1) 36 assert delay == context[:backoff_min] 37 end 38 39 @tag backoff_type: :rand 40 test "random backoffs aways in [min, max]", context do 41 backoff = new(context) 42 {delays, _} = backoff(backoff, 20) 43 assert Enum.all?(delays, fn(delay) -> 44 delay >= context[:backoff_min] and delay <= context[:backoff_max] 45 end) 46 end 47 48 @tag backoff_type: :rand 49 test "random backoffs are not all the same value", context do 50 backoff = new(context) 51 {delays, _} = backoff(backoff, 20) 52 ## If the stars align this test could fail ;) 53 refute Enum.all?(delays, &(hd(delays) == &1)) 54 end 55 56 @tag backoff_type: :rand 57 test "random backoffs repeat", context do 58 backoff = new(context) 59 assert backoff(backoff, 20) == backoff(backoff, 20) 60 end 61 62 @tag backoff_type: :rand_exp 63 test "random exponential backoffs aways in [min, max]", context do 64 backoff = new(context) 65 {delays, _} = backoff(backoff, 20) 66 assert Enum.all?(delays, fn(delay) -> 67 delay >= context[:backoff_min] and delay <= context[:backoff_max] 68 end) 69 end 70 71 @tag backoff_type: :rand_exp 72 test "random exponential backoffs increase until a third of max", context do 73 backoff = new(context) 74 {delays, _} = backoff(backoff, 20) 75 Enum.reduce(delays, fn(next, prev) -> 76 assert next >= prev or (next >= div(context[:backoff_max], 3)) 77 next 78 end) 79 end 80 81 @tag backoff_type: :rand_exp 82 test "random exponential backoffs repeat", context do 83 backoff = new(context) 84 assert backoff(backoff, 20) == backoff(backoff, 20) 85 end 86 87 @tag backoff_type: :rand_exp 88 test "random exponential backoffs reset in [min, min * 3]", context do 89 backoff = new(context) 90 {[delay | _], backoff} = backoff(backoff, 20) 91 assert delay in context[:backoff_min]..(context[:backoff_min]*3) 92 93 backoff = Backoff.reset(backoff) 94 {[delay], _} = backoff(backoff, 1) 95 assert delay in context[:backoff_min]..(context[:backoff_min]*3) 96 end 97 98 ## Helpers 99 100 def new(context) do 101 Backoff.new(Enum.into(context, [])) 102 end 103 104 defp backoff(backoff, n) do 105 Enum.map_reduce(1..n, backoff, fn(_, acc) -> Backoff.backoff(acc) end) 106 end 107end 108