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