berater 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,36 +1,24 @@
1
1
  describe Berater::Inhibitor do
2
- before { Berater.mode = :inhibited }
3
-
4
2
  describe '.new' do
5
3
  it 'initializes without any arguments or options' do
6
4
  expect(described_class.new).to be_a described_class
7
5
  end
8
6
 
9
7
  it 'initializes with any arguments and options' do
10
- expect(described_class.new(:abc, x: 123)).to be_a described_class
8
+ expect(described_class.new(:abc, :def, x: 123)).to be_a described_class
11
9
  end
12
10
 
13
11
  it 'has default values' do
14
- expect(described_class.new.key).to eq described_class.to_s
12
+ expect(described_class.new.key).to be :inhibitor
15
13
  expect(described_class.new.redis).to be Berater.redis
16
14
  end
17
15
  end
18
16
 
19
- describe '.limit' do
20
- it 'always limits' do
21
- expect { described_class.limit }.to be_inhibited
22
- end
23
-
24
- it 'works with any arguments or options' do
25
- expect { described_class.limit(:abc, x: 123) }.to be_inhibited
26
- end
27
- end
28
-
29
17
  describe '#limit' do
30
18
  let(:limiter) { described_class.new }
31
19
 
32
20
  it 'always limits' do
33
- expect { described_class.limit }.to be_inhibited
21
+ expect { limiter.limit }.to be_inhibited
34
22
  end
35
23
  end
36
24
 
@@ -1,6 +1,6 @@
1
1
  describe 'be_overloaded' do
2
2
  context 'Berater::Unlimiter' do
3
- let(:limiter) { Berater.new(:unlimited) }
3
+ let(:limiter) { Berater.new(:key, :unlimited) }
4
4
 
5
5
  it { expect(limiter).not_to be_overloaded }
6
6
  it { expect(limiter).not_to be_inhibited }
@@ -19,7 +19,7 @@ describe 'be_overloaded' do
19
19
  end
20
20
 
21
21
  context 'Berater::Inhibitor' do
22
- let(:limiter) { Berater.new(:inhibited) }
22
+ let(:limiter) { Berater.new(:key, :inhibited) }
23
23
 
24
24
  it { expect(limiter).to be_overloaded }
25
25
  it { expect(limiter).to be_inhibited }
@@ -32,7 +32,7 @@ describe 'be_overloaded' do
32
32
  end
33
33
 
34
34
  context 'Berater::RateLimiter' do
35
- let(:limiter) { Berater.new(:rate, 1, :second) }
35
+ let(:limiter) { Berater.new(:key, :rate, 1, :second) }
36
36
 
37
37
  it { expect(limiter).not_to be_overloaded }
38
38
  it { expect(limiter).not_to be_inhibited }
@@ -67,7 +67,7 @@ describe 'be_overloaded' do
67
67
  end
68
68
 
69
69
  context 'Berater::ConcurrencyLimiter' do
70
- let(:limiter) { Berater.new(:concurrency, 1) }
70
+ let(:limiter) { Berater.new(:key, :concurrency, 1) }
71
71
 
72
72
  it { expect(limiter).not_to be_overloaded }
73
73
  it { expect(limiter).not_to be_inhibited }
@@ -1,23 +1,23 @@
1
1
  describe Berater::RateLimiter do
2
- before { Berater.mode = :rate }
2
+ it_behaves_like 'a limiter', Berater.new(:key, :rate, 3, :second)
3
3
 
4
4
  describe '.new' do
5
- let(:limiter) { described_class.new(1, :second) }
5
+ let(:limiter) { described_class.new(:key, 1, :second) }
6
6
 
7
7
  it 'initializes' do
8
+ expect(limiter.key).to be :key
8
9
  expect(limiter.count).to eq 1
9
- expect(limiter.interval).to eq 1
10
+ expect(limiter.interval).to eq :second
10
11
  end
11
12
 
12
13
  it 'has default values' do
13
- expect(limiter.key).to eq described_class.to_s
14
14
  expect(limiter.redis).to be Berater.redis
15
15
  end
16
16
  end
17
17
 
18
18
  describe '#count' do
19
19
  def expect_count(count)
20
- limiter = described_class.new(count, :second)
20
+ limiter = described_class.new(:key, count, :second)
21
21
  expect(limiter.count).to eq count
22
22
  end
23
23
 
@@ -28,7 +28,7 @@ describe Berater::RateLimiter do
28
28
  context 'with erroneous values' do
29
29
  def expect_bad_count(count)
30
30
  expect do
31
- described_class.new(count, :second)
31
+ described_class.new(:key, count, :second)
32
32
  end.to raise_error ArgumentError
33
33
  end
34
34
 
@@ -41,7 +41,7 @@ describe Berater::RateLimiter do
41
41
 
42
42
  describe '#interval' do
43
43
  def expect_interval(interval, expected)
44
- limiter = described_class.new(1, interval)
44
+ limiter = described_class.new(:key, 1, interval)
45
45
  expect(limiter.interval).to eq expected
46
46
  end
47
47
 
@@ -52,28 +52,28 @@ describe Berater::RateLimiter do
52
52
  end
53
53
 
54
54
  context 'with symbols' do
55
- it { expect_interval(:sec, 1) }
56
- it { expect_interval(:second, 1) }
57
- it { expect_interval(:seconds, 1) }
55
+ it { expect_interval(:sec, :second) }
56
+ it { expect_interval(:second, :second) }
57
+ it { expect_interval(:seconds, :second) }
58
58
 
59
- it { expect_interval(:min, 60) }
60
- it { expect_interval(:minute, 60) }
61
- it { expect_interval(:minutes, 60) }
59
+ it { expect_interval(:min, :minute) }
60
+ it { expect_interval(:minute, :minute) }
61
+ it { expect_interval(:minutes, :minute) }
62
62
 
63
- it { expect_interval(:hour, 3600) }
64
- it { expect_interval(:hours, 3600) }
63
+ it { expect_interval(:hour, :hour) }
64
+ it { expect_interval(:hours, :hour) }
65
65
  end
66
66
 
67
67
  context 'with strings' do
68
- it { expect_interval('sec', 1) }
69
- it { expect_interval('minute', 60) }
70
- it { expect_interval('hours', 3600) }
68
+ it { expect_interval('sec', :second) }
69
+ it { expect_interval('minute', :minute) }
70
+ it { expect_interval('hours', :hour) }
71
71
  end
72
72
 
73
73
  context 'with erroneous values' do
74
74
  def expect_bad_interval(interval)
75
75
  expect do
76
- described_class.new(1, interval)
76
+ described_class.new(:key, 1, interval)
77
77
  end.to raise_error(ArgumentError)
78
78
  end
79
79
 
@@ -81,85 +81,110 @@ describe Berater::RateLimiter do
81
81
  it { expect_bad_interval(:secondz) }
82
82
  it { expect_bad_interval('huor') }
83
83
  end
84
- end
85
84
 
86
- describe '#limit' do
87
- let(:limiter) { described_class.new(3, :second) }
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
88
90
 
89
- it 'works' do
90
- expect(limiter.limit).to eq 1
91
+ it { expect_sec(:second, 1) }
92
+ it { expect_sec(:minute, 60) }
93
+ it { expect_sec(:hour, 3600) }
91
94
  end
95
+ end
92
96
 
93
- it 'counts' do
94
- expect(limiter.limit).to eq 1
95
- expect(limiter.limit).to eq 2
96
- expect(limiter.limit).to eq 3
97
- end
97
+ describe '#limit' do
98
+ let(:limiter) { described_class.new(:key, 3, :second) }
98
99
 
99
- it 'yields' do
100
+ it 'works' do
100
101
  expect {|b| limiter.limit(&b) }.to yield_control
101
102
  expect(limiter.limit { 123 }).to eq 123
102
103
  end
103
104
 
105
+ it 'works without a block' do
106
+ expect(limiter.limit).to be_a Berater::Lock
107
+ end
108
+
104
109
  it 'limits excessive calls' do
105
110
  3.times { limiter.limit }
106
111
 
107
- expect { limiter.limit }.to be_overrated
112
+ expect(limiter).to be_overrated
108
113
  end
109
114
 
110
115
  it 'limit resets over time' do
111
- expect(limiter.limit).to eq 1
112
- expect(limiter.limit).to eq 2
113
- expect(limiter.limit).to eq 3
116
+ 3.times { limiter.limit }
114
117
  expect(limiter).to be_overrated
115
118
 
116
119
  # travel forward a second
117
120
  Timecop.freeze(1)
118
121
 
119
- expect(limiter.limit).to eq 1
120
- expect(limiter.limit).to eq 2
121
- expect(limiter.limit).to eq 3
122
+ 3.times { limiter.limit }
122
123
  expect(limiter).to be_overrated
123
124
  end
124
125
  end
125
126
 
126
127
  context 'with same key, different limiters' do
127
- let(:limiter_one) { described_class.new(1, :second) }
128
- let(:limiter_two) { described_class.new(1, :second) }
128
+ let(:limiter_one) { described_class.new(:key, 1, :second) }
129
+ let(:limiter_two) { described_class.new(:key, 1, :second) }
129
130
 
130
131
  it 'works as expected' do
131
- expect(limiter_one.limit).to eq 1
132
+ expect(limiter_one.limit).not_to be_overrated
132
133
 
133
- expect { limiter_one }.to be_overrated
134
- expect { limiter_two }.to be_overrated
134
+ expect(limiter_one).to be_overrated
135
+ expect(limiter_two).to be_overrated
135
136
  end
136
137
  end
137
138
 
138
- context 'with different keys, same limiter' do
139
- let(:limiter) { described_class.new(1, :second) }
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) }
140
142
 
141
143
  it 'works as expected' do
142
- expect { limiter.limit(key: :one) }.not_to be_overrated
143
- expect { limiter.limit(key: :one) }.to be_overrated
144
+ expect(limiter_one.limit).not_to be_overrated
145
+ expect(limiter_two.limit).not_to be_overrated
146
+
147
+ expect(limiter_one).to be_overrated
148
+ expect(limiter_two.limit).not_to be_overrated
144
149
 
145
- expect { limiter.limit(key: :two) }.not_to be_overrated
146
- expect { limiter.limit(key: :two) }.to be_overrated
150
+ expect(limiter_one).to be_overrated
151
+ expect(limiter_two).to be_overrated
147
152
  end
148
153
  end
149
154
 
150
- context 'with different keys, different limiters' do
151
- let(:limiter_one) { described_class.new(1, :second, key: :one) }
152
- let(:limiter_two) { described_class.new(2, :second, key: :two) }
155
+ describe '#to_s' do
156
+ def check(count, interval, expected)
157
+ expect(
158
+ described_class.new(:key, count, interval).to_s
159
+ ).to match(expected)
160
+ end
153
161
 
154
- it 'works as expected' do
155
- expect(limiter_one.limit).to eq 1
156
- expect(limiter_two.limit).to eq 1
162
+ it 'works with symbols' do
163
+ check(1, :second, /1 per second/)
164
+ check(1, :minute, /1 per minute/)
165
+ check(1, :hour, /1 per hour/)
166
+ end
167
+
168
+ it 'works with strings' do
169
+ check(1, 'second', /1 per second/)
170
+ check(1, 'minute', /1 per minute/)
171
+ check(1, 'hour', /1 per hour/)
172
+ end
157
173
 
158
- expect { limiter_one.limit }.to be_overrated
159
- expect(limiter_two.limit).to eq 2
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
160
183
 
161
- expect { limiter_one.limit }.to be_overrated
162
- expect { limiter_two.limit }.to be_overrated
184
+ it 'works with integers' do
185
+ check(1, 1, /1 every second/)
186
+ check(1, 2, /1 every 2 seconds/)
187
+ check(2, 3, /2 every 3 seconds/)
163
188
  end
164
189
  end
165
190
 
@@ -0,0 +1,183 @@
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 }
8
+
9
+ context 'when test_mode = nil' do
10
+ before { Berater.test_mode = nil }
11
+
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
18
+ end
19
+
20
+ context 'when test_mode = :pass' do
21
+ before { Berater.test_mode = :pass }
22
+
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
29
+ end
30
+
31
+ context 'when test_mode = :fail' do
32
+ before { Berater.test_mode = :fail }
33
+
34
+ it { expect(limiter).to be_a Berater::Unlimiter }
35
+
36
+ it 'never works' do
37
+ expect { limiter }.to be_overloaded
38
+ end
39
+ end
40
+ end
41
+
42
+ describe 'Inhibitor' do
43
+ let(:limiter) { Berater::Inhibitor.new }
44
+
45
+ context 'when test_mode = nil' do
46
+ before { Berater.test_mode = nil }
47
+
48
+ it { expect(limiter).to be_a Berater::Inhibitor }
49
+
50
+ it 'works per usual' do
51
+ expect { limiter }.to be_overloaded
52
+ end
53
+ end
54
+
55
+ context 'when test_mode = :pass' do
56
+ before { Berater.test_mode = :pass }
57
+
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
64
+ end
65
+
66
+ context 'when test_mode = :fail' do
67
+ before { Berater.test_mode = :fail }
68
+
69
+ it { expect(limiter).to be_a Berater::Inhibitor }
70
+
71
+ it 'never works' do
72
+ expect { limiter }.to be_overloaded
73
+ end
74
+ end
75
+ end
76
+
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
89
+
90
+ context 'when test_mode = nil' do
91
+ before { Berater.test_mode = nil }
92
+
93
+ it_behaves_like 'a RateLimiter'
94
+
95
+ it 'works per usual' do
96
+ expect(limiter.redis).to receive(:multi).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
104
+ end
105
+
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(:multi)
113
+ expect {|block| limiter.limit(&block) }.to yield_control
114
+ 10.times { expect(limiter.limit).to be_a Berater::Lock }
115
+ end
116
+ end
117
+
118
+ context 'when test_mode = :fail' do
119
+ before { Berater.test_mode = :fail }
120
+
121
+ it_behaves_like 'a RateLimiter'
122
+
123
+ it 'never works and without calling redis' do
124
+ expect(limiter.redis).not_to receive(:multi)
125
+ expect { limiter }.to be_overloaded
126
+ end
127
+ end
128
+ end
129
+
130
+ describe 'ConcurrencyLimiter' do
131
+ let(:limiter) { Berater::ConcurrencyLimiter.new(:key, 1) }
132
+
133
+ shared_examples 'a ConcurrencyLimiter' do
134
+ it { expect(limiter).to be_a Berater::ConcurrencyLimiter }
135
+
136
+ it 'checks arguments' do
137
+ expect {
138
+ Berater::ConcurrencyLimiter.new(:key, 1.0)
139
+ }.to raise_error(ArgumentError)
140
+ end
141
+ end
142
+
143
+ context 'when test_mode = nil' do
144
+ before { Berater.test_mode = nil }
145
+
146
+ it_behaves_like 'a ConcurrencyLimiter'
147
+
148
+ 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
156
+ end
157
+ end
158
+
159
+ context 'when test_mode = :pass' do
160
+ before { Berater.test_mode = :pass }
161
+
162
+ 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
169
+ end
170
+
171
+ context 'when test_mode = :fail' do
172
+ before { Berater.test_mode = :fail }
173
+
174
+ 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
180
+ end
181
+ end
182
+
183
+ end