berater 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,6 +16,12 @@ describe 'be_overloaded' do
16
16
  it { expect { limiter.limit }.not_to be_inhibited }
17
17
  it { expect { limiter.limit }.not_to be_overrated }
18
18
  it { expect { limiter.limit }.not_to be_incapacitated }
19
+
20
+ it 'catches false positives' do
21
+ expect {
22
+ expect { limiter }.to be_overloaded
23
+ }.to fail
24
+ end
19
25
  end
20
26
 
21
27
  context 'Berater::Inhibitor' do
@@ -29,10 +35,16 @@ describe 'be_overloaded' do
29
35
 
30
36
  it { expect { limiter.limit }.to be_overloaded }
31
37
  it { expect { limiter.limit }.to be_inhibited }
38
+
39
+ it 'catches false negatives' do
40
+ expect {
41
+ expect { limiter }.not_to be_overloaded
42
+ }.to fail
43
+ end
32
44
  end
33
45
 
34
46
  context 'Berater::RateLimiter' do
35
- let(:limiter) { Berater.new(:key, :rate, 1, :second) }
47
+ let(:limiter) { Berater.new(:key, 1, :second) }
36
48
 
37
49
  it { expect(limiter).not_to be_overloaded }
38
50
  it { expect(limiter).not_to be_inhibited }
@@ -67,7 +79,7 @@ describe 'be_overloaded' do
67
79
  end
68
80
 
69
81
  context 'Berater::ConcurrencyLimiter' do
70
- let(:limiter) { Berater.new(:key, :concurrency, 1) }
82
+ let(:limiter) { Berater.new(:key, 1) }
71
83
 
72
84
  it { expect(limiter).not_to be_overloaded }
73
85
  it { expect(limiter).not_to be_inhibited }
@@ -1,12 +1,12 @@
1
1
  describe Berater::RateLimiter do
2
- it_behaves_like 'a limiter', Berater.new(:key, :rate, 3, :second)
2
+ it_behaves_like 'a limiter', Berater.new(:key, 3, :second)
3
3
 
4
4
  describe '.new' do
5
5
  let(:limiter) { described_class.new(:key, 1, :second) }
6
6
 
7
7
  it 'initializes' do
8
8
  expect(limiter.key).to be :key
9
- expect(limiter.count).to eq 1
9
+ expect(limiter.capacity).to eq 1
10
10
  expect(limiter.interval).to eq :second
11
11
  end
12
12
 
@@ -15,82 +15,38 @@ describe Berater::RateLimiter do
15
15
  end
16
16
  end
17
17
 
18
- describe '#count' do
19
- def expect_count(count)
20
- limiter = described_class.new(:key, count, :second)
21
- expect(limiter.count).to eq count
18
+ describe '#capacity' do
19
+ def expect_capacity(capacity)
20
+ limiter = described_class.new(:key, capacity, :second)
21
+ expect(limiter.capacity).to eq capacity
22
22
  end
23
23
 
24
- it { expect_count(0) }
25
- it { expect_count(1) }
26
- it { expect_count(100) }
24
+ it { expect_capacity(0) }
25
+ it { expect_capacity(1) }
26
+ it { expect_capacity(100) }
27
27
 
28
28
  context 'with erroneous values' do
29
- def expect_bad_count(count)
29
+ def expect_bad_capacity(capacity)
30
30
  expect do
31
- described_class.new(:key, count, :second)
31
+ described_class.new(:key, capacity, :second)
32
32
  end.to raise_error ArgumentError
33
33
  end
34
34
 
35
- it { expect_bad_count(0.5) }
36
- it { expect_bad_count(-1) }
37
- it { expect_bad_count('1') }
38
- it { expect_bad_count(:one) }
35
+ it { expect_bad_capacity(0.5) }
36
+ it { expect_bad_capacity(-1) }
37
+ it { expect_bad_capacity('1') }
38
+ it { expect_bad_capacity(:one) }
39
39
  end
40
40
  end
41
41
 
42
42
  describe '#interval' do
43
- def expect_interval(interval, expected)
44
- limiter = described_class.new(:key, 1, interval)
45
- expect(limiter.interval).to eq expected
46
- end
47
-
48
- context 'with ints' do
49
- it { expect_interval(0, 0) }
50
- it { expect_interval(1, 1) }
51
- it { expect_interval(33, 33) }
52
- end
53
-
54
- context 'with symbols' do
55
- it { expect_interval(:sec, :second) }
56
- it { expect_interval(:second, :second) }
57
- it { expect_interval(:seconds, :second) }
58
-
59
- it { expect_interval(:min, :minute) }
60
- it { expect_interval(:minute, :minute) }
61
- it { expect_interval(:minutes, :minute) }
62
-
63
- it { expect_interval(:hour, :hour) }
64
- it { expect_interval(:hours, :hour) }
65
- end
66
-
67
- context 'with strings' do
68
- it { expect_interval('sec', :second) }
69
- it { expect_interval('minute', :minute) }
70
- it { expect_interval('hours', :hour) }
71
- end
72
-
73
- context 'with erroneous values' do
74
- def expect_bad_interval(interval)
75
- expect do
76
- described_class.new(:key, 1, interval)
77
- end.to raise_error(ArgumentError)
78
- end
79
-
80
- it { expect_bad_interval(-1) }
81
- it { expect_bad_interval(:secondz) }
82
- it { expect_bad_interval('huor') }
83
- end
43
+ # see spec/utils_spec.rb for more
84
44
 
85
- context 'interprets values' do
86
- def expect_sec(interval, expected)
87
- limiter = described_class.new(:key, 1, interval)
88
- expect(limiter.instance_variable_get(:@interval_sec)).to eq expected
89
- end
45
+ subject { described_class.new(:key, 1, :second) }
90
46
 
91
- it { expect_sec(:second, 1) }
92
- it { expect_sec(:minute, 60) }
93
- it { expect_sec(:hour, 3600) }
47
+ it 'saves the interval in original and microsecond format' do
48
+ expect(subject.interval).to be :second
49
+ expect(subject.instance_variable_get(:@interval_usec)).to be 10**6
94
50
  end
95
51
  end
96
52
 
@@ -112,50 +68,101 @@ describe Berater::RateLimiter do
112
68
  expect(limiter).to be_overrated
113
69
  end
114
70
 
115
- it 'limit resets over time' do
71
+ it 'limit resets over time, with millisecond precision' do
116
72
  3.times { limiter.limit }
117
73
  expect(limiter).to be_overrated
118
74
 
119
- # travel forward a second
75
+ # travel forward to just before the count decrements
76
+ Timecop.freeze(0.333)
77
+ expect(limiter).to be_overrated
78
+
79
+ # traveling one more millisecond will decrement the count
80
+ Timecop.freeze(0.001)
81
+ limiter.limit
82
+ expect(limiter).to be_overrated
83
+
84
+ # traveling 1 second will reset the count
120
85
  Timecop.freeze(1)
121
86
 
122
87
  3.times { limiter.limit }
123
88
  expect(limiter).to be_overrated
124
89
  end
125
- end
126
90
 
127
- context 'with same key, different limiters' do
128
- let(:limiter_one) { described_class.new(:key, 1, :second) }
129
- let(:limiter_two) { described_class.new(:key, 1, :second) }
91
+ it 'accepts a dynamic capacity' do
92
+ limiter = described_class.new(:key, 1, :second)
130
93
 
131
- it 'works as expected' do
132
- expect(limiter_one.limit).not_to be_overrated
94
+ expect { limiter.limit(capacity: 0) }.to be_overrated
95
+ 5.times { limiter.limit(capacity: 10) }
96
+ expect { limiter }.to be_overrated
97
+ end
98
+
99
+ context 'works with cost parameter' do
100
+ it { expect { limiter.limit(cost: 4) }.to be_overrated }
133
101
 
134
- expect(limiter_one).to be_overrated
135
- expect(limiter_two).to be_overrated
102
+ it 'works within limit' do
103
+ limiter.limit(cost: 3)
104
+ expect { limiter.limit }.to be_overrated
105
+ end
106
+
107
+ it 'resets over time' do
108
+ limiter.limit(cost: 3)
109
+ expect(limiter).to be_overrated
110
+
111
+ Timecop.freeze(1)
112
+ expect(limiter).not_to be_overrated
113
+ end
114
+
115
+ it 'can be a Float' do
116
+ 2.times { limiter.limit(cost: 1.5) }
117
+ expect(limiter).to be_overrated
118
+ end
136
119
  end
137
- end
138
120
 
139
- context 'with different keys, different limiters' do
140
- let(:limiter_one) { described_class.new(:one, 1, :second) }
141
- let(:limiter_two) { described_class.new(:two, 2, :second) }
121
+ context 'with same key, different limiters' do
122
+ let(:limiter_one) { described_class.new(:key, 1, :second) }
123
+ let(:limiter_two) { described_class.new(:key, 1, :second) }
142
124
 
143
- it 'works as expected' do
144
- expect(limiter_one.limit).not_to be_overrated
145
- expect(limiter_two.limit).not_to be_overrated
125
+ it 'works as expected' do
126
+ expect(limiter_one.limit).not_to be_overrated
146
127
 
147
- expect(limiter_one).to be_overrated
148
- expect(limiter_two.limit).not_to be_overrated
128
+ expect(limiter_one).to be_overrated
129
+ expect(limiter_two).to be_overrated
130
+ end
131
+ end
132
+
133
+ context 'with different keys, different limiters' do
134
+ let(:limiter_one) { described_class.new(:one, 1, :second) }
135
+ let(:limiter_two) { described_class.new(:two, 2, :second) }
149
136
 
150
- expect(limiter_one).to be_overrated
151
- expect(limiter_two).to be_overrated
137
+ it 'works as expected' do
138
+ expect(limiter_one.limit).not_to be_overrated
139
+ expect(limiter_two.limit).not_to be_overrated
140
+
141
+ expect(limiter_one).to be_overrated
142
+ expect(limiter_two.limit).not_to be_overrated
143
+
144
+ expect(limiter_one).to be_overrated
145
+ expect(limiter_two).to be_overrated
146
+ end
147
+ end
148
+ end
149
+
150
+ describe '#overloaded?' do
151
+ let(:limiter) { described_class.new(:key, 1, :second) }
152
+
153
+ it 'works' do
154
+ expect(limiter.overloaded?).to be false
155
+ limiter.limit
156
+ expect(limiter.overloaded?).to be true
157
+ Timecop.freeze(1)
158
+ expect(limiter.overloaded?).to be false
152
159
  end
153
160
  end
154
161
 
155
162
  describe '#to_s' do
156
- def check(count, interval, expected)
163
+ def check(capacity, interval, expected)
157
164
  expect(
158
- described_class.new(:key, count, interval).to_s
165
+ described_class.new(:key, capacity, interval).to_s
159
166
  ).to match(expected)
160
167
  end
161
168
 
@@ -171,16 +178,6 @@ describe Berater::RateLimiter do
171
178
  check(1, 'hour', /1 per hour/)
172
179
  end
173
180
 
174
- it 'normalizes' do
175
- check(1, :sec, /1 per second/)
176
- check(1, :seconds, /1 per second/)
177
-
178
- check(1, :min, /1 per minute/)
179
- check(1, :minutes, /1 per minute/)
180
-
181
- check(1, :hours, /1 per hour/)
182
- end
183
-
184
181
  it 'works with integers' do
185
182
  check(1, 1, /1 every second/)
186
183
  check(1, 2, /1 every 2 seconds/)
@@ -0,0 +1,102 @@
1
+ # Can you build a rate limiter from a concurrency limiter? Yes!
2
+
3
+ class RateRiddler
4
+ def self.limit(capacity, interval)
5
+ lock = Berater::ConcurrencyLimiter.new(:key, capacity, timeout: interval).limit
6
+ yield if block_given?
7
+ # allow lock to time out rather than be released
8
+ end
9
+ end
10
+
11
+
12
+ describe 'a ConcurrencyLimiter-derived rate limiter' do
13
+ def limit(&block)
14
+ RateRiddler.limit(1, :second, &block)
15
+ end
16
+
17
+ it 'works' do
18
+ expect(limit { 123 }).to eq 123
19
+ end
20
+
21
+ it 'respects limits' do
22
+ limit
23
+ expect { limit }.to be_overloaded
24
+ end
25
+
26
+ it 'resets over time' do
27
+ limit
28
+ expect { limit }.to be_overloaded
29
+
30
+ Timecop.freeze(1)
31
+
32
+ limit
33
+ expect { limit }.to be_overloaded
34
+ end
35
+ end
36
+
37
+
38
+ # Can you build a concurrency limiter from a rate limiter? Almost...
39
+
40
+ class ConcurrenyRiddler
41
+ def self.limit(capacity, timeout: nil)
42
+ timeout ||= 1_000 # fake infinity
43
+
44
+ limiter = Berater::RateLimiter.new(:key, capacity, timeout)
45
+ limiter.limit
46
+ yield if block_given?
47
+ ensure
48
+ # decrement counter
49
+ limiter.redis.decr(limiter.send(:cache_key, :key))
50
+ end
51
+ end
52
+
53
+
54
+ describe 'a RateLimiter-derived concurrency limiter' do
55
+ def limit(capacity = 1, timeout: nil, &block)
56
+ ConcurrenyRiddler.limit(capacity, timeout: timeout, &block)
57
+ end
58
+
59
+ it 'works' do
60
+ expect(limit { 123 }).to eq 123
61
+ end
62
+
63
+ it 'respects limits' do
64
+ limit do
65
+ # a second, simultaneous request isn't allowed
66
+ expect { limit }.to be_overloaded
67
+ end
68
+
69
+ # but now it'll work
70
+ limit
71
+ end
72
+
73
+ it 'resets over time' do
74
+ limit(timeout: 1) do
75
+ expect { limit }.to be_overloaded
76
+
77
+ # ...wait for it
78
+ Timecop.freeze(10)
79
+
80
+ limit(timeout: 1)
81
+ end
82
+ end
83
+
84
+ it "has no memory of the order, so timeouts don't work quite right" do
85
+ limit(2, timeout: 1) do
86
+ Timecop.freeze(0.5)
87
+
88
+ limit(2, timeout: 1) do
89
+ # this is where the masquerading breaks. the first lock is still
90
+ # being held and within it's timeout limit, however the RaterLimiter
91
+ # decremented the count internally since enough time has passed.
92
+ # This next call *should* fail, but doesn't.
93
+
94
+ expect {
95
+ expect { limit(2, timeout: 1) }.to be_overloaded
96
+ }.to fail
97
+
98
+ # ...close, but not quite!
99
+ end
100
+ end
101
+ end
102
+ end
@@ -1,84 +1,138 @@
1
- require 'berater/test_mode'
1
+ describe Berater::TestMode, order: :defined do
2
+ let(:reset_test_mode) { true }
2
3
 
3
- describe 'Berater.test_mode' do
4
- after { Berater.test_mode = nil }
4
+ after do
5
+ Berater.test_mode = nil if reset_test_mode
6
+ end
7
+
8
+ context 'after test_mode.rb was required, but not used' do
9
+ let(:reset_test_mode) { false }
10
+
11
+ it 'has already been loaded by "berater/rspec", unfortunately' do
12
+ expect {
13
+ expect { Berater.test_mode }.to raise_error(NoMethodError)
14
+ }.to fail
15
+ end
16
+
17
+ it 'defaults to off' do
18
+ expect(Berater.test_mode).to be nil
19
+ end
20
+
21
+ it 'did not prepend .new yet' do
22
+ expect(Berater::Limiter.singleton_class.ancestors).not_to include(described_class)
23
+ end
24
+
25
+ it 'prepends when first turned on' do
26
+ Berater.test_mode = :pass
27
+
28
+ expect(Berater::Limiter.singleton_class.ancestors).to include(described_class)
29
+ end
30
+
31
+ it 'preserves the original functionality via super' do
32
+ expect { Berater::Limiter.new }.to raise_error(NotImplementedError)
33
+ end
34
+ end
35
+
36
+ describe '.test_mode' do
37
+ it 'can be turned on' do
38
+ Berater.test_mode = :pass
39
+ expect(Berater.test_mode).to be :pass
40
+
41
+ Berater.test_mode = :fail
42
+ expect(Berater.test_mode).to be :fail
43
+ end
44
+
45
+ it 'can be turned off' do
46
+ Berater.test_mode = nil
47
+ expect(Berater.test_mode).to be nil
48
+ end
49
+
50
+ it 'validates input' do
51
+ expect { Berater.test_mode = :foo }.to raise_error(ArgumentError)
52
+ end
53
+ end
54
+
55
+ shared_examples 'it always works, without redis' do
56
+ before do
57
+ Berater.redis = nil
58
+ expect_any_instance_of(Berater::LuaScript).not_to receive(:eval)
59
+ end
60
+
61
+ it_behaves_like 'it is not overloaded'
62
+
63
+ it 'always works' do
64
+ 10.times { subject.limit }
65
+ end
66
+ end
67
+
68
+ shared_examples 'it never works, without redis' do
69
+ before do
70
+ Berater.redis = nil
71
+ expect_any_instance_of(Berater::LuaScript).not_to receive(:eval)
72
+ end
73
+
74
+ it_behaves_like 'it is overloaded'
75
+
76
+ it 'never works' do
77
+ expect { subject }.to be_overloaded
78
+ end
79
+ end
5
80
 
6
81
  describe 'Unlimiter' do
7
- let(:limiter) { Berater::Unlimiter.new }
82
+ subject { Berater::Unlimiter.new }
8
83
 
9
84
  context 'when test_mode = nil' do
10
85
  before { Berater.test_mode = nil }
11
86
 
12
- it { expect(limiter).to be_a Berater::Unlimiter }
13
-
14
- it 'works per usual' do
15
- expect {|block| limiter.limit(&block) }.to yield_control
16
- 10.times { expect(limiter.limit).to be_a Berater::Lock }
17
- end
87
+ it { is_expected.to be_a Berater::Unlimiter }
88
+ it_behaves_like 'it always works, without redis'
18
89
  end
19
90
 
20
91
  context 'when test_mode = :pass' do
21
92
  before { Berater.test_mode = :pass }
22
93
 
23
- it { expect(limiter).to be_a Berater::Unlimiter }
24
-
25
- it 'always works' do
26
- expect {|block| limiter.limit(&block) }.to yield_control
27
- 10.times { expect(limiter.limit).to be_a Berater::Lock }
28
- end
94
+ it { is_expected.to be_a Berater::Unlimiter }
95
+ it_behaves_like 'it always works, without redis'
29
96
  end
30
97
 
31
98
  context 'when test_mode = :fail' do
32
99
  before { Berater.test_mode = :fail }
33
100
 
34
- it { expect(limiter).to be_a Berater::Unlimiter }
35
-
36
- it 'never works' do
37
- expect { limiter }.to be_overloaded
38
- end
101
+ it { is_expected.to be_a Berater::Unlimiter }
102
+ it_behaves_like 'it never works, without redis'
39
103
  end
40
104
  end
41
105
 
42
106
  describe 'Inhibitor' do
43
- let(:limiter) { Berater::Inhibitor.new }
107
+ subject { Berater::Inhibitor.new }
44
108
 
45
109
  context 'when test_mode = nil' do
46
110
  before { Berater.test_mode = nil }
47
111
 
48
- it { expect(limiter).to be_a Berater::Inhibitor }
49
-
50
- it 'works per usual' do
51
- expect { limiter }.to be_overloaded
52
- end
112
+ it { is_expected.to be_a Berater::Inhibitor }
113
+ it_behaves_like 'it never works, without redis'
53
114
  end
54
115
 
55
116
  context 'when test_mode = :pass' do
56
117
  before { Berater.test_mode = :pass }
57
118
 
58
- it { expect(limiter).to be_a Berater::Inhibitor }
59
-
60
- it 'always works' do
61
- expect {|block| limiter.limit(&block) }.to yield_control
62
- 10.times { expect(limiter.limit).to be_a Berater::Lock }
63
- end
119
+ it { is_expected.to be_a Berater::Inhibitor }
120
+ it_behaves_like 'it always works, without redis'
64
121
  end
65
122
 
66
123
  context 'when test_mode = :fail' do
67
124
  before { Berater.test_mode = :fail }
68
125
 
69
- it { expect(limiter).to be_a Berater::Inhibitor }
70
-
71
- it 'never works' do
72
- expect { limiter }.to be_overloaded
73
- end
126
+ it { is_expected.to be_a Berater::Inhibitor }
127
+ it_behaves_like 'it never works, without redis'
74
128
  end
75
129
  end
76
130
 
77
131
  describe 'RateLimiter' do
78
- let(:limiter) { Berater::RateLimiter.new(:key, 1, :second) }
132
+ subject { Berater::RateLimiter.new(:key, 1, :second) }
79
133
 
80
134
  shared_examples 'a RateLimiter' do
81
- it { expect(limiter).to be_a Berater::RateLimiter }
135
+ it { is_expected.to be_a Berater::RateLimiter }
82
136
 
83
137
  it 'checks arguments' do
84
138
  expect {
@@ -91,15 +145,12 @@ describe 'Berater.test_mode' do
91
145
  before { Berater.test_mode = nil }
92
146
 
93
147
  it_behaves_like 'a RateLimiter'
148
+ it_behaves_like 'it is not overloaded'
94
149
 
95
150
  it 'works per usual' do
96
- expect(limiter.redis).to receive(:eval).twice.and_call_original
97
- expect(limiter.limit).to be_a Berater::Lock
98
- expect { limiter.limit }.to be_overloaded
99
- end
100
-
101
- it 'yields per usual' do
102
- expect {|block| limiter.limit(&block) }.to yield_control
151
+ expect(Berater::RateLimiter::LUA_SCRIPT).to receive(:eval).twice.and_call_original
152
+ expect(subject.limit).to be_a Berater::Lock
153
+ expect { subject.limit }.to be_overloaded
103
154
  end
104
155
  end
105
156
 
@@ -107,31 +158,22 @@ describe 'Berater.test_mode' do
107
158
  before { Berater.test_mode = :pass }
108
159
 
109
160
  it_behaves_like 'a RateLimiter'
110
-
111
- it 'always works and without calling redis' do
112
- expect(limiter.redis).not_to receive(:eval)
113
- expect {|block| limiter.limit(&block) }.to yield_control
114
- 10.times { expect(limiter.limit).to be_a Berater::Lock }
115
- end
161
+ it_behaves_like 'it always works, without redis'
116
162
  end
117
163
 
118
164
  context 'when test_mode = :fail' do
119
165
  before { Berater.test_mode = :fail }
120
166
 
121
167
  it_behaves_like 'a RateLimiter'
122
-
123
- it 'never works and without calling redis' do
124
- expect(limiter.redis).not_to receive(:eval)
125
- expect { limiter }.to be_overloaded
126
- end
168
+ it_behaves_like 'it never works, without redis'
127
169
  end
128
170
  end
129
171
 
130
172
  describe 'ConcurrencyLimiter' do
131
- let(:limiter) { Berater::ConcurrencyLimiter.new(:key, 1) }
173
+ subject { Berater::ConcurrencyLimiter.new(:key, 1) }
132
174
 
133
175
  shared_examples 'a ConcurrencyLimiter' do
134
- it { expect(limiter).to be_a Berater::ConcurrencyLimiter }
176
+ it { expect(subject).to be_a Berater::ConcurrencyLimiter }
135
177
 
136
178
  it 'checks arguments' do
137
179
  expect {
@@ -144,15 +186,12 @@ describe 'Berater.test_mode' do
144
186
  before { Berater.test_mode = nil }
145
187
 
146
188
  it_behaves_like 'a ConcurrencyLimiter'
189
+ it_behaves_like 'it is not overloaded'
147
190
 
148
191
  it 'works per usual' do
149
- expect(limiter.redis).to receive(:eval).twice.and_call_original
150
- expect(limiter.limit).to be_a Berater::Lock
151
- expect { limiter.limit }.to be_overloaded
152
- end
153
-
154
- it 'yields per usual' do
155
- expect {|block| limiter.limit(&block) }.to yield_control
192
+ expect(Berater::ConcurrencyLimiter::LUA_SCRIPT).to receive(:eval).twice.and_call_original
193
+ expect(subject.limit).to be_a Berater::Lock
194
+ expect { subject.limit }.to be_overloaded
156
195
  end
157
196
  end
158
197
 
@@ -160,23 +199,14 @@ describe 'Berater.test_mode' do
160
199
  before { Berater.test_mode = :pass }
161
200
 
162
201
  it_behaves_like 'a ConcurrencyLimiter'
163
-
164
- it 'always works and without calling redis' do
165
- expect(limiter.redis).not_to receive(:eval)
166
- expect {|block| limiter.limit(&block) }.to yield_control
167
- 10.times { expect(limiter.limit).to be_a Berater::Lock }
168
- end
202
+ it_behaves_like 'it always works, without redis'
169
203
  end
170
204
 
171
205
  context 'when test_mode = :fail' do
172
206
  before { Berater.test_mode = :fail }
173
207
 
174
208
  it_behaves_like 'a ConcurrencyLimiter'
175
-
176
- it 'never works and without calling redis' do
177
- expect(limiter.redis).not_to receive(:eval)
178
- expect { limiter }.to be_overloaded
179
- end
209
+ it_behaves_like 'it never works, without redis'
180
210
  end
181
211
  end
182
212