berater 0.5.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/berater.rb +10 -7
- data/lib/berater/concurrency_limiter.rb +18 -27
- data/lib/berater/dsl.rb +8 -8
- data/lib/berater/inhibitor.rb +2 -9
- data/lib/berater/limiter.rb +44 -20
- data/lib/berater/lock.rb +3 -4
- data/lib/berater/rate_limiter.rb +43 -40
- data/lib/berater/rspec.rb +2 -2
- data/lib/berater/rspec/matchers.rb +37 -38
- data/lib/berater/test_mode.rb +13 -29
- data/lib/berater/unlimiter.rb +6 -4
- data/lib/berater/utils.rb +4 -4
- data/lib/berater/version.rb +1 -1
- data/spec/berater_spec.rb +9 -9
- data/spec/concurrency_limiter_spec.rb +82 -55
- data/spec/dsl_refinement_spec.rb +0 -12
- data/spec/dsl_spec.rb +5 -17
- data/spec/limiter_spec.rb +39 -3
- data/spec/matchers_spec.rb +64 -72
- data/spec/rate_limiter_spec.rb +134 -44
- data/spec/riddle_spec.rb +6 -2
- data/spec/test_mode_spec.rb +40 -111
- data/spec/utils_spec.rb +30 -30
- metadata +2 -2
data/spec/riddle_spec.rb
CHANGED
@@ -42,11 +42,15 @@ class ConcurrenyRiddler
|
|
42
42
|
timeout ||= 1_000 # fake infinity
|
43
43
|
|
44
44
|
limiter = Berater::RateLimiter.new(:key, capacity, timeout)
|
45
|
-
limiter.limit
|
45
|
+
lock = limiter.limit
|
46
46
|
yield if block_given?
|
47
47
|
ensure
|
48
48
|
# decrement counter
|
49
|
-
|
49
|
+
if lock
|
50
|
+
key = limiter.send(:cache_key, :key)
|
51
|
+
count, ts = limiter.redis.get(key).split ';'
|
52
|
+
limiter.redis.set(key, "#{count.to_f - 1};#{ts}")
|
53
|
+
end
|
50
54
|
end
|
51
55
|
end
|
52
56
|
|
data/spec/test_mode_spec.rb
CHANGED
@@ -1,35 +1,24 @@
|
|
1
|
-
describe Berater::TestMode
|
2
|
-
let(:reset_test_mode) { true }
|
3
|
-
|
1
|
+
describe Berater::TestMode do
|
4
2
|
after do
|
5
|
-
Berater.test_mode = nil
|
3
|
+
Berater.test_mode = nil
|
6
4
|
end
|
7
5
|
|
8
|
-
context 'after test_mode.rb
|
9
|
-
|
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
|
6
|
+
context 'after test_mode.rb has been loaded' do
|
7
|
+
it 'monkey patches Berater' do
|
8
|
+
expect(Berater).to respond_to(:test_mode)
|
15
9
|
end
|
16
10
|
|
17
11
|
it 'defaults to off' do
|
18
12
|
expect(Berater.test_mode).to be nil
|
19
13
|
end
|
20
14
|
|
21
|
-
it '
|
22
|
-
expect(Berater::
|
23
|
-
|
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)
|
15
|
+
it 'prepends Limiter subclasses' do
|
16
|
+
expect(Berater::Unlimiter.ancestors).to include(described_class)
|
17
|
+
expect(Berater::Inhibitor.ancestors).to include(described_class)
|
29
18
|
end
|
30
19
|
|
31
20
|
it 'preserves the original functionality via super' do
|
32
|
-
expect { Berater::Limiter.new }.to raise_error(
|
21
|
+
expect { Berater::Limiter.new }.to raise_error(NoMethodError)
|
33
22
|
end
|
34
23
|
end
|
35
24
|
|
@@ -50,31 +39,43 @@ describe Berater::TestMode, order: :defined do
|
|
50
39
|
it 'validates input' do
|
51
40
|
expect { Berater.test_mode = :foo }.to raise_error(ArgumentError)
|
52
41
|
end
|
53
|
-
end
|
54
42
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
expect_any_instance_of(Berater::LuaScript).not_to receive(:eval)
|
59
|
-
end
|
43
|
+
it 'works no matter when limiter was created' do
|
44
|
+
limiter = Berater::Unlimiter.new
|
45
|
+
expect(limiter).not_to be_overloaded
|
60
46
|
|
61
|
-
|
47
|
+
Berater.test_mode = :fail
|
48
|
+
expect(limiter).to be_overloaded
|
49
|
+
end
|
62
50
|
|
63
|
-
it '
|
64
|
-
|
51
|
+
it 'supports a generic expectation' do
|
52
|
+
Berater.test_mode = :pass
|
53
|
+
expect_any_instance_of(Berater::Limiter).to receive(:limit)
|
54
|
+
Berater::Unlimiter.new.limit
|
65
55
|
end
|
66
56
|
end
|
67
57
|
|
68
|
-
shared_examples 'it
|
58
|
+
shared_examples 'it supports test_mode' do
|
69
59
|
before do
|
60
|
+
# without hitting Redis
|
70
61
|
Berater.redis = nil
|
71
62
|
expect_any_instance_of(Berater::LuaScript).not_to receive(:eval)
|
72
63
|
end
|
73
64
|
|
74
|
-
|
65
|
+
context 'with test_mode = :pass' do
|
66
|
+
before { Berater.test_mode = :pass }
|
67
|
+
|
68
|
+
it_behaves_like 'it is not overloaded'
|
69
|
+
|
70
|
+
it 'always works' do
|
71
|
+
10.times { subject.limit }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'with test_mode = :fail' do
|
76
|
+
before { Berater.test_mode = :fail }
|
75
77
|
|
76
|
-
|
77
|
-
expect { subject }.to be_overloaded
|
78
|
+
it_behaves_like 'it is overloaded'
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
@@ -84,23 +85,10 @@ describe Berater::TestMode, order: :defined do
|
|
84
85
|
context 'when test_mode = nil' do
|
85
86
|
before { Berater.test_mode = nil }
|
86
87
|
|
87
|
-
it
|
88
|
-
it_behaves_like 'it always works, without redis'
|
89
|
-
end
|
90
|
-
|
91
|
-
context 'when test_mode = :pass' do
|
92
|
-
before { Berater.test_mode = :pass }
|
93
|
-
|
94
|
-
it { is_expected.to be_a Berater::Unlimiter }
|
95
|
-
it_behaves_like 'it always works, without redis'
|
88
|
+
it_behaves_like 'it is not overloaded'
|
96
89
|
end
|
97
90
|
|
98
|
-
|
99
|
-
before { Berater.test_mode = :fail }
|
100
|
-
|
101
|
-
it { is_expected.to be_a Berater::Unlimiter }
|
102
|
-
it_behaves_like 'it never works, without redis'
|
103
|
-
end
|
91
|
+
it_behaves_like 'it supports test_mode'
|
104
92
|
end
|
105
93
|
|
106
94
|
describe 'Inhibitor' do
|
@@ -109,42 +97,18 @@ describe Berater::TestMode, order: :defined do
|
|
109
97
|
context 'when test_mode = nil' do
|
110
98
|
before { Berater.test_mode = nil }
|
111
99
|
|
112
|
-
it
|
113
|
-
it_behaves_like 'it never works, without redis'
|
100
|
+
it_behaves_like 'it is overloaded'
|
114
101
|
end
|
115
102
|
|
116
|
-
|
117
|
-
before { Berater.test_mode = :pass }
|
118
|
-
|
119
|
-
it { is_expected.to be_a Berater::Inhibitor }
|
120
|
-
it_behaves_like 'it always works, without redis'
|
121
|
-
end
|
122
|
-
|
123
|
-
context 'when test_mode = :fail' do
|
124
|
-
before { Berater.test_mode = :fail }
|
125
|
-
|
126
|
-
it { is_expected.to be_a Berater::Inhibitor }
|
127
|
-
it_behaves_like 'it never works, without redis'
|
128
|
-
end
|
103
|
+
it_behaves_like 'it supports test_mode'
|
129
104
|
end
|
130
105
|
|
131
106
|
describe 'RateLimiter' do
|
132
107
|
subject { Berater::RateLimiter.new(:key, 1, :second) }
|
133
108
|
|
134
|
-
shared_examples 'a RateLimiter' do
|
135
|
-
it { is_expected.to be_a Berater::RateLimiter }
|
136
|
-
|
137
|
-
it 'checks arguments' do
|
138
|
-
expect {
|
139
|
-
Berater::RateLimiter.new(:key, 1)
|
140
|
-
}.to raise_error(ArgumentError)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
109
|
context 'when test_mode = nil' do
|
145
110
|
before { Berater.test_mode = nil }
|
146
111
|
|
147
|
-
it_behaves_like 'a RateLimiter'
|
148
112
|
it_behaves_like 'it is not overloaded'
|
149
113
|
|
150
114
|
it 'works per usual' do
|
@@ -154,38 +118,15 @@ describe Berater::TestMode, order: :defined do
|
|
154
118
|
end
|
155
119
|
end
|
156
120
|
|
157
|
-
|
158
|
-
before { Berater.test_mode = :pass }
|
159
|
-
|
160
|
-
it_behaves_like 'a RateLimiter'
|
161
|
-
it_behaves_like 'it always works, without redis'
|
162
|
-
end
|
163
|
-
|
164
|
-
context 'when test_mode = :fail' do
|
165
|
-
before { Berater.test_mode = :fail }
|
166
|
-
|
167
|
-
it_behaves_like 'a RateLimiter'
|
168
|
-
it_behaves_like 'it never works, without redis'
|
169
|
-
end
|
121
|
+
it_behaves_like 'it supports test_mode'
|
170
122
|
end
|
171
123
|
|
172
124
|
describe 'ConcurrencyLimiter' do
|
173
125
|
subject { Berater::ConcurrencyLimiter.new(:key, 1) }
|
174
126
|
|
175
|
-
shared_examples 'a ConcurrencyLimiter' do
|
176
|
-
it { expect(subject).to be_a Berater::ConcurrencyLimiter }
|
177
|
-
|
178
|
-
it 'checks arguments' do
|
179
|
-
expect {
|
180
|
-
Berater::ConcurrencyLimiter.new(:key, 1.0)
|
181
|
-
}.to raise_error(ArgumentError)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
127
|
context 'when test_mode = nil' do
|
186
128
|
before { Berater.test_mode = nil }
|
187
129
|
|
188
|
-
it_behaves_like 'a ConcurrencyLimiter'
|
189
130
|
it_behaves_like 'it is not overloaded'
|
190
131
|
|
191
132
|
it 'works per usual' do
|
@@ -195,19 +136,7 @@ describe Berater::TestMode, order: :defined do
|
|
195
136
|
end
|
196
137
|
end
|
197
138
|
|
198
|
-
|
199
|
-
before { Berater.test_mode = :pass }
|
200
|
-
|
201
|
-
it_behaves_like 'a ConcurrencyLimiter'
|
202
|
-
it_behaves_like 'it always works, without redis'
|
203
|
-
end
|
204
|
-
|
205
|
-
context 'when test_mode = :fail' do
|
206
|
-
before { Berater.test_mode = :fail }
|
207
|
-
|
208
|
-
it_behaves_like 'a ConcurrencyLimiter'
|
209
|
-
it_behaves_like 'it never works, without redis'
|
210
|
-
end
|
139
|
+
it_behaves_like 'it supports test_mode'
|
211
140
|
end
|
212
141
|
|
213
142
|
end
|
data/spec/utils_spec.rb
CHANGED
@@ -1,63 +1,63 @@
|
|
1
1
|
describe Berater::Utils do
|
2
2
|
using Berater::Utils
|
3
3
|
|
4
|
-
describe '.
|
4
|
+
describe '.to_msec' do
|
5
5
|
def f(val)
|
6
|
-
(val * 10**
|
6
|
+
(val * 10**3).to_i
|
7
7
|
end
|
8
8
|
|
9
9
|
it 'works with integers' do
|
10
|
-
expect(0.
|
11
|
-
expect(3.
|
10
|
+
expect(0.to_msec).to be f(0)
|
11
|
+
expect(3.to_msec).to be f(3)
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'works with floats' do
|
15
|
-
expect(0.1.
|
16
|
-
expect(3.0.
|
15
|
+
expect(0.1.to_msec).to be f(0.1)
|
16
|
+
expect(3.0.to_msec).to be f(3)
|
17
17
|
end
|
18
18
|
|
19
|
-
it '
|
20
|
-
expect(0.123456.
|
21
|
-
expect(123456.654321.
|
19
|
+
it 'truncates excessive precision' do
|
20
|
+
expect(0.123456.to_msec).to be 123
|
21
|
+
expect(123456.654321.to_msec).to be 123456654
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'works with symbols that are keywords' do
|
25
|
-
expect(:sec.
|
26
|
-
expect(:second.
|
27
|
-
expect(:seconds.
|
25
|
+
expect(:sec.to_msec).to be f(1)
|
26
|
+
expect(:second.to_msec).to be f(1)
|
27
|
+
expect(:seconds.to_msec).to be f(1)
|
28
28
|
|
29
|
-
expect(:min.
|
30
|
-
expect(:minute.
|
31
|
-
expect(:minutes.
|
29
|
+
expect(:min.to_msec).to be f(60)
|
30
|
+
expect(:minute.to_msec).to be f(60)
|
31
|
+
expect(:minutes.to_msec).to be f(60)
|
32
32
|
|
33
|
-
expect(:hour.
|
34
|
-
expect(:hours.
|
33
|
+
expect(:hour.to_msec).to be f(60 * 60)
|
34
|
+
expect(:hours.to_msec).to be f(60 * 60)
|
35
35
|
end
|
36
36
|
|
37
37
|
it 'works with strings that are keywords' do
|
38
|
-
expect('sec'.
|
39
|
-
expect('second'.
|
40
|
-
expect('seconds'.
|
38
|
+
expect('sec'.to_msec).to be f(1)
|
39
|
+
expect('second'.to_msec).to be f(1)
|
40
|
+
expect('seconds'.to_msec).to be f(1)
|
41
41
|
|
42
|
-
expect('min'.
|
43
|
-
expect('minute'.
|
44
|
-
expect('minutes'.
|
42
|
+
expect('min'.to_msec).to be f(60)
|
43
|
+
expect('minute'.to_msec).to be f(60)
|
44
|
+
expect('minutes'.to_msec).to be f(60)
|
45
45
|
|
46
|
-
expect('hour'.
|
47
|
-
expect('hours'.
|
46
|
+
expect('hour'.to_msec).to be f(60 * 60)
|
47
|
+
expect('hours'.to_msec).to be f(60 * 60)
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'works with strings that are numeric' do
|
51
|
-
expect('0'.
|
52
|
-
expect('3'.
|
51
|
+
expect('0'.to_msec).to be f(0)
|
52
|
+
expect('3'.to_msec).to be f(3)
|
53
53
|
|
54
|
-
expect('0.1'.
|
55
|
-
expect('3.0'.
|
54
|
+
expect('0.1'.to_msec).to be f(0.1)
|
55
|
+
expect('3.0'.to_msec).to be f(3)
|
56
56
|
end
|
57
57
|
|
58
58
|
context 'with erroneous values' do
|
59
59
|
def e(val)
|
60
|
-
expect { val.
|
60
|
+
expect { val.to_msec }.to raise_error(ArgumentError)
|
61
61
|
end
|
62
62
|
|
63
63
|
it 'rejects negative numbers' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: berater
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Pepper
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|