berater 0.1.1 → 0.3.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 +35 -24
- data/lib/berater/concurrency_limiter.rb +31 -88
- data/lib/berater/dsl.rb +57 -0
- data/lib/berater/inhibitor.rb +4 -10
- data/lib/berater/limiter.rb +30 -0
- data/lib/berater/lock.rb +36 -0
- data/lib/berater/rate_limiter.rb +37 -23
- data/lib/berater/rspec.rb +12 -0
- data/lib/berater/rspec/matchers.rb +60 -0
- data/lib/berater/test_mode.rb +43 -0
- data/lib/berater/unlimiter.rb +14 -10
- data/lib/berater/version.rb +1 -1
- data/spec/berater_spec.rb +69 -90
- data/spec/concurrency_limiter_spec.rb +63 -74
- data/spec/inhibitor_spec.rb +3 -15
- data/spec/{matcher_spec.rb → matchers_spec.rb} +4 -4
- data/spec/rate_limiter_spec.rb +83 -58
- data/spec/test_mode_spec.rb +183 -0
- data/spec/unlimiter_spec.rb +6 -31
- metadata +12 -7
- data/lib/berater/base_limiter.rb +0 -34
- data/spec/concurrency_lock_spec.rb +0 -50
@@ -0,0 +1,60 @@
|
|
1
|
+
module BeraterMatchers
|
2
|
+
class Overloaded
|
3
|
+
def initialize(type)
|
4
|
+
@type = type
|
5
|
+
end
|
6
|
+
|
7
|
+
def supports_block_expectations?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(obj)
|
12
|
+
begin
|
13
|
+
case obj
|
14
|
+
when Proc
|
15
|
+
# eg. expect { ... }.to be_overrated
|
16
|
+
res = obj.call
|
17
|
+
|
18
|
+
if res.is_a? Berater::Limiter
|
19
|
+
# eg. expect { Berater.new(...) }.to be_overrated
|
20
|
+
res.limit {}
|
21
|
+
end
|
22
|
+
when Berater::Limiter
|
23
|
+
# eg. expect(Berater.new(...)).to be_overrated
|
24
|
+
obj.limit {}
|
25
|
+
end
|
26
|
+
|
27
|
+
false
|
28
|
+
rescue @type
|
29
|
+
true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# def description
|
34
|
+
# it { expect { Berater.new(:inhibitor) }.not_to be_overrated }
|
35
|
+
|
36
|
+
def failure_message
|
37
|
+
"expected #{@type} to be raised"
|
38
|
+
end
|
39
|
+
|
40
|
+
def failure_message_when_negated
|
41
|
+
"did not expect #{@type} to be raised"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def be_overloaded
|
46
|
+
Overloaded.new(Berater::Overloaded)
|
47
|
+
end
|
48
|
+
|
49
|
+
def be_overrated
|
50
|
+
Overloaded.new(Berater::RateLimiter::Overrated)
|
51
|
+
end
|
52
|
+
|
53
|
+
def be_incapacitated
|
54
|
+
Overloaded.new(Berater::ConcurrencyLimiter::Incapacitated)
|
55
|
+
end
|
56
|
+
|
57
|
+
def be_inhibited
|
58
|
+
Overloaded.new(Berater::Inhibitor::Inhibited)
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'berater'
|
2
|
+
|
3
|
+
module Berater
|
4
|
+
extend self
|
5
|
+
|
6
|
+
attr_reader :test_mode
|
7
|
+
|
8
|
+
def test_mode=(mode)
|
9
|
+
unless [ nil, :pass, :fail ].include?(mode)
|
10
|
+
raise ArgumentError, "invalid mode: #{Berater.test_mode}"
|
11
|
+
end
|
12
|
+
|
13
|
+
@test_mode = mode
|
14
|
+
end
|
15
|
+
|
16
|
+
class Limiter
|
17
|
+
def self.new(*args, **opts)
|
18
|
+
return super unless Berater.test_mode
|
19
|
+
|
20
|
+
# chose a stub class with desired behavior
|
21
|
+
stub_klass = case Berater.test_mode
|
22
|
+
when :pass
|
23
|
+
Berater::Unlimiter
|
24
|
+
when :fail
|
25
|
+
Berater::Inhibitor
|
26
|
+
end
|
27
|
+
|
28
|
+
# don't stub self
|
29
|
+
return super if self < stub_klass
|
30
|
+
|
31
|
+
# swap out limit method with stub
|
32
|
+
super.tap do |instance|
|
33
|
+
stub = stub_klass.allocate
|
34
|
+
stub.send(:initialize, *args, **opts)
|
35
|
+
|
36
|
+
instance.define_singleton_method(:limit) do |&block|
|
37
|
+
stub.limit(&block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/lib/berater/unlimiter.rb
CHANGED
@@ -1,18 +1,22 @@
|
|
1
1
|
module Berater
|
2
|
-
class Unlimiter <
|
2
|
+
class Unlimiter < Limiter
|
3
3
|
|
4
|
-
def initialize(*args, **opts)
|
5
|
-
super(**opts)
|
4
|
+
def initialize(key = :unlimiter, *args, **opts)
|
5
|
+
super(key, **opts)
|
6
6
|
end
|
7
7
|
|
8
|
-
def limit
|
9
|
-
|
10
|
-
return self.class.new(
|
11
|
-
**options.merge(opts)
|
12
|
-
).limit(&block)
|
13
|
-
end
|
8
|
+
def limit
|
9
|
+
lock = Lock.new(self, 0, 0)
|
14
10
|
|
15
|
-
|
11
|
+
if block_given?
|
12
|
+
begin
|
13
|
+
yield lock
|
14
|
+
ensure
|
15
|
+
lock.release
|
16
|
+
end
|
17
|
+
else
|
18
|
+
lock
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
22
|
end
|
data/lib/berater/version.rb
CHANGED
data/spec/berater_spec.rb
CHANGED
@@ -9,10 +9,10 @@ describe Berater do
|
|
9
9
|
describe '.configure' do
|
10
10
|
it 'can be set via configure' do
|
11
11
|
Berater.configure do |c|
|
12
|
-
c.
|
12
|
+
c.redis = :redis
|
13
13
|
end
|
14
14
|
|
15
|
-
expect(Berater.
|
15
|
+
expect(Berater.redis).to eq :redis
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -24,20 +24,13 @@ describe Berater do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
describe '.
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context 'unlimited mode' do
|
34
|
-
before { Berater.mode = :unlimited }
|
35
|
-
|
36
|
-
describe '.new' do
|
37
|
-
let(:limiter) { Berater.new(:unlimited) }
|
27
|
+
describe '.new' do
|
28
|
+
context 'unlimited mode' do
|
29
|
+
let(:limiter) { Berater.new(:key, :unlimited) }
|
38
30
|
|
39
31
|
it 'instantiates an Unlimiter' do
|
40
32
|
expect(limiter).to be_a Berater::Unlimiter
|
33
|
+
expect(limiter.key).to be :key
|
41
34
|
end
|
42
35
|
|
43
36
|
it 'inherits redis' do
|
@@ -46,35 +39,22 @@ describe Berater do
|
|
46
39
|
|
47
40
|
it 'accepts options' do
|
48
41
|
redis = double('Redis')
|
49
|
-
limiter = Berater.new(:
|
50
|
-
expect(limiter.key).to match(/key/)
|
42
|
+
limiter = Berater.new(:key, :unlimited, redis: redis)
|
51
43
|
expect(limiter.redis).to be redis
|
52
44
|
end
|
53
|
-
end
|
54
|
-
|
55
|
-
describe '.limit' do
|
56
|
-
it 'works' do
|
57
|
-
expect(Berater.limit).to be_nil
|
58
|
-
end
|
59
45
|
|
60
|
-
it '
|
61
|
-
expect
|
62
|
-
|
63
|
-
|
64
|
-
it 'never limits' do
|
65
|
-
10.times { expect(Berater.limit { 123 } ).to eq 123 }
|
46
|
+
it 'works with convinience' do
|
47
|
+
expect(Berater).to receive(:new).and_return(limiter)
|
48
|
+
expect {|b| Berater(:key, :unlimited, &b) }.to yield_control
|
66
49
|
end
|
67
50
|
end
|
68
|
-
end
|
69
51
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
describe '.new' do
|
74
|
-
let(:limiter) { Berater.new(:inhibited) }
|
52
|
+
context 'inhibited mode' do
|
53
|
+
let(:limiter) { Berater.new(:key, :inhibited) }
|
75
54
|
|
76
55
|
it 'instantiates an Inhibitor' do
|
77
56
|
expect(limiter).to be_a Berater::Inhibitor
|
57
|
+
expect(limiter.key).to be :key
|
78
58
|
end
|
79
59
|
|
80
60
|
it 'inherits redis' do
|
@@ -83,27 +63,22 @@ describe Berater do
|
|
83
63
|
|
84
64
|
it 'accepts options' do
|
85
65
|
redis = double('Redis')
|
86
|
-
limiter = Berater.new(:
|
87
|
-
expect(limiter.key).to match(/key/)
|
66
|
+
limiter = Berater.new(:key, :inhibited, redis: redis)
|
88
67
|
expect(limiter.redis).to be redis
|
89
68
|
end
|
90
|
-
end
|
91
69
|
|
92
|
-
|
93
|
-
|
94
|
-
expect { Berater
|
70
|
+
it 'works with convinience' do
|
71
|
+
expect(Berater).to receive(:new).and_return(limiter)
|
72
|
+
expect { Berater(:key, :inhibited) }.to be_inhibited
|
95
73
|
end
|
96
74
|
end
|
97
|
-
end
|
98
75
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
describe '.limiter' do
|
103
|
-
let(:limiter) { Berater.new(:rate, 1, :second) }
|
76
|
+
context 'rate mode' do
|
77
|
+
let(:limiter) { Berater.new(:key, :rate, 1, :second) }
|
104
78
|
|
105
79
|
it 'instantiates a RateLimiter' do
|
106
80
|
expect(limiter).to be_a Berater::RateLimiter
|
81
|
+
expect(limiter.key).to be :key
|
107
82
|
end
|
108
83
|
|
109
84
|
it 'inherits redis' do
|
@@ -112,44 +87,22 @@ describe Berater do
|
|
112
87
|
|
113
88
|
it 'accepts options' do
|
114
89
|
redis = double('Redis')
|
115
|
-
limiter = Berater.new(:rate, 1, :second,
|
116
|
-
expect(limiter.key).to match(/key/)
|
90
|
+
limiter = Berater.new(:key, :rate, 1, :second, redis: redis)
|
117
91
|
expect(limiter.redis).to be redis
|
118
92
|
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe '.limit' do
|
122
|
-
it 'works' do
|
123
|
-
expect(Berater.limit(1, :second)).to eq 1
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'yields' do
|
127
|
-
expect {|b| Berater.limit(2, :second, &b) }.to yield_control
|
128
|
-
expect(Berater.limit(2, :second) { 123 }).to eq 123
|
129
|
-
end
|
130
93
|
|
131
|
-
it '
|
132
|
-
expect(Berater.
|
133
|
-
expect { Berater
|
134
|
-
end
|
135
|
-
|
136
|
-
it 'accepts options' do
|
137
|
-
redis = double('Redis')
|
138
|
-
expect(redis).to receive(:multi)
|
139
|
-
|
140
|
-
Berater.limit(1, :second, redis: redis) rescue nil
|
94
|
+
it 'works with convinience' do
|
95
|
+
expect(Berater).to receive(:new).and_return(limiter)
|
96
|
+
expect {|b| Berater(:key, :rate, 1, :second, &b) }.to yield_control
|
141
97
|
end
|
142
98
|
end
|
143
|
-
end
|
144
|
-
|
145
|
-
context 'concurrency mode' do
|
146
|
-
before { Berater.mode = :concurrency }
|
147
99
|
|
148
|
-
|
149
|
-
let(:limiter) { Berater.new(:concurrency, 1) }
|
100
|
+
context 'concurrency mode' do
|
101
|
+
let(:limiter) { Berater.new(:key, :concurrency, 1) }
|
150
102
|
|
151
103
|
it 'instantiates a ConcurrencyLimiter' do
|
152
104
|
expect(limiter).to be_a Berater::ConcurrencyLimiter
|
105
|
+
expect(limiter.key).to be :key
|
153
106
|
end
|
154
107
|
|
155
108
|
it 'inherits redis' do
|
@@ -158,33 +111,59 @@ describe Berater do
|
|
158
111
|
|
159
112
|
it 'accepts options' do
|
160
113
|
redis = double('Redis')
|
161
|
-
limiter = Berater.new(:concurrency, 1,
|
162
|
-
expect(limiter.key).to match(/key/)
|
114
|
+
limiter = Berater.new(:key, :concurrency, 1, redis: redis)
|
163
115
|
expect(limiter.redis).to be redis
|
164
116
|
end
|
117
|
+
|
118
|
+
it 'works with convinience' do
|
119
|
+
expect(Berater).to receive(:new).and_return(limiter)
|
120
|
+
expect {|b| Berater(:key, :concurrency, 1, &b) }.to yield_control
|
121
|
+
end
|
165
122
|
end
|
166
123
|
|
167
|
-
|
168
|
-
it '
|
169
|
-
|
170
|
-
expect(
|
171
|
-
expect(
|
124
|
+
context 'with DSL' do
|
125
|
+
it 'instatiates an Unlimiter' do
|
126
|
+
limiter = Berater.new(:key) { unlimited }
|
127
|
+
expect(limiter).to be_a Berater::Unlimiter
|
128
|
+
expect(limiter.key).to be :key
|
172
129
|
end
|
173
130
|
|
174
|
-
it '
|
175
|
-
|
131
|
+
it 'instatiates an Inhibiter' do
|
132
|
+
limiter = Berater.new(:key) { inhibited }
|
133
|
+
expect(limiter).to be_a Berater::Inhibitor
|
134
|
+
expect(limiter.key).to be :key
|
176
135
|
end
|
177
136
|
|
178
|
-
it '
|
179
|
-
Berater.
|
180
|
-
expect
|
137
|
+
it 'instatiates a RateLimiter' do
|
138
|
+
limiter = Berater.new(:key) { 1.per second }
|
139
|
+
expect(limiter).to be_a Berater::RateLimiter
|
140
|
+
expect(limiter.key).to be :key
|
141
|
+
expect(limiter.count).to be 1
|
142
|
+
expect(limiter.interval).to be :second
|
181
143
|
end
|
182
144
|
|
183
|
-
it '
|
184
|
-
|
185
|
-
expect(
|
145
|
+
it 'instatiates a ConcurrencyLimiter' do
|
146
|
+
limiter = Berater.new(:key, timeout: 2) { 1.at_once }
|
147
|
+
expect(limiter).to be_a Berater::ConcurrencyLimiter
|
148
|
+
expect(limiter.key).to be :key
|
149
|
+
expect(limiter.capacity).to be 1
|
150
|
+
expect(limiter.timeout).to be 2
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'does not accept mode/args and dsl block' do
|
154
|
+
expect {
|
155
|
+
Berater.new(:key, :rate) { 1.per second }
|
156
|
+
}.to raise_error(ArgumentError)
|
157
|
+
|
158
|
+
expect {
|
159
|
+
Berater.new(:key, :concurrency, 2) { 3.at_once }
|
160
|
+
}.to raise_error(ArgumentError)
|
161
|
+
end
|
186
162
|
|
187
|
-
|
163
|
+
it 'requires either mode or dsl block' do
|
164
|
+
expect {
|
165
|
+
Berater.new(:key)
|
166
|
+
}.to raise_error(ArgumentError)
|
188
167
|
end
|
189
168
|
end
|
190
169
|
end
|
@@ -1,22 +1,23 @@
|
|
1
1
|
describe Berater::ConcurrencyLimiter do
|
2
|
-
|
2
|
+
it_behaves_like 'a limiter', described_class.new(:key, 1)
|
3
|
+
it_behaves_like 'a limiter', described_class.new(:key, 1, timeout: 1)
|
3
4
|
|
4
5
|
describe '.new' do
|
5
|
-
let(:limiter) { described_class.new(1) }
|
6
|
+
let(:limiter) { described_class.new(:key, 1) }
|
6
7
|
|
7
8
|
it 'initializes' do
|
9
|
+
expect(limiter.key).to be :key
|
8
10
|
expect(limiter.capacity).to be 1
|
9
11
|
end
|
10
12
|
|
11
13
|
it 'has default values' do
|
12
|
-
expect(limiter.key).to eq described_class.to_s
|
13
14
|
expect(limiter.redis).to be Berater.redis
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
18
|
describe '#capacity' do
|
18
19
|
def expect_capacity(capacity)
|
19
|
-
limiter = described_class.new(capacity)
|
20
|
+
limiter = described_class.new(:key, capacity)
|
20
21
|
expect(limiter.capacity).to eq capacity
|
21
22
|
end
|
22
23
|
|
@@ -27,7 +28,7 @@ describe Berater::ConcurrencyLimiter do
|
|
27
28
|
context 'with erroneous values' do
|
28
29
|
def expect_bad_capacity(capacity)
|
29
30
|
expect do
|
30
|
-
described_class.new(capacity)
|
31
|
+
described_class.new(:key, capacity)
|
31
32
|
end.to raise_error ArgumentError
|
32
33
|
end
|
33
34
|
|
@@ -40,7 +41,7 @@ describe Berater::ConcurrencyLimiter do
|
|
40
41
|
|
41
42
|
describe '#timeout' do
|
42
43
|
def expect_timeout(timeout)
|
43
|
-
limiter = described_class.new(1, timeout: timeout)
|
44
|
+
limiter = described_class.new(:key, 1, timeout: timeout)
|
44
45
|
expect(limiter.timeout).to eq timeout
|
45
46
|
end
|
46
47
|
|
@@ -51,7 +52,7 @@ describe Berater::ConcurrencyLimiter do
|
|
51
52
|
context 'with erroneous values' do
|
52
53
|
def expect_bad_timeout(timeout)
|
53
54
|
expect do
|
54
|
-
described_class.new(1, timeout: timeout)
|
55
|
+
described_class.new(:key, 1, timeout: timeout)
|
55
56
|
end.to raise_error ArgumentError
|
56
57
|
end
|
57
58
|
|
@@ -63,126 +64,114 @@ describe Berater::ConcurrencyLimiter do
|
|
63
64
|
end
|
64
65
|
|
65
66
|
describe '#limit' do
|
66
|
-
let(:limiter) { described_class.new(
|
67
|
+
let(:limiter) { described_class.new(:key, 2) }
|
67
68
|
|
68
69
|
it 'works' do
|
69
70
|
expect {|b| limiter.limit(&b) }.to yield_control
|
70
71
|
end
|
71
72
|
|
72
|
-
it 'works many times if workers
|
73
|
+
it 'works many times if workers release locks' do
|
73
74
|
30.times do
|
74
75
|
expect {|b| limiter.limit(&b) }.to yield_control
|
75
76
|
end
|
77
|
+
|
78
|
+
30.times do
|
79
|
+
lock = limiter.limit
|
80
|
+
lock.release
|
81
|
+
end
|
76
82
|
end
|
77
83
|
|
78
84
|
it 'limits excessive calls' do
|
79
|
-
expect(limiter.limit).to be_a Berater::
|
80
|
-
expect(limiter.limit).to be_a Berater::
|
85
|
+
expect(limiter.limit).to be_a Berater::Lock
|
86
|
+
expect(limiter.limit).to be_a Berater::Lock
|
81
87
|
|
82
|
-
expect
|
88
|
+
expect(limiter).to be_incapacitated
|
83
89
|
end
|
84
90
|
|
85
|
-
|
86
|
-
|
87
|
-
expect(limiter.limit).to be_a Berater::ConcurrencyLimiter::Lock
|
88
|
-
expect { limiter }.to be_incapacitated
|
91
|
+
context 'with capacity 0' do
|
92
|
+
let(:limiter) { described_class.new(:key, 0) }
|
89
93
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
expect(limiter.limit).to be_a Berater::ConcurrencyLimiter::Lock
|
94
|
-
expect { limiter }.to be_incapacitated
|
94
|
+
it 'always fails' do
|
95
|
+
expect(limiter).to be_incapacitated
|
96
|
+
end
|
95
97
|
end
|
96
98
|
end
|
97
99
|
|
98
100
|
context 'with same key, different limiters' do
|
99
|
-
let(:limiter_one) { described_class.new(1) }
|
100
|
-
let(:limiter_two) { described_class.new(1) }
|
101
|
+
let(:limiter_one) { described_class.new(:key, 1) }
|
102
|
+
let(:limiter_two) { described_class.new(:key, 1) }
|
101
103
|
|
102
104
|
it { expect(limiter_one.key).to eq limiter_two.key }
|
103
105
|
|
104
106
|
it 'works as expected' do
|
105
|
-
expect(limiter_one.limit).to be_a Berater::
|
107
|
+
expect(limiter_one.limit).to be_a Berater::Lock
|
106
108
|
|
107
|
-
expect
|
108
|
-
expect
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
context 'with different keys, same limiter' do
|
113
|
-
let(:limiter) { described_class.new(1) }
|
114
|
-
|
115
|
-
it 'works as expected' do
|
116
|
-
one_lock = limiter.limit(key: :one)
|
117
|
-
expect(one_lock).to be_a Berater::ConcurrencyLimiter::Lock
|
118
|
-
|
119
|
-
expect { limiter.limit(key: :one) {} }.to be_incapacitated
|
120
|
-
expect { limiter.limit(key: :two) {} }.not_to be_incapacitated
|
121
|
-
|
122
|
-
two_lock = limiter.limit(key: :two)
|
123
|
-
expect(two_lock).to be_a Berater::ConcurrencyLimiter::Lock
|
124
|
-
|
125
|
-
expect { limiter.limit(key: :one) {} }.to be_incapacitated
|
126
|
-
expect { limiter.limit(key: :two) {} }.to be_incapacitated
|
127
|
-
|
128
|
-
one_lock.release
|
129
|
-
expect { limiter.limit(key: :one) {} }.not_to be_incapacitated
|
130
|
-
expect { limiter.limit(key: :two) {} }.to be_incapacitated
|
131
|
-
|
132
|
-
two_lock.release
|
133
|
-
expect { limiter.limit(key: :one) {} }.not_to be_incapacitated
|
134
|
-
expect { limiter.limit(key: :two) {} }.not_to be_incapacitated
|
109
|
+
expect(limiter_one).to be_incapacitated
|
110
|
+
expect(limiter_two).to be_incapacitated
|
135
111
|
end
|
136
112
|
end
|
137
113
|
|
138
114
|
context 'with same key, different capacities' do
|
139
|
-
let(:limiter_one) { described_class.new(1) }
|
140
|
-
let(:limiter_two) { described_class.new(2) }
|
115
|
+
let(:limiter_one) { described_class.new(:key, 1) }
|
116
|
+
let(:limiter_two) { described_class.new(:key, 2) }
|
141
117
|
|
142
118
|
it { expect(limiter_one.capacity).not_to eq limiter_two.capacity }
|
143
119
|
|
144
120
|
it 'works as expected' do
|
145
121
|
one_lock = limiter_one.limit
|
146
|
-
expect(one_lock).to be_a Berater::
|
122
|
+
expect(one_lock).to be_a Berater::Lock
|
147
123
|
|
148
|
-
expect
|
149
|
-
expect
|
124
|
+
expect(limiter_one).to be_incapacitated
|
125
|
+
expect(limiter_two).not_to be_incapacitated
|
150
126
|
|
151
127
|
two_lock = limiter_two.limit
|
152
|
-
expect(two_lock).to be_a Berater::
|
128
|
+
expect(two_lock).to be_a Berater::Lock
|
153
129
|
|
154
|
-
expect
|
155
|
-
expect
|
130
|
+
expect(limiter_one).to be_incapacitated
|
131
|
+
expect(limiter_two).to be_incapacitated
|
156
132
|
|
157
133
|
one_lock.release
|
158
|
-
expect
|
159
|
-
expect
|
134
|
+
expect(limiter_one).to be_incapacitated
|
135
|
+
expect(limiter_two).not_to be_incapacitated
|
160
136
|
|
161
137
|
two_lock.release
|
162
|
-
expect
|
163
|
-
expect
|
138
|
+
expect(limiter_one).not_to be_incapacitated
|
139
|
+
expect(limiter_two).not_to be_incapacitated
|
164
140
|
end
|
165
141
|
end
|
166
142
|
|
167
143
|
context 'with different keys, different limiters' do
|
168
|
-
let(:limiter_one) { described_class.new(
|
169
|
-
let(:limiter_two) { described_class.new(
|
144
|
+
let(:limiter_one) { described_class.new(:one, 1) }
|
145
|
+
let(:limiter_two) { described_class.new(:two, 1) }
|
170
146
|
|
171
147
|
it 'works as expected' do
|
172
|
-
expect
|
173
|
-
expect
|
148
|
+
expect(limiter_one).not_to be_incapacitated
|
149
|
+
expect(limiter_two).not_to be_incapacitated
|
174
150
|
|
175
151
|
one_lock = limiter_one.limit
|
176
|
-
expect(one_lock).to be_a Berater::
|
152
|
+
expect(one_lock).to be_a Berater::Lock
|
177
153
|
|
178
|
-
expect
|
179
|
-
expect
|
154
|
+
expect(limiter_one).to be_incapacitated
|
155
|
+
expect(limiter_two).not_to be_incapacitated
|
180
156
|
|
181
157
|
two_lock = limiter_two.limit
|
182
|
-
expect(two_lock).to be_a Berater::
|
158
|
+
expect(two_lock).to be_a Berater::Lock
|
183
159
|
|
184
|
-
expect
|
185
|
-
expect
|
160
|
+
expect(limiter_one).to be_incapacitated
|
161
|
+
expect(limiter_two).to be_incapacitated
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#to_s' do
|
166
|
+
def check(capacity, expected)
|
167
|
+
expect(
|
168
|
+
described_class.new(:key, capacity).to_s
|
169
|
+
).to match(expected)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'works' do
|
173
|
+
check(1, /1 at a time/)
|
174
|
+
check(3, /3 at a time/)
|
186
175
|
end
|
187
176
|
end
|
188
177
|
|