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