@@ -4,50 +4,140 @@ module Concurrent
4
4
5
5
context '#with_read_lock' do
6
6
7
- it 'acquires the lock'
8
-
9
- it 'returns the value of the block operation'
10
-
11
- it 'releases the lock'
12
-
13
- it 'raises an exception if no block is given'
14
-
15
- it 'raises an exception if maximum lock limit is exceeded'
16
-
17
- it 'does not release the lock when an exception is raised'
7
+ it 'acquires the lock' do
8
+ expect ( subject ) . to receive ( :acquire_read_lock ) . with ( no_args )
9
+ subject . with_read_lock { nil }
10
+ end
11
+
12
+ it 'returns the value of the block operation' do
13
+ expected = 100
14
+ actual = subject . with_read_lock { expected }
15
+ expect ( actual ) . to eq expected
16
+ end
17
+
18
+ it 'releases the lock' do
19
+ expect ( subject ) . to receive ( :release_read_lock ) . with ( no_args )
20
+ subject . with_read_lock { nil }
21
+ end
22
+
23
+ it 'raises an exception if no block is given' do
24
+ expect {
25
+ subject . with_read_lock
26
+ } . to raise_error ( ArgumentError )
27
+ end
28
+
29
+ it 'raises an exception if maximum lock limit is exceeded' do
30
+ counter = Concurrent ::Atomic . new ( ReadWriteLock ::MAX_READERS )
31
+ allow ( Concurrent ::Atomic ) . to receive ( :new ) . with ( anything ) . and_return ( counter )
32
+ expect {
33
+ subject . with_read_lock { nil }
34
+ } . to raise_error ( Concurrent ::ResourceLimitError )
35
+ end
36
+
37
+ it 'does not release the lock when an exception is raised' do
38
+ expect ( subject ) . to_not receive ( :release_read_lock ) . with ( any_args )
39
+ lambda do
40
+ subject . with_read_lock { raise StandardError }
41
+ end
42
+ end
18
43
end
19
44
20
45
context '#with_write_lock' do
21
46
22
- it 'acquires the lock'
23
-
24
- it 'returns the value of the block operation'
25
-
26
- it 'releases the lock'
27
-
28
- it 'raises an exception if no block is given'
29
-
30
- it 'raises an exception if maximum lock limit is exceeded'
31
-
32
- it 'does not release the lock when an exception is raised'
47
+ it 'acquires the lock' do
48
+ expect ( subject ) . to receive ( :acquire_write_lock ) . with ( no_args )
49
+ subject . with_write_lock { nil }
50
+ end
51
+
52
+ it 'returns the value of the block operation' do
53
+ expected = 100
54
+ actual = subject . with_write_lock { expected }
55
+ expect ( actual ) . to eq expected
56
+ end
57
+
58
+ it 'releases the lock' do
59
+ expect ( subject ) . to receive ( :release_write_lock ) . with ( no_args )
60
+ subject . with_write_lock { nil }
61
+ end
62
+
63
+ it 'raises an exception if no block is given' do
64
+ expect {
65
+ subject . with_write_lock
66
+ } . to raise_error ( ArgumentError )
67
+ end
68
+
69
+ it 'raises an exception if maximum lock limit is exceeded' do
70
+ counter = Concurrent ::Atomic . new ( ReadWriteLock ::MAX_WRITERS )
71
+ allow ( Concurrent ::Atomic ) . to receive ( :new ) . with ( anything ) . and_return ( counter )
72
+ expect {
73
+ subject . with_write_lock { nil }
74
+ } . to raise_error ( Concurrent ::ResourceLimitError )
75
+ end
76
+
77
+ it 'does not release the lock when an exception is raised' do
78
+ expect ( subject ) . to_not receive ( :release_write_lock ) . with ( any_args )
79
+ lambda do
80
+ subject . with_write_lock { raise StandardError }
81
+ end
82
+ end
33
83
end
34
84
35
85
context '#acquire_read_lock' do
36
86
37
- it 'increments the lock count'
38
-
39
- it 'waits for a running writer to finish'
40
-
41
- it 'does not wait for any running readers'
42
-
43
- it 'raises an exception if maximum lock limit is exceeded'
87
+ it 'increments the lock count' do
88
+ counter = Concurrent ::Atomic . new ( 0 )
89
+ allow ( Concurrent ::Atomic ) . to receive ( :new ) . with ( anything ) . and_return ( counter )
90
+ subject . acquire_read_lock
91
+ expect ( counter . value ) . to eq 1
92
+ end
93
+
94
+ it 'waits for a running writer to finish' do
95
+ pending ( 'need to figure out the timing' )
96
+ expect ( true ) . to be false
97
+ end
98
+
99
+ it 'does not wait for any running readers' do
100
+ pending ( 'need to figure out the timing' )
101
+ expect ( true ) . to be false
102
+ end
103
+
104
+ it 'raises an exception if maximum lock limit is exceeded' do
105
+ counter = Concurrent ::Atomic . new ( ReadWriteLock ::MAX_WRITERS )
106
+ allow ( Concurrent ::Atomic ) . to receive ( :new ) . with ( anything ) . and_return ( counter )
107
+ expect {
108
+ subject . acquire_write_lock { nil }
109
+ } . to raise_error ( Concurrent ::ResourceLimitError )
110
+ end
111
+
112
+ it 'returns true if the lock is acquired' do
113
+ expect ( subject . acquire_read_lock ) . to be true
114
+ end
44
115
end
45
116
46
117
context '#release_read_lock' do
47
118
48
- it 'decrements the counter'
49
-
50
- it 'unblocks running writers'
119
+ it 'decrements the counter' do
120
+ counter = Concurrent ::Atomic . new ( 0 )
121
+ allow ( Concurrent ::Atomic ) . to receive ( :new ) . with ( anything ) . and_return ( counter )
122
+ subject . acquire_read_lock
123
+ expect ( counter . value ) . to eq 1
124
+ subject . release_read_lock
125
+ expect ( counter . value ) . to eq 0
126
+ end
127
+
128
+ it 'unblocks running writers' do
129
+ pending ( 'need to figure out the timing' )
130
+ expect ( true ) . to be false
131
+ end
132
+
133
+ it 'returns true if the lock is released' do
134
+ subject . acquire_read_lock
135
+ expect ( subject . release_read_lock ) . to be true
136
+ end
137
+
138
+ it 'returns true if the lock was never set' do
139
+ expect ( subject . release_read_lock ) . to be true
140
+ end
51
141
end
52
142
53
143
context '#acquire_write_lock' do
@@ -59,24 +149,77 @@ module Concurrent
59
149
it 'waits for a running reader to finish'
60
150
61
151
it 'raises an exception if maximum lock limit is exceeded'
152
+
153
+ it 'returns true if the lock is acquired'
62
154
end
63
155
64
156
context '#release_write_lock' do
65
157
66
- it 'decrements the counter'
67
-
68
- it 'unblocks running readers'
69
-
70
- it 'unblocks running writers'
158
+ it 'decrements the counter' do
159
+ counter = Concurrent ::Atomic . new ( 0 )
160
+ allow ( Concurrent ::Atomic ) . to receive ( :new ) . with ( anything ) . and_return ( counter )
161
+ subject . acquire_write_lock
162
+ expect ( counter . value ) . to be > 1
163
+ subject . release_write_lock
164
+ expect ( counter . value ) . to eq 0
165
+ end
166
+
167
+ it 'unblocks running readers' do
168
+ pending ( 'need to figure out the timing' )
169
+ expect ( true ) . to be false
170
+ end
171
+
172
+ it 'unblocks running writers' do
173
+ pending ( 'need to figure out the timing' )
174
+ expect ( true ) . to be false
175
+ end
176
+
177
+ it 'returns true if the lock is released' do
178
+ subject . acquire_write_lock
179
+ expect ( subject . release_write_lock ) . to be true
180
+ end
181
+
182
+ it 'returns true if the lock was never set' do
183
+ expect ( subject . release_write_lock ) . to be true
184
+ end
71
185
end
72
186
73
187
context '#to_s' do
74
188
75
- it 'includes the running reader count'
76
-
77
- it 'includes the running writer count'
78
-
79
- it 'includes the waiting writer count'
189
+ it 'includes the running reader count' do
190
+ subject . with_read_lock do
191
+ expect ( subject . to_s ) . to match ( /1 readers running/ )
192
+ end
193
+ expect ( subject . to_s ) . to_not match ( /readers running/ )
194
+ end
195
+
196
+ it 'includes the running writer count' do
197
+ subject . with_write_lock do
198
+ expect ( subject . to_s ) . to match ( /1 writer running/ )
199
+ end
200
+ expect ( subject . to_s ) . to_not match ( /writer running/ )
201
+ end
202
+
203
+ it 'includes the waiting writer count' do
204
+ start_latch = Concurrent ::CountDownLatch . new ( 1 )
205
+ end_latch = Concurrent ::CountDownLatch . new ( 1 )
206
+
207
+ thread = Thread . new do
208
+ start_latch . wait ( 1 )
209
+ subject . acquire_write_lock
210
+ subject . release_write_lock
211
+ end_latch . count_down
212
+ end
213
+
214
+ subject . with_write_lock do
215
+ start_latch . count_down
216
+ sleep ( 0.1 )
217
+ expect ( subject . to_s ) . to match ( /1 writers waiting/ )
218
+ end
219
+ expect ( subject . to_s ) . to match ( /1 writers waiting/ )
220
+ end_latch . wait ( 1 )
221
+ expect ( subject . to_s ) . to match ( /0 writers waiting/ )
222
+ end
80
223
end
81
224
end
82
225
end
0 commit comments