1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.named;
20
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.concurrent.CountDownLatch;
24 import java.util.concurrent.TimeUnit;
25
26 import org.eclipse.aether.named.support.LockUpgradeNotSupportedException;
27 import org.junit.jupiter.api.Test;
28 import org.junit.jupiter.api.TestInfo;
29 import org.junit.jupiter.api.Timeout;
30
31 import static org.junit.jupiter.api.Assertions.*;
32
33
34
35
36 public abstract class NamedLockFactoryTestSupport {
37
38 protected static NamedLockFactory namedLockFactory;
39
40 protected Collection<NamedLockKey> lockName(TestInfo testInfo) {
41 return Collections.singleton(NamedLockKey.of(testInfo.getDisplayName()));
42 }
43
44 @Test
45 void testFailure(TestInfo testInfo) throws InterruptedException {
46
47
48 assertThrows(IllegalStateException.class, () -> {
49 Thread t1 = new Thread(() -> {
50 try {
51 namedLockFactory.getLock(lockName(testInfo)).lockShared(1L, TimeUnit.MINUTES);
52 namedLockFactory.getLock(lockName(testInfo)).lockShared(1L, TimeUnit.MINUTES);
53 } catch (InterruptedException e) {
54 throw new RuntimeException(e);
55 }
56 });
57 Thread t2 = new Thread(() -> {
58 try {
59 namedLockFactory.getLock(lockName(testInfo)).lockShared(1L, TimeUnit.MINUTES);
60 namedLockFactory.getLock(lockName(testInfo)).lockShared(1L, TimeUnit.MINUTES);
61 namedLockFactory.getLock(lockName(testInfo)).lockShared(1L, TimeUnit.MINUTES);
62 } catch (InterruptedException e) {
63 throw new RuntimeException(e);
64 }
65 });
66 t1.start();
67 t2.start();
68 t1.join();
69 t2.join();
70 throw namedLockFactory.onFailure(new IllegalStateException("failure"));
71 });
72 }
73
74 @Test
75 void refCounting(TestInfo testInfo) {
76 final Collection<NamedLockKey> keys = lockName(testInfo);
77 try (NamedLock one = namedLockFactory.getLock(keys);
78 NamedLock two = namedLockFactory.getLock(keys)) {
79 assertSame(one, two);
80 one.close();
81 two.close();
82
83 try (NamedLock three = namedLockFactory.getLock(keys)) {
84 assertNotSame(three, two);
85 }
86 }
87 }
88
89 @Test
90 void unlockWoLock(TestInfo testInfo) {
91 assertThrows(IllegalStateException.class, () -> {
92 final Collection<NamedLockKey> keys = lockName(testInfo);
93 try (NamedLock one = namedLockFactory.getLock(keys)) {
94 one.unlock();
95 }
96 });
97 }
98
99 @Test
100 void wwBoxing(TestInfo testInfo) throws InterruptedException {
101 final Collection<NamedLockKey> keys = lockName(testInfo);
102 try (NamedLock one = namedLockFactory.getLock(keys)) {
103 assertTrue(one.lockExclusively(1L, TimeUnit.MILLISECONDS));
104 assertTrue(one.lockExclusively(1L, TimeUnit.MILLISECONDS));
105 one.unlock();
106 one.unlock();
107 }
108 }
109
110 @Test
111 void rrBoxing(TestInfo testInfo) throws InterruptedException {
112 final Collection<NamedLockKey> keys = lockName(testInfo);
113 try (NamedLock one = namedLockFactory.getLock(keys)) {
114 assertTrue(one.lockShared(1L, TimeUnit.MILLISECONDS));
115 assertTrue(one.lockShared(1L, TimeUnit.MILLISECONDS));
116 one.unlock();
117 one.unlock();
118 }
119 }
120
121 @Test
122 void wrBoxing(TestInfo testInfo) throws InterruptedException {
123 final Collection<NamedLockKey> keys = lockName(testInfo);
124 try (NamedLock one = namedLockFactory.getLock(keys)) {
125 assertTrue(one.lockExclusively(1L, TimeUnit.MILLISECONDS));
126 assertTrue(one.lockShared(1L, TimeUnit.MILLISECONDS));
127 one.unlock();
128 one.unlock();
129 }
130 }
131
132 @Test
133 void rwBoxing(TestInfo testInfo) throws InterruptedException {
134 final Collection<NamedLockKey> keys = lockName(testInfo);
135 try (NamedLock one = namedLockFactory.getLock(keys)) {
136 assertTrue(one.lockShared(1L, TimeUnit.MILLISECONDS));
137 try {
138 one.lockExclusively(1L, TimeUnit.MILLISECONDS);
139 fail();
140 } catch (LockUpgradeNotSupportedException e) {
141
142 }
143 one.unlock();
144 }
145 }
146
147 @Test
148 @Timeout(5)
149 public void sharedAccess(TestInfo testInfo) throws InterruptedException {
150 final Collection<NamedLockKey> keys = lockName(testInfo);
151 CountDownLatch winners = new CountDownLatch(2);
152 CountDownLatch losers = new CountDownLatch(0);
153 Thread t1 = new Thread(new Access(namedLockFactory, keys, true, winners, losers));
154 Thread t2 = new Thread(new Access(namedLockFactory, keys, true, winners, losers));
155 t1.start();
156 t2.start();
157 t1.join();
158 t2.join();
159 winners.await();
160 losers.await();
161 }
162
163 @Test
164 @Timeout(5)
165 public void exclusiveAccess(TestInfo testInfo) throws InterruptedException {
166 final Collection<NamedLockKey> keys = lockName(testInfo);
167 CountDownLatch winners = new CountDownLatch(1);
168 CountDownLatch losers = new CountDownLatch(1);
169 Thread t1 = new Thread(new Access(namedLockFactory, keys, false, winners, losers));
170 Thread t2 = new Thread(new Access(namedLockFactory, keys, false, winners, losers));
171 t1.start();
172 t2.start();
173 t1.join();
174 t2.join();
175 winners.await();
176 losers.await();
177 }
178
179 @Test
180 @Timeout(5)
181 public void mixedAccess(TestInfo testInfo) throws InterruptedException {
182 final Collection<NamedLockKey> keys = lockName(testInfo);
183 CountDownLatch winners = new CountDownLatch(1);
184 CountDownLatch losers = new CountDownLatch(1);
185 Thread t1 = new Thread(new Access(namedLockFactory, keys, true, winners, losers));
186 Thread t2 = new Thread(new Access(namedLockFactory, keys, false, winners, losers));
187 t1.start();
188 t2.start();
189 t1.join();
190 t2.join();
191 winners.await();
192 losers.await();
193 }
194
195 @Test
196 @Timeout(5)
197 public void fullyConsumeLockTime(TestInfo testInfo) throws InterruptedException {
198 long start = System.nanoTime();
199 final Collection<NamedLockKey> keys = lockName(testInfo);
200 CountDownLatch winners = new CountDownLatch(1);
201 CountDownLatch losers = new CountDownLatch(1);
202 Thread t1 = new Thread(new Access(namedLockFactory, keys, true, winners, losers));
203 Thread t2 = new Thread(new Access(namedLockFactory, keys, false, winners, losers));
204 t1.start();
205 t2.start();
206 t1.join();
207 t2.join();
208 winners.await();
209 losers.await();
210 long end = System.nanoTime();
211 long duration = end - start;
212 long expectedDuration = TimeUnit.MILLISECONDS.toNanos(ACCESS_WAIT_MILLIS);
213 assertTrue(duration >= expectedDuration, duration + " >= " + expectedDuration);
214 }
215
216 @Test
217 @Timeout(5)
218 public void releasedExclusiveAllowAccess(TestInfo testInfo) throws InterruptedException {
219 final Collection<NamedLockKey> keys = lockName(testInfo);
220 CountDownLatch winners = new CountDownLatch(1);
221 CountDownLatch losers = new CountDownLatch(0);
222 Thread t1 = new Thread(new Access(namedLockFactory, keys, true, winners, losers));
223 try (NamedLock namedLock = namedLockFactory.getLock(keys)) {
224 assertTrue(namedLock.lockExclusively(50L, TimeUnit.MILLISECONDS));
225 try {
226 t1.start();
227 Thread.sleep(50L);
228 } finally {
229 namedLock.unlock();
230 }
231 }
232 t1.join();
233 winners.await();
234 losers.await();
235 }
236
237 private static final long ACCESS_WAIT_MILLIS = 1000L;
238
239 private static class Access implements Runnable {
240 final NamedLockFactory namedLockFactory;
241 final Collection<NamedLockKey> keys;
242 final boolean shared;
243 final CountDownLatch winner;
244 final CountDownLatch loser;
245
246 public Access(
247 NamedLockFactory namedLockFactory,
248 Collection<NamedLockKey> keys,
249 boolean shared,
250 CountDownLatch winner,
251 CountDownLatch loser) {
252 this.namedLockFactory = namedLockFactory;
253 this.keys = keys;
254 this.shared = shared;
255 this.winner = winner;
256 this.loser = loser;
257 }
258
259 @Override
260 public void run() {
261 try (NamedLock lock = namedLockFactory.getLock(keys)) {
262 if (shared
263 ? lock.lockShared(ACCESS_WAIT_MILLIS, TimeUnit.MILLISECONDS)
264 : lock.lockExclusively(ACCESS_WAIT_MILLIS, TimeUnit.MILLISECONDS)) {
265 try {
266 winner.countDown();
267 loser.await();
268 } finally {
269 lock.unlock();
270 }
271 } else {
272 loser.countDown();
273 winner.await();
274 }
275 } catch (InterruptedException e) {
276 fail(e.getMessage());
277 }
278 }
279 }
280 }