berater 0.3.0 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,46 @@
1
+ require 'berater/dsl'
2
+
3
+ describe Berater do
4
+ using Berater::DSL
5
+
6
+ it 'instatiates an Unlimiter' do
7
+ limiter = Berater.new(:key) { unlimited }
8
+ expect(limiter).to be_a Berater::Unlimiter
9
+ expect(limiter.key).to be :key
10
+ end
11
+
12
+ it 'instatiates an Inhibiter' do
13
+ limiter = Berater.new(:key) { inhibited }
14
+ expect(limiter).to be_a Berater::Inhibitor
15
+ expect(limiter.key).to be :key
16
+ end
17
+
18
+ it 'instatiates a RateLimiter' do
19
+ limiter = Berater.new(:key) { 1.per second }
20
+ expect(limiter).to be_a Berater::RateLimiter
21
+ expect(limiter.key).to be :key
22
+ expect(limiter.capacity).to be 1
23
+ expect(limiter.interval).to be :second
24
+ end
25
+
26
+ it 'instatiates a ConcurrencyLimiter' do
27
+ limiter = Berater.new(:key, timeout: 2) { 1.at_once }
28
+ expect(limiter).to be_a Berater::ConcurrencyLimiter
29
+ expect(limiter.key).to be :key
30
+ expect(limiter.capacity).to be 1
31
+ expect(limiter.timeout).to be 2
32
+ end
33
+
34
+ it 'does not accept args and dsl block' do
35
+ expect {
36
+ Berater.new(:key, 2) { 3.at_once }
37
+ }.to raise_error(ArgumentError)
38
+ end
39
+
40
+ it 'requires either mode or dsl block' do
41
+ expect {
42
+ Berater.new(:key)
43
+ }.to raise_error(ArgumentError)
44
+ end
45
+
46
+ end
data/spec/dsl_spec.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'berater/dsl'
2
+
3
+ describe Berater::DSL do
4
+ def check(expected, &block)
5
+ expect(Berater::DSL.eval(&block)).to eq expected
6
+ end
7
+
8
+ context 'rate mode' do
9
+ it 'has keywords' do
10
+ check(:second) { second }
11
+ check(:minute) { minute }
12
+ check(:hour) { hour }
13
+ end
14
+
15
+ it 'parses' do
16
+ check([ 1, :second ]) { 1.per second }
17
+ check([ 3, :minute ]) { 3.per minute }
18
+ check([ 5, :hour ]) { 5.every hour }
19
+ end
20
+
21
+ it 'cleans up afterward' do
22
+ check([ 1, :second ]) { 1.per second }
23
+
24
+ expect(Integer).not_to respond_to(:per)
25
+ expect(Integer).not_to respond_to(:every)
26
+ end
27
+
28
+ it 'works with variables' do
29
+ count = 1
30
+ interval = :second
31
+
32
+ check([ count, interval ]) { count.per interval }
33
+ end
34
+ end
35
+
36
+ context 'concurrency mode' do
37
+ it 'parses' do
38
+ check([ 1 ]) { 1.at_once }
39
+ check([ 3 ]) { 3.at_a_time }
40
+ check([ 5 ]) { 5.concurrently }
41
+ end
42
+
43
+ it 'cleans up afterward' do
44
+ check([ 1 ]) { 1.at_once }
45
+
46
+ expect(Integer).not_to respond_to(:at_once)
47
+ expect(Integer).not_to respond_to(:at_a_time)
48
+ expect(Integer).not_to respond_to(:concurrently)
49
+ end
50
+
51
+ it 'works with constants' do
52
+ class Foo
53
+ CAPACITY = 3
54
+ end
55
+
56
+ check([ Foo::CAPACITY ]) { Foo::CAPACITY.at_once }
57
+ end
58
+ end
59
+
60
+ context 'unlimited mode' do
61
+ it 'has keywords' do
62
+ check(:unlimited) { unlimited }
63
+ end
64
+ end
65
+
66
+ context 'inhibited mode' do
67
+ it 'has keywords' do
68
+ check(:inhibited) { inhibited }
69
+ end
70
+ end
71
+
72
+ end
@@ -15,11 +15,9 @@ describe Berater::Inhibitor do
15
15
  end
16
16
 
17
17
  describe '#limit' do
18
- let(:limiter) { described_class.new }
18
+ subject { described_class.new }
19
19
 
20
- it 'always limits' do
21
- expect { limiter.limit }.to be_inhibited
22
- end
20
+ it_behaves_like 'it is overloaded'
23
21
  end
24
22
 
25
23
  end
@@ -0,0 +1,107 @@
1
+ describe Berater::Limiter do
2
+ it 'can not be initialized' do
3
+ expect { described_class.new }.to raise_error(NoMethodError)
4
+ end
5
+
6
+ describe 'abstract methods' do
7
+ let(:limiter) { Class.new(described_class).new(:key, 1) }
8
+
9
+ it do
10
+ expect { limiter.limit }.to raise_error(NotImplementedError)
11
+ expect { limiter.overloaded? }.to raise_error(NotImplementedError)
12
+ end
13
+ end
14
+
15
+ describe '#limit' do
16
+ subject { Berater::Unlimiter.new }
17
+
18
+ context 'with a capacity parameter' do
19
+ it 'overrides the stored value' do
20
+ is_expected.to receive(:acquire_lock).with(3, anything)
21
+
22
+ subject.limit(capacity: 3)
23
+ end
24
+
25
+ it 'validates the type' do
26
+ expect {
27
+ subject.limit(capacity: 'abc')
28
+ }.to raise_error(ArgumentError)
29
+ end
30
+ end
31
+
32
+ context 'with a cost parameter' do
33
+ it 'overrides the stored value' do
34
+ is_expected.to receive(:acquire_lock).with(anything, 2)
35
+
36
+ subject.limit(cost: 2)
37
+ end
38
+
39
+ it 'validates' do
40
+ expect {
41
+ subject.limit(cost: 'abc')
42
+ }.to raise_error(ArgumentError)
43
+
44
+ expect {
45
+ subject.limit(cost: -1)
46
+ }.to raise_error(ArgumentError)
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#==' do
52
+ let(:limiter) { Berater::RateLimiter.new(:key, 1, :second) }
53
+
54
+ it 'equals itself' do
55
+ expect(limiter).to eq limiter
56
+ end
57
+
58
+ it 'equals something with the same initialization parameters' do
59
+ expect(limiter).to eq(
60
+ Berater::RateLimiter.new(:key, 1, :second)
61
+ )
62
+ end
63
+
64
+ it 'equals something with equvalent initialization parameters' do
65
+ expect(limiter).to eq(
66
+ Berater::RateLimiter.new(:key, 1, 1)
67
+ )
68
+ end
69
+
70
+ it 'does not equal something different' do
71
+ expect(limiter).not_to eq(
72
+ Berater::RateLimiter.new(:key, 2, :second)
73
+ )
74
+
75
+ expect(limiter).not_to eq(
76
+ Berater::RateLimiter.new(:keyz, 1, :second)
77
+ )
78
+
79
+ expect(limiter).not_to eq(
80
+ Berater::RateLimiter.new(:key, 1, :minute)
81
+ )
82
+ end
83
+
84
+ it 'does not equal something altogether different' do
85
+ expect(limiter).not_to eq(
86
+ Berater::ConcurrencyLimiter.new(:key, 1)
87
+ )
88
+ end
89
+
90
+ it 'works for ConcurrencyLimiter too' do
91
+ limiter = Berater::ConcurrencyLimiter.new(:key, 1)
92
+ expect(limiter).to eq limiter
93
+
94
+ expect(limiter).not_to eq(
95
+ Berater::ConcurrencyLimiter.new(:key, 1, timeout: 1)
96
+ )
97
+ end
98
+
99
+ it 'and the others' do
100
+ unlimiter = Berater::Unlimiter.new
101
+ expect(unlimiter).to eq unlimiter
102
+
103
+ expect(unlimiter).not_to eq Berater::Inhibitor.new
104
+ end
105
+ end
106
+
107
+ end
@@ -0,0 +1,97 @@
1
+ describe Berater::LuaScript do
2
+ subject { Berater::LuaScript('return redis.call("PING")') }
3
+
4
+ before { redis.script(:flush) }
5
+
6
+ let(:redis) { Berater.redis }
7
+
8
+ it { is_expected.to be_a Berater::LuaScript }
9
+
10
+ describe '#eval' do
11
+ def ping
12
+ expect(subject.eval(redis)).to eq 'PONG'
13
+ end
14
+
15
+ it { ping }
16
+
17
+ it 'loads the script into redis' do
18
+ expect(redis).to receive(:evalsha).once.and_call_original
19
+ expect(redis).to receive(:eval).once.and_call_original
20
+ ping
21
+ expect(subject.loaded?(redis)).to be true
22
+ end
23
+ end
24
+
25
+ describe '#load' do
26
+ it 'loads script into redis' do
27
+ expect(redis.script(:exists, subject.sha)).to be false
28
+ subject.load(redis)
29
+ expect(redis.script(:exists, subject.sha)).to be true
30
+ end
31
+
32
+ it 'returns the sha' do
33
+ expect(subject.load(redis)).to eq subject.sha
34
+ end
35
+
36
+ it 'validates the returned sha' do
37
+ allow(redis).to receive(:script).with(:flush).and_call_original
38
+ expect(redis).to receive(:script).with(:load, String).and_return('abc')
39
+ expect { subject.load(redis) }.to raise_error(RuntimeError)
40
+ end
41
+ end
42
+
43
+ describe '#loaded?' do
44
+ it do
45
+ expect(subject.loaded?(redis)).to be false
46
+ subject.load(redis)
47
+ expect(subject.loaded?(redis)).to be true
48
+ end
49
+ end
50
+
51
+ describe '#to_s' do
52
+ it { expect(subject.to_s).to be subject.source }
53
+ end
54
+
55
+ describe '#minify' do
56
+ subject do
57
+ expect(
58
+ Berater::LuaScript(lua).send(:minify)
59
+ ).to eq expected
60
+ end
61
+
62
+ context do
63
+ let(:lua) do <<-LUA
64
+ -- this comment gets removed
65
+ redis.call('PING') -- this one too
66
+ LUA
67
+ end
68
+
69
+ let(:expected) { "redis.call('PING')" }
70
+
71
+ it { subject }
72
+ end
73
+
74
+ context 'with if statement' do
75
+ let(:lua) do <<~LUA
76
+ if condition then
77
+ call
78
+ end
79
+
80
+ return 123
81
+ LUA
82
+ end
83
+
84
+ let(:expected) do
85
+ [
86
+ 'if condition then',
87
+ 'call',
88
+ 'end',
89
+ 'return 123'
90
+ ].join "\n"
91
+ end
92
+
93
+ it { subject }
94
+ end
95
+ end
96
+
97
+ end
@@ -1,4 +1,5 @@
1
- describe 'be_overloaded' do
1
+ describe Berater::Matchers::Overloaded do
2
+
2
3
  context 'Berater::Unlimiter' do
3
4
  let(:limiter) { Berater.new(:key, :unlimited) }
4
5
 
@@ -32,7 +33,7 @@ describe 'be_overloaded' do
32
33
  end
33
34
 
34
35
  context 'Berater::RateLimiter' do
35
- let(:limiter) { Berater.new(:key, :rate, 1, :second) }
36
+ let(:limiter) { Berater.new(:key, 1, :second) }
36
37
 
37
38
  it { expect(limiter).not_to be_overloaded }
38
39
  it { expect(limiter).not_to be_inhibited }
@@ -67,7 +68,7 @@ describe 'be_overloaded' do
67
68
  end
68
69
 
69
70
  context 'Berater::ConcurrencyLimiter' do
70
- let(:limiter) { Berater.new(:key, :concurrency, 1) }
71
+ let(:limiter) { Berater.new(:key, 1) }
71
72
 
72
73
  it { expect(limiter).not_to be_overloaded }
73
74
  it { expect(limiter).not_to be_inhibited }
@@ -115,4 +116,71 @@ describe 'be_overloaded' do
115
116
  end
116
117
  end
117
118
  end
119
+
120
+ context 'when matchers fail' do
121
+ let(:unlimiter) { Berater::Unlimiter.new }
122
+ let(:inhibitor) { Berater::Inhibitor.new }
123
+
124
+ it 'catches false negatives' do
125
+ expect {
126
+ expect(unlimiter).to be_overloaded
127
+ }.to fail_including('expected to be overloaded')
128
+
129
+ expect {
130
+ expect { unlimiter }.to be_overloaded
131
+ }.to fail_including('expected to be overloaded')
132
+
133
+ expect {
134
+ expect { unlimiter.limit }.to be_overloaded
135
+ }.to fail_including("expected #{Berater::Overloaded} to be raised")
136
+
137
+ expect {
138
+ expect { 123 }.to be_overloaded
139
+ }.to fail_including("expected #{Berater::Overloaded} to be raised")
140
+ end
141
+
142
+ it 'catches false positives' do
143
+ expect {
144
+ expect(inhibitor).not_to be_overloaded
145
+ }.to fail_including('expected not to be overloaded')
146
+
147
+ expect {
148
+ expect { inhibitor }.not_to be_overloaded
149
+ }.to fail_including('expected not to be overloaded')
150
+
151
+ expect {
152
+ expect { inhibitor.limit }.not_to be_overloaded
153
+ }.to fail_including("did not expect #{Berater::Overloaded} to be raised")
154
+
155
+ expect {
156
+ expect { raise Berater::Overloaded }.not_to be_overloaded
157
+ }.to fail_including("did not expect #{Berater::Overloaded} to be raised")
158
+ end
159
+
160
+ it 'supports different verbs' do
161
+ expect {
162
+ expect { unlimiter }.to be_overrated
163
+ }.to fail_including('expected to be overrated')
164
+
165
+ expect {
166
+ expect { unlimiter }.to be_incapacitated
167
+ }.to fail_including('expected to be incapacitated')
168
+ end
169
+
170
+ it 'supports different exceptions' do
171
+ expect {
172
+ expect { 123 }.to be_overrated
173
+ }.to fail_including(
174
+ "expected #{Berater::RateLimiter::Overrated} to be raised"
175
+ )
176
+
177
+ expect {
178
+ expect {
179
+ raise Berater::ConcurrencyLimiter::Incapacitated
180
+ }.not_to be_incapacitated
181
+ }.to fail_including(
182
+ "did not expect #{Berater::ConcurrencyLimiter::Incapacitated} to be raised"
183
+ )
184
+ end
185
+ end
118
186
  end
@@ -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,48 @@ 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(1.5) }
27
+ it { expect_capacity(100) }
27
28
 
28
29
  context 'with erroneous values' do
29
- def expect_bad_count(count)
30
+ def expect_bad_capacity(capacity)
30
31
  expect do
31
- described_class.new(:key, count, :second)
32
+ described_class.new(:key, capacity, :second)
32
33
  end.to raise_error ArgumentError
33
34
  end
34
35
 
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) }
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
43
+ # see spec/utils_spec.rb for more
66
44
 
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
45
+ subject { described_class.new(:key, 1, :second) }
72
46
 
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') }
47
+ it 'saves the interval in original and millisecond format' do
48
+ expect(subject.interval).to be :second
49
+ expect(subject.instance_variable_get(:@interval_msec)).to be 10**3
83
50
  end
84
51
 
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
52
+ it 'must be > 0' do
53
+ expect {
54
+ described_class.new(:key, 1, 0)
55
+ }.to raise_error(ArgumentError)
90
56
 
91
- it { expect_sec(:second, 1) }
92
- it { expect_sec(:minute, 60) }
93
- it { expect_sec(:hour, 3600) }
57
+ expect {
58
+ described_class.new(:key, 1, -1)
59
+ }.to raise_error(ArgumentError)
94
60
  end
95
61
  end
96
62
 
@@ -112,50 +78,132 @@ describe Berater::RateLimiter do
112
78
  expect(limiter).to be_overrated
113
79
  end
114
80
 
115
- it 'limit resets over time' do
81
+ it 'resets limit over time' do
116
82
  3.times { limiter.limit }
117
83
  expect(limiter).to be_overrated
118
84
 
119
- # travel forward a second
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
+ context 'with millisecond precision' do
92
+ it 'resets limit over time' do
93
+ 3.times { limiter.limit }
94
+ expect(limiter).to be_overrated
130
95
 
131
- it 'works as expected' do
132
- expect(limiter_one.limit).not_to be_overrated
96
+ # travel forward to just before the count decrements
97
+ Timecop.freeze(0.333)
98
+ expect(limiter).to be_overrated
133
99
 
134
- expect(limiter_one).to be_overrated
135
- expect(limiter_two).to be_overrated
100
+ # traveling one more millisecond will decrement the count
101
+ Timecop.freeze(0.001)
102
+ limiter.limit
103
+ expect(limiter).to be_overrated
104
+ end
105
+
106
+ it 'works when drip rate is < 1 per millisecond' do
107
+ limiter = described_class.new(:key, 2_000, :second)
108
+
109
+ limiter.capacity.times { limiter.limit }
110
+ expect(limiter).to be_overrated
111
+
112
+ Timecop.freeze(0.001)
113
+ expect(limiter).not_to be_overrated
114
+
115
+ 2.times { limiter.limit }
116
+ end
136
117
  end
137
- end
138
118
 
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) }
119
+ context 'when capacity is a Float' do
120
+ let(:limiter) { described_class.new(:key, 1.5, :second) }
121
+
122
+ it 'still works' do
123
+ limiter.limit
124
+ expect(limiter).not_to be_overrated
125
+
126
+ expect { limiter.limit }.to be_overrated
127
+
128
+ limiter.limit(cost: 0.5)
129
+ end
130
+ end
131
+
132
+ it 'accepts a dynamic capacity' do
133
+ limiter = described_class.new(:key, 1, :second)
134
+
135
+ expect { limiter.limit(capacity: 0) }.to be_overrated
136
+ 5.times { limiter.limit(capacity: 10) }
137
+ expect { limiter }.to be_overrated
138
+ end
139
+
140
+ context 'works with cost parameter' do
141
+ it { expect { limiter.limit(cost: 4) }.to be_overrated }
142
+
143
+ it 'works within limit' do
144
+ limiter.limit(cost: 3)
145
+ expect { limiter.limit }.to be_overrated
146
+ end
147
+
148
+ it 'resets over time' do
149
+ limiter.limit(cost: 3)
150
+ expect(limiter).to be_overrated
151
+
152
+ Timecop.freeze(1)
153
+ expect(limiter).not_to be_overrated
154
+ end
155
+
156
+ it 'can be a Float' do
157
+ 2.times { limiter.limit(cost: 1.5) }
158
+ expect(limiter).to be_overrated
159
+ end
160
+ end
161
+
162
+ context 'with same key, different limiters' do
163
+ let(:limiter_one) { described_class.new(:key, 1, :second) }
164
+ let(:limiter_two) { described_class.new(:key, 1, :second) }
165
+
166
+ it 'works as expected' do
167
+ expect(limiter_one.limit).not_to be_overrated
168
+
169
+ expect(limiter_one).to be_overrated
170
+ expect(limiter_two).to be_overrated
171
+ end
172
+ end
173
+
174
+ context 'with different keys, different limiters' do
175
+ let(:limiter_one) { described_class.new(:one, 1, :second) }
176
+ let(:limiter_two) { described_class.new(:two, 2, :second) }
177
+
178
+ it 'works as expected' do
179
+ expect(limiter_one.limit).not_to be_overrated
180
+ expect(limiter_two.limit).not_to be_overrated
181
+
182
+ expect(limiter_one).to be_overrated
183
+ expect(limiter_two.limit).not_to be_overrated
142
184
 
143
- it 'works as expected' do
144
- expect(limiter_one.limit).not_to be_overrated
145
- expect(limiter_two.limit).not_to be_overrated
185
+ expect(limiter_one).to be_overrated
186
+ expect(limiter_two).to be_overrated
187
+ end
188
+ end
189
+ end
146
190
 
147
- expect(limiter_one).to be_overrated
148
- expect(limiter_two.limit).not_to be_overrated
191
+ describe '#overloaded?' do
192
+ let(:limiter) { described_class.new(:key, 1, :second) }
149
193
 
150
- expect(limiter_one).to be_overrated
151
- expect(limiter_two).to be_overrated
194
+ it 'works' do
195
+ expect(limiter.overloaded?).to be false
196
+ limiter.limit
197
+ expect(limiter.overloaded?).to be true
198
+ Timecop.freeze(1)
199
+ expect(limiter.overloaded?).to be false
152
200
  end
153
201
  end
154
202
 
155
203
  describe '#to_s' do
156
- def check(count, interval, expected)
204
+ def check(capacity, interval, expected)
157
205
  expect(
158
- described_class.new(:key, count, interval).to_s
206
+ described_class.new(:key, capacity, interval).to_s
159
207
  ).to match(expected)
160
208
  end
161
209
 
@@ -171,16 +219,6 @@ describe Berater::RateLimiter do
171
219
  check(1, 'hour', /1 per hour/)
172
220
  end
173
221
 
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
222
  it 'works with integers' do
185
223
  check(1, 1, /1 every second/)
186
224
  check(1, 2, /1 every 2 seconds/)