berater 0.4.0 → 0.7.0
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 +29 -37
- data/lib/berater/concurrency_limiter.rb +53 -48
- data/lib/berater/dsl.rb +21 -10
- data/lib/berater/inhibitor.rb +3 -5
- data/lib/berater/limiter.rb +74 -4
- data/lib/berater/lock.rb +4 -14
- data/lib/berater/lua_script.rb +55 -0
- data/lib/berater/rate_limiter.rb +62 -90
- data/lib/berater/rspec.rb +3 -1
- data/lib/berater/rspec/matchers.rb +43 -42
- data/lib/berater/test_mode.rb +14 -21
- data/lib/berater/unlimiter.rb +8 -12
- data/lib/berater/utils.rb +46 -0
- data/lib/berater/version.rb +1 -1
- data/spec/berater_spec.rb +35 -72
- data/spec/concurrency_limiter_spec.rb +168 -66
- data/spec/dsl_refinement_spec.rb +34 -0
- data/spec/dsl_spec.rb +60 -0
- data/spec/inhibitor_spec.rb +2 -4
- data/spec/limiter_spec.rb +107 -0
- data/spec/lua_script_spec.rb +97 -0
- data/spec/matchers_spec.rb +64 -60
- data/spec/rate_limiter_spec.rb +183 -96
- data/spec/riddle_spec.rb +106 -0
- data/spec/test_mode_spec.rb +83 -124
- data/spec/unlimiter_spec.rb +3 -9
- data/spec/utils_spec.rb +78 -0
- metadata +31 -3
data/spec/test_mode_spec.rb
CHANGED
@@ -1,183 +1,142 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
describe 'Unlimiter' do
|
7
|
-
let(:limiter) { Berater::Unlimiter.new }
|
1
|
+
describe Berater::TestMode do
|
2
|
+
after do
|
3
|
+
Berater.test_mode = nil
|
4
|
+
end
|
8
5
|
|
9
|
-
|
10
|
-
|
6
|
+
context 'after test_mode.rb has been loaded' do
|
7
|
+
it 'monkey patches Berater' do
|
8
|
+
expect(Berater).to respond_to(:test_mode)
|
9
|
+
end
|
11
10
|
|
12
|
-
|
11
|
+
it 'defaults to off' do
|
12
|
+
expect(Berater.test_mode).to be nil
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
15
|
+
it 'prepends Limiter subclasses' do
|
16
|
+
expect(Berater::Unlimiter.ancestors).to include(described_class)
|
17
|
+
expect(Berater::Inhibitor.ancestors).to include(described_class)
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
it 'preserves the original functionality via super' do
|
21
|
+
expect { Berater::Limiter.new }.to raise_error(NoMethodError)
|
22
|
+
end
|
23
|
+
end
|
22
24
|
|
23
|
-
|
25
|
+
describe '.test_mode' do
|
26
|
+
it 'can be turned on' do
|
27
|
+
Berater.test_mode = :pass
|
28
|
+
expect(Berater.test_mode).to be :pass
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
10.times { expect(limiter.limit).to be_a Berater::Lock }
|
28
|
-
end
|
30
|
+
Berater.test_mode = :fail
|
31
|
+
expect(Berater.test_mode).to be :fail
|
29
32
|
end
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
34
|
+
it 'can be turned off' do
|
35
|
+
Berater.test_mode = nil
|
36
|
+
expect(Berater.test_mode).to be nil
|
37
|
+
end
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
end
|
39
|
+
it 'validates input' do
|
40
|
+
expect { Berater.test_mode = :foo }.to raise_error(ArgumentError)
|
39
41
|
end
|
40
|
-
end
|
41
42
|
|
42
|
-
|
43
|
-
|
43
|
+
it 'works no matter when limiter was created' do
|
44
|
+
limiter = Berater::Unlimiter.new
|
45
|
+
expect(limiter).not_to be_overloaded
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
+
Berater.test_mode = :fail
|
48
|
+
expect(limiter).to be_overloaded
|
49
|
+
end
|
47
50
|
|
48
|
-
|
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
|
55
|
+
end
|
56
|
+
end
|
49
57
|
|
50
|
-
|
51
|
-
|
52
|
-
|
58
|
+
shared_examples 'it supports test_mode' do
|
59
|
+
before do
|
60
|
+
# without hitting Redis
|
61
|
+
Berater.redis = nil
|
62
|
+
expect_any_instance_of(Berater::LuaScript).not_to receive(:eval)
|
53
63
|
end
|
54
64
|
|
55
|
-
context '
|
65
|
+
context 'with test_mode = :pass' do
|
56
66
|
before { Berater.test_mode = :pass }
|
57
67
|
|
58
|
-
it
|
68
|
+
it_behaves_like 'it is not overloaded'
|
59
69
|
|
60
70
|
it 'always works' do
|
61
|
-
|
62
|
-
10.times { expect(limiter.limit).to be_a Berater::Lock }
|
71
|
+
10.times { subject.limit }
|
63
72
|
end
|
64
73
|
end
|
65
74
|
|
66
|
-
context '
|
75
|
+
context 'with test_mode = :fail' do
|
67
76
|
before { Berater.test_mode = :fail }
|
68
77
|
|
69
|
-
it
|
70
|
-
|
71
|
-
it 'never works' do
|
72
|
-
expect { limiter }.to be_overloaded
|
73
|
-
end
|
78
|
+
it_behaves_like 'it is overloaded'
|
74
79
|
end
|
75
80
|
end
|
76
81
|
|
77
|
-
describe '
|
78
|
-
|
79
|
-
|
80
|
-
shared_examples 'a RateLimiter' do
|
81
|
-
it { expect(limiter).to be_a Berater::RateLimiter }
|
82
|
-
|
83
|
-
it 'checks arguments' do
|
84
|
-
expect {
|
85
|
-
Berater::RateLimiter.new(:key, 1)
|
86
|
-
}.to raise_error(ArgumentError)
|
87
|
-
end
|
88
|
-
end
|
82
|
+
describe 'Unlimiter' do
|
83
|
+
subject { Berater::Unlimiter.new }
|
89
84
|
|
90
85
|
context 'when test_mode = nil' do
|
91
86
|
before { Berater.test_mode = nil }
|
92
87
|
|
93
|
-
it_behaves_like '
|
94
|
-
|
95
|
-
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
|
103
|
-
end
|
88
|
+
it_behaves_like 'it is not overloaded'
|
104
89
|
end
|
105
90
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
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
|
116
|
-
end
|
91
|
+
it_behaves_like 'it supports test_mode'
|
92
|
+
end
|
117
93
|
|
118
|
-
|
119
|
-
|
94
|
+
describe 'Inhibitor' do
|
95
|
+
subject { Berater::Inhibitor.new }
|
120
96
|
|
121
|
-
|
97
|
+
context 'when test_mode = nil' do
|
98
|
+
before { Berater.test_mode = nil }
|
122
99
|
|
123
|
-
|
124
|
-
expect(limiter.redis).not_to receive(:eval)
|
125
|
-
expect { limiter }.to be_overloaded
|
126
|
-
end
|
100
|
+
it_behaves_like 'it is overloaded'
|
127
101
|
end
|
128
|
-
end
|
129
|
-
|
130
|
-
describe 'ConcurrencyLimiter' do
|
131
|
-
let(:limiter) { Berater::ConcurrencyLimiter.new(:key, 1) }
|
132
102
|
|
133
|
-
|
134
|
-
|
103
|
+
it_behaves_like 'it supports test_mode'
|
104
|
+
end
|
135
105
|
|
136
|
-
|
137
|
-
|
138
|
-
Berater::ConcurrencyLimiter.new(:key, 1.0)
|
139
|
-
}.to raise_error(ArgumentError)
|
140
|
-
end
|
141
|
-
end
|
106
|
+
describe 'RateLimiter' do
|
107
|
+
subject { Berater::RateLimiter.new(:key, 1, :second) }
|
142
108
|
|
143
109
|
context 'when test_mode = nil' do
|
144
110
|
before { Berater.test_mode = nil }
|
145
111
|
|
146
|
-
it_behaves_like '
|
112
|
+
it_behaves_like 'it is not overloaded'
|
147
113
|
|
148
114
|
it 'works per usual' do
|
149
|
-
expect(
|
150
|
-
expect(
|
151
|
-
expect {
|
152
|
-
end
|
153
|
-
|
154
|
-
it 'yields per usual' do
|
155
|
-
expect {|block| limiter.limit(&block) }.to yield_control
|
115
|
+
expect(Berater::RateLimiter::LUA_SCRIPT).to receive(:eval).twice.and_call_original
|
116
|
+
expect(subject.limit).to be_a Berater::Lock
|
117
|
+
expect { subject.limit }.to be_overloaded
|
156
118
|
end
|
157
119
|
end
|
158
120
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
it_behaves_like 'a ConcurrencyLimiter'
|
121
|
+
it_behaves_like 'it supports test_mode'
|
122
|
+
end
|
163
123
|
|
164
|
-
|
165
|
-
|
166
|
-
expect {|block| limiter.limit(&block) }.to yield_control
|
167
|
-
10.times { expect(limiter.limit).to be_a Berater::Lock }
|
168
|
-
end
|
169
|
-
end
|
124
|
+
describe 'ConcurrencyLimiter' do
|
125
|
+
subject { Berater::ConcurrencyLimiter.new(:key, 1) }
|
170
126
|
|
171
|
-
context 'when test_mode =
|
172
|
-
before { Berater.test_mode =
|
127
|
+
context 'when test_mode = nil' do
|
128
|
+
before { Berater.test_mode = nil }
|
173
129
|
|
174
|
-
it_behaves_like '
|
130
|
+
it_behaves_like 'it is not overloaded'
|
175
131
|
|
176
|
-
it '
|
177
|
-
expect(
|
178
|
-
expect
|
132
|
+
it 'works per usual' do
|
133
|
+
expect(Berater::ConcurrencyLimiter::LUA_SCRIPT).to receive(:eval).twice.and_call_original
|
134
|
+
expect(subject.limit).to be_a Berater::Lock
|
135
|
+
expect { subject.limit }.to be_overloaded
|
179
136
|
end
|
180
137
|
end
|
138
|
+
|
139
|
+
it_behaves_like 'it supports test_mode'
|
181
140
|
end
|
182
141
|
|
183
142
|
end
|
data/spec/unlimiter_spec.rb
CHANGED
@@ -17,19 +17,13 @@ describe Berater::Unlimiter do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
describe '#limit' do
|
20
|
-
|
20
|
+
subject { described_class.new }
|
21
21
|
|
22
|
-
it '
|
23
|
-
expect {|b| limiter.limit(&b) }.to yield_control
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'works without a block' do
|
27
|
-
expect(limiter.limit).to be_a Berater::Lock
|
28
|
-
end
|
22
|
+
it_behaves_like 'it is not overloaded'
|
29
23
|
|
30
24
|
it 'is never overloaded' do
|
31
25
|
10.times do
|
32
|
-
expect {
|
26
|
+
expect { subject.limit }.not_to be_overloaded
|
33
27
|
end
|
34
28
|
end
|
35
29
|
end
|
data/spec/utils_spec.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
describe Berater::Utils do
|
2
|
+
using Berater::Utils
|
3
|
+
|
4
|
+
describe '.to_msec' do
|
5
|
+
def f(val)
|
6
|
+
(val * 10**3).to_i
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'works with integers' do
|
10
|
+
expect(0.to_msec).to be f(0)
|
11
|
+
expect(3.to_msec).to be f(3)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'works with floats' do
|
15
|
+
expect(0.1.to_msec).to be f(0.1)
|
16
|
+
expect(3.0.to_msec).to be f(3)
|
17
|
+
end
|
18
|
+
|
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
|
+
end
|
23
|
+
|
24
|
+
it 'works with symbols that are keywords' do
|
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
|
+
|
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
|
+
|
33
|
+
expect(:hour.to_msec).to be f(60 * 60)
|
34
|
+
expect(:hours.to_msec).to be f(60 * 60)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'works with strings that are keywords' do
|
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
|
+
|
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
|
+
|
46
|
+
expect('hour'.to_msec).to be f(60 * 60)
|
47
|
+
expect('hours'.to_msec).to be f(60 * 60)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'works with strings that are numeric' do
|
51
|
+
expect('0'.to_msec).to be f(0)
|
52
|
+
expect('3'.to_msec).to be f(3)
|
53
|
+
|
54
|
+
expect('0.1'.to_msec).to be f(0.1)
|
55
|
+
expect('3.0'.to_msec).to be f(3)
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with erroneous values' do
|
59
|
+
def e(val)
|
60
|
+
expect { val.to_msec }.to raise_error(ArgumentError)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'rejects negative numbers' do
|
64
|
+
e(-1)
|
65
|
+
e(-1.2)
|
66
|
+
e('-1')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'rejects bogus symbols and strings' do
|
70
|
+
e('abc')
|
71
|
+
e('1a')
|
72
|
+
e(:abc)
|
73
|
+
e(Float::INFINITY)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
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.0
|
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-
|
11
|
+
date: 2021-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: benchmark
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: byebug
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,7 +122,7 @@ dependencies:
|
|
108
122
|
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
111
|
-
description:
|
125
|
+
description: work...within limits
|
112
126
|
email:
|
113
127
|
executables: []
|
114
128
|
extensions: []
|
@@ -120,19 +134,27 @@ files:
|
|
120
134
|
- lib/berater/inhibitor.rb
|
121
135
|
- lib/berater/limiter.rb
|
122
136
|
- lib/berater/lock.rb
|
137
|
+
- lib/berater/lua_script.rb
|
123
138
|
- lib/berater/rate_limiter.rb
|
124
139
|
- lib/berater/rspec.rb
|
125
140
|
- lib/berater/rspec/matchers.rb
|
126
141
|
- lib/berater/test_mode.rb
|
127
142
|
- lib/berater/unlimiter.rb
|
143
|
+
- lib/berater/utils.rb
|
128
144
|
- lib/berater/version.rb
|
129
145
|
- spec/berater_spec.rb
|
130
146
|
- spec/concurrency_limiter_spec.rb
|
147
|
+
- spec/dsl_refinement_spec.rb
|
148
|
+
- spec/dsl_spec.rb
|
131
149
|
- spec/inhibitor_spec.rb
|
150
|
+
- spec/limiter_spec.rb
|
151
|
+
- spec/lua_script_spec.rb
|
132
152
|
- spec/matchers_spec.rb
|
133
153
|
- spec/rate_limiter_spec.rb
|
154
|
+
- spec/riddle_spec.rb
|
134
155
|
- spec/test_mode_spec.rb
|
135
156
|
- spec/unlimiter_spec.rb
|
157
|
+
- spec/utils_spec.rb
|
136
158
|
homepage: https://github.com/dpep/berater_rb
|
137
159
|
licenses:
|
138
160
|
- MIT
|
@@ -159,8 +181,14 @@ summary: Berater
|
|
159
181
|
test_files:
|
160
182
|
- spec/rate_limiter_spec.rb
|
161
183
|
- spec/matchers_spec.rb
|
184
|
+
- spec/dsl_refinement_spec.rb
|
162
185
|
- spec/test_mode_spec.rb
|
186
|
+
- spec/dsl_spec.rb
|
187
|
+
- spec/lua_script_spec.rb
|
163
188
|
- spec/concurrency_limiter_spec.rb
|
189
|
+
- spec/riddle_spec.rb
|
190
|
+
- spec/utils_spec.rb
|
164
191
|
- spec/berater_spec.rb
|
192
|
+
- spec/limiter_spec.rb
|
165
193
|
- spec/inhibitor_spec.rb
|
166
194
|
- spec/unlimiter_spec.rb
|