View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.commons.concurrent;
18  
19  import static org.junit.jupiter.api.Assertions.*;
20  
21  import org.apache.juneau.*;
22  import org.junit.jupiter.api.*;
23  
24  /**
25   * Tests for {@link SimpleReadWriteLock}.
26   */
27  class SimpleReadWriteLock_Test extends TestBase {
28  
29  	//====================================================================================================
30  	// NO_OP static field tests
31  	//====================================================================================================
32  
33  	@Test
34  	void a01_noOp_exists() {
35  		assertNotNull(SimpleReadWriteLock.NO_OP);
36  	}
37  
38  	@Test
39  	void a02_noOp_readReturnsNoOp() {
40  		var lock = SimpleReadWriteLock.NO_OP.read();
41  		assertSame(SimpleLock.NO_OP, lock);
42  	}
43  
44  	@Test
45  	void a03_noOp_writeReturnsNoOp() {
46  		var lock = SimpleReadWriteLock.NO_OP.write();
47  		assertSame(SimpleLock.NO_OP, lock);
48  	}
49  
50  	@Test
51  	void a04_noOp_closeDoesNotThrow() throws Exception {
52  		var lock = SimpleReadWriteLock.NO_OP.read();
53  		// Should not throw when closing NO_OP lock
54  		assertDoesNotThrow(() -> lock.close());
55  	}
56  
57  	//====================================================================================================
58  	// Constructor tests
59  	//====================================================================================================
60  
61  	@Test
62  	void b01_constructor_default() {
63  		var lock = new SimpleReadWriteLock();
64  		assertNotNull(lock);
65  		assertFalse(lock.isFair());
66  	}
67  
68  	@Test
69  	void b02_constructor_fair() {
70  		var lock = new SimpleReadWriteLock(true);
71  		assertNotNull(lock);
72  		assertTrue(lock.isFair());
73  	}
74  
75  	@Test
76  	void b03_constructor_unfair() {
77  		var lock = new SimpleReadWriteLock(false);
78  		assertNotNull(lock);
79  		assertFalse(lock.isFair());
80  	}
81  
82  	//====================================================================================================
83  	// read() tests
84  	//====================================================================================================
85  
86  	@Test
87  	void c01_read_returnsSimpleLock() {
88  		var rwLock = new SimpleReadWriteLock();
89  		var lock = rwLock.read();
90  		assertNotNull(lock);
91  		assertInstanceOf(SimpleLock.class, lock);
92  	}
93  
94  	@Test
95  	void c02_read_returnsNewInstance() {
96  		var rwLock = new SimpleReadWriteLock();
97  		var lock1 = rwLock.read();
98  		var lock2 = rwLock.read();
99  		assertNotSame(lock1, lock2);
100 	}
101 
102 	@Test
103 	void c03_read_canClose() throws Exception {
104 		var rwLock = new SimpleReadWriteLock();
105 		var lock = rwLock.read();
106 		// Should not throw when closing
107 		assertDoesNotThrow(() -> lock.close());
108 	}
109 
110 	@Test
111 	void c04_read_multipleCalls() {
112 		var rwLock = new SimpleReadWriteLock();
113 		var lock1 = rwLock.read();
114 		var lock2 = rwLock.read();
115 		var lock3 = rwLock.read();
116 		assertNotNull(lock1);
117 		assertNotNull(lock2);
118 		assertNotNull(lock3);
119 	}
120 
121 	//====================================================================================================
122 	// write() tests
123 	//====================================================================================================
124 
125 	@Test
126 	void d01_write_returnsSimpleLock() {
127 		var rwLock = new SimpleReadWriteLock();
128 		var lock = rwLock.write();
129 		assertNotNull(lock);
130 		assertInstanceOf(SimpleLock.class, lock);
131 	}
132 
133 	@Test
134 	void d02_write_returnsNewInstance() {
135 		var rwLock = new SimpleReadWriteLock();
136 		var lock1 = rwLock.write();
137 		var lock2 = rwLock.write();
138 		assertNotSame(lock1, lock2);
139 	}
140 
141 	@Test
142 	void d03_write_canClose() throws Exception {
143 		var rwLock = new SimpleReadWriteLock();
144 		var lock = rwLock.write();
145 		// Should not throw when closing
146 		assertDoesNotThrow(() -> lock.close());
147 	}
148 
149 	@Test
150 	void d04_write_multipleCalls() {
151 		var rwLock = new SimpleReadWriteLock();
152 		var lock1 = rwLock.write();
153 		var lock2 = rwLock.write();
154 		var lock3 = rwLock.write();
155 		assertNotNull(lock1);
156 		assertNotNull(lock2);
157 		assertNotNull(lock3);
158 	}
159 
160 	//====================================================================================================
161 	// read() and write() interaction tests
162 	//====================================================================================================
163 
164 	@Test
165 	void e01_readAndWrite_differentInstances() throws Exception {
166 		var rwLock = new SimpleReadWriteLock();
167 		var readLock = rwLock.read();
168 		readLock.close();  // Release read lock before acquiring write lock
169 		var writeLock = rwLock.write();
170 		assertNotSame(readLock, writeLock);
171 		writeLock.close();  // Clean up
172 	}
173 
174 	@Test
175 	void e02_readAndWrite_bothCanBeCreated() throws Exception {
176 		var rwLock = new SimpleReadWriteLock();
177 		var readLock = rwLock.read();
178 		readLock.close();  // Release read lock before acquiring write lock
179 		var writeLock = rwLock.write();
180 		assertNotNull(readLock);
181 		assertNotNull(writeLock);
182 		writeLock.close();  // Clean up
183 	}
184 
185 	@Test
186 	void e03_readAndWrite_bothCanBeClosed() throws Exception {
187 		var rwLock = new SimpleReadWriteLock();
188 		var readLock = rwLock.read();
189 		readLock.close();  // Release read lock before acquiring write lock
190 		var writeLock = rwLock.write();
191 		assertDoesNotThrow(() -> writeLock.close());
192 		// Both locks have been closed successfully
193 	}
194 
195 	//====================================================================================================
196 	// Inherited ReentrantReadWriteLock methods tests
197 	//====================================================================================================
198 
199 	@Test
200 	void f01_isFair_default() {
201 		var lock = new SimpleReadWriteLock();
202 		assertFalse(lock.isFair());
203 	}
204 
205 	@Test
206 	void f02_isFair_explicit() {
207 		var fairLock = new SimpleReadWriteLock(true);
208 		var unfairLock = new SimpleReadWriteLock(false);
209 		assertTrue(fairLock.isFair());
210 		assertFalse(unfairLock.isFair());
211 	}
212 
213 	@Test
214 	void f03_getReadLockCount_initial() {
215 		var lock = new SimpleReadWriteLock();
216 		assertEquals(0, lock.getReadLockCount());
217 	}
218 
219 	@Test
220 	void f04_getWriteHoldCount_initial() {
221 		var lock = new SimpleReadWriteLock();
222 		assertEquals(0, lock.getWriteHoldCount());
223 	}
224 
225 	@Test
226 	void f05_isWriteLocked_initial() {
227 		var lock = new SimpleReadWriteLock();
228 		assertFalse(lock.isWriteLocked());
229 	}
230 
231 	@Test
232 	void f06_isWriteLockedByCurrentThread_initial() {
233 		var lock = new SimpleReadWriteLock();
234 		assertFalse(lock.isWriteLockedByCurrentThread());
235 	}
236 
237 	@Test
238 	void f07_getReadHoldCount_initial() {
239 		var lock = new SimpleReadWriteLock();
240 		assertEquals(0, lock.getReadHoldCount());
241 	}
242 
243 	@Test
244 	void f08_getQueueLength_initial() {
245 		var lock = new SimpleReadWriteLock();
246 		assertEquals(0, lock.getQueueLength());
247 	}
248 
249 	@Test
250 	void f09_hasQueuedThreads_initial() {
251 		var lock = new SimpleReadWriteLock();
252 		assertFalse(lock.hasQueuedThreads());
253 	}
254 
255 	@Test
256 	void f10_hasQueuedThread_currentThread() {
257 		var lock = new SimpleReadWriteLock();
258 		assertFalse(lock.hasQueuedThread(Thread.currentThread()));
259 	}
260 
261 	@Test
262 	void f11_getReadLockCount_afterRead() throws Exception {
263 		var lock = new SimpleReadWriteLock();
264 		var readLock = lock.read();
265 		// After acquiring read lock, count should be > 0
266 		assertTrue(lock.getReadLockCount() > 0);
267 		readLock.close();
268 	}
269 
270 	@Test
271 	void f12_isWriteLocked_afterWrite() throws Exception {
272 		var lock = new SimpleReadWriteLock();
273 		var writeLock = lock.write();
274 		// After acquiring write lock, should be write locked
275 		assertTrue(lock.isWriteLocked());
276 		writeLock.close();
277 	}
278 
279 	@Test
280 	void f13_isWriteLockedByCurrentThread_afterWrite() throws Exception {
281 		var lock = new SimpleReadWriteLock();
282 		var writeLock = lock.write();
283 		// After acquiring write lock, current thread should hold it
284 		assertTrue(lock.isWriteLockedByCurrentThread());
285 		writeLock.close();
286 	}
287 
288 	@Test
289 	void f14_getReadHoldCount_afterRead() throws Exception {
290 		var lock = new SimpleReadWriteLock();
291 		var readLock = lock.read();
292 		// After acquiring read lock, hold count should be > 0
293 		assertTrue(lock.getReadHoldCount() > 0);
294 		readLock.close();
295 	}
296 
297 	@Test
298 	void f15_getWriteHoldCount_afterWrite() throws Exception {
299 		var lock = new SimpleReadWriteLock();
300 		var writeLock = lock.write();
301 		// After acquiring write lock, hold count should be > 0
302 		assertTrue(lock.getWriteHoldCount() > 0);
303 		writeLock.close();
304 	}
305 
306 	//====================================================================================================
307 	// try-with-resources tests
308 	//====================================================================================================
309 
310 	@Test
311 	void g01_tryWithResources_read() throws Exception {
312 		var lock = new SimpleReadWriteLock();
313 		try (var readLock = lock.read()) {
314 			assertNotNull(readLock);
315 			assertTrue(lock.getReadLockCount() > 0);
316 		}
317 		// After try-with-resources, lock should be released
318 		assertEquals(0, lock.getReadLockCount());
319 	}
320 
321 	@Test
322 	void g02_tryWithResources_write() throws Exception {
323 		var lock = new SimpleReadWriteLock();
324 		try (var writeLock = lock.write()) {
325 			assertNotNull(writeLock);
326 			assertTrue(lock.isWriteLocked());
327 		}
328 		// After try-with-resources, lock should be released
329 		assertFalse(lock.isWriteLocked());
330 	}
331 
332 	@Test
333 	void g03_tryWithResources_readAndWrite() throws Exception {
334 		var lock = new SimpleReadWriteLock();
335 		try (var readLock = lock.read()) {
336 			assertNotNull(readLock);
337 		}
338 		// Read lock is released, now we can acquire write lock
339 		try (var writeLock = lock.write()) {
340 			assertNotNull(writeLock);
341 		}
342 		// After try-with-resources, locks should be released
343 		assertEquals(0, lock.getReadLockCount());
344 		assertFalse(lock.isWriteLocked());
345 	}
346 
347 	//====================================================================================================
348 	// Edge cases
349 	//====================================================================================================
350 
351 	@Test
352 	void h01_edgeCase_multipleReadLocks() throws Exception {
353 		var lock = new SimpleReadWriteLock();
354 		var readLock1 = lock.read();
355 		var readLock2 = lock.read();
356 		var readLock3 = lock.read();
357 		assertNotNull(readLock1);
358 		assertNotNull(readLock2);
359 		assertNotNull(readLock3);
360 		readLock1.close();
361 		readLock2.close();
362 		readLock3.close();
363 	}
364 
365 	@Test
366 	void h02_edgeCase_multipleWriteLocks() throws Exception {
367 		var lock = new SimpleReadWriteLock();
368 		var writeLock1 = lock.write();
369 		writeLock1.close();
370 		var writeLock2 = lock.write();
371 		writeLock2.close();
372 		var writeLock3 = lock.write();
373 		writeLock3.close();
374 		// All should work
375 		assertFalse(lock.isWriteLocked());
376 	}
377 
378 	@Test
379 	void h03_edgeCase_fairLock() throws Exception {
380 		var lock = new SimpleReadWriteLock(true);
381 		assertTrue(lock.isFair());
382 		var readLock = lock.read();
383 		assertNotNull(readLock);
384 		readLock.close();  // Release read lock before acquiring write lock
385 		var writeLock = lock.write();
386 		assertNotNull(writeLock);
387 		writeLock.close();
388 	}
389 
390 	@Test
391 	void h04_edgeCase_unfairLock() throws Exception {
392 		var lock = new SimpleReadWriteLock(false);
393 		assertFalse(lock.isFair());
394 		var readLock = lock.read();
395 		assertNotNull(readLock);
396 		readLock.close();  // Release read lock before acquiring write lock
397 		var writeLock = lock.write();
398 		assertNotNull(writeLock);
399 		writeLock.close();
400 	}
401 }
402