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.
@@ -1,183 +1,142 @@
1
- require 'berater/test_mode'
2
-
3
- describe 'Berater.test_mode' do
4
- after { Berater.test_mode = nil }
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
- context 'when test_mode = nil' do
10
- before { Berater.test_mode = nil }
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
- it { expect(limiter).to be_a Berater::Unlimiter }
11
+ it 'defaults to off' do
12
+ expect(Berater.test_mode).to be nil
13
+ end
13
14
 
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
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
- context 'when test_mode = :pass' do
21
- before { Berater.test_mode = :pass }
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
- it { expect(limiter).to be_a Berater::Unlimiter }
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
- 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
30
+ Berater.test_mode = :fail
31
+ expect(Berater.test_mode).to be :fail
29
32
  end
30
33
 
31
- context 'when test_mode = :fail' do
32
- before { Berater.test_mode = :fail }
33
-
34
- it { expect(limiter).to be_a Berater::Unlimiter }
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
- it 'never works' do
37
- expect { limiter }.to be_overloaded
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
- describe 'Inhibitor' do
43
- let(:limiter) { Berater::Inhibitor.new }
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
- context 'when test_mode = nil' do
46
- before { Berater.test_mode = nil }
47
+ Berater.test_mode = :fail
48
+ expect(limiter).to be_overloaded
49
+ end
47
50
 
48
- it { expect(limiter).to be_a Berater::Inhibitor }
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
- it 'works per usual' do
51
- expect { limiter }.to be_overloaded
52
- end
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 'when test_mode = :pass' do
65
+ context 'with test_mode = :pass' do
56
66
  before { Berater.test_mode = :pass }
57
67
 
58
- it { expect(limiter).to be_a Berater::Inhibitor }
68
+ it_behaves_like 'it is not overloaded'
59
69
 
60
70
  it 'always works' do
61
- expect {|block| limiter.limit(&block) }.to yield_control
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 'when test_mode = :fail' do
75
+ context 'with test_mode = :fail' do
67
76
  before { Berater.test_mode = :fail }
68
77
 
69
- it { expect(limiter).to be_a Berater::Inhibitor }
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 'RateLimiter' do
78
- let(:limiter) { Berater::RateLimiter.new(:key, 1, :second) }
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 'a RateLimiter'
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
- context 'when test_mode = :pass' do
107
- before { Berater.test_mode = :pass }
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
- context 'when test_mode = :fail' do
119
- before { Berater.test_mode = :fail }
94
+ describe 'Inhibitor' do
95
+ subject { Berater::Inhibitor.new }
120
96
 
121
- it_behaves_like 'a RateLimiter'
97
+ context 'when test_mode = nil' do
98
+ before { Berater.test_mode = nil }
122
99
 
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
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
- shared_examples 'a ConcurrencyLimiter' do
134
- it { expect(limiter).to be_a Berater::ConcurrencyLimiter }
103
+ it_behaves_like 'it supports test_mode'
104
+ end
135
105
 
136
- it 'checks arguments' do
137
- expect {
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 'a ConcurrencyLimiter'
112
+ it_behaves_like 'it is not overloaded'
147
113
 
148
114
  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
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
- context 'when test_mode = :pass' do
160
- before { Berater.test_mode = :pass }
161
-
162
- it_behaves_like 'a ConcurrencyLimiter'
121
+ it_behaves_like 'it supports test_mode'
122
+ end
163
123
 
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
169
- end
124
+ describe 'ConcurrencyLimiter' do
125
+ subject { Berater::ConcurrencyLimiter.new(:key, 1) }
170
126
 
171
- context 'when test_mode = :fail' do
172
- before { Berater.test_mode = :fail }
127
+ context 'when test_mode = nil' do
128
+ before { Berater.test_mode = nil }
173
129
 
174
- it_behaves_like 'a ConcurrencyLimiter'
130
+ it_behaves_like 'it is not overloaded'
175
131
 
176
- it 'never works and without calling redis' do
177
- expect(limiter.redis).not_to receive(:eval)
178
- expect { limiter }.to be_overloaded
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
@@ -17,19 +17,13 @@ describe Berater::Unlimiter do
17
17
  end
18
18
 
19
19
  describe '#limit' do
20
- let(:limiter) { described_class.new }
20
+ subject { described_class.new }
21
21
 
22
- it 'works' do
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 { limiter.limit }.not_to be_overloaded
26
+ expect { subject.limit }.not_to be_overloaded
33
27
  end
34
28
  end
35
29
  end
@@ -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.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-02-22 00:00:00.000000000 Z
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: rate limiter
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