1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.internal.impl.synccontext;
20
21 import java.io.IOException;
22 import java.nio.file.Files;
23 import java.nio.file.Paths;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.concurrent.CountDownLatch;
27 import java.util.concurrent.TimeUnit;
28
29 import org.eclipse.aether.RepositorySystemSession;
30 import org.eclipse.aether.SyncContext;
31 import org.eclipse.aether.artifact.DefaultArtifact;
32 import org.eclipse.aether.internal.impl.synccontext.named.*;
33 import org.eclipse.aether.named.NamedLockFactory;
34 import org.eclipse.aether.named.support.LockUpgradeNotSupportedException;
35 import org.eclipse.aether.repository.LocalRepository;
36 import org.eclipse.aether.spi.synccontext.SyncContextFactory;
37 import org.junit.AfterClass;
38 import org.junit.Assert;
39 import org.junit.Before;
40 import org.junit.Test;
41
42 import static java.util.Objects.requireNonNull;
43 import static org.hamcrest.MatcherAssert.assertThat;
44 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
45 import static org.mockito.Mockito.mock;
46 import static org.mockito.Mockito.when;
47
48
49
50
51 public abstract class NamedLockFactoryAdapterTestSupport {
52 private static final long ADAPTER_TIME = 1000L;
53
54 private static final TimeUnit ADAPTER_TIME_UNIT = TimeUnit.MILLISECONDS;
55
56
57
58
59 protected static NameMapper nameMapper = new DiscriminatingNameMapper(GAVNameMapper.gav());
60
61
62
63
64
65 protected static NamedLockFactory namedLockFactory;
66
67 private static NamedLockFactoryAdapter adapter;
68
69 private RepositorySystemSession session;
70
71 public static void createAdapter() {
72 requireNonNull(namedLockFactory, "NamedLockFactory not set");
73 adapter = new NamedLockFactoryAdapter(nameMapper, namedLockFactory);
74 }
75
76 @AfterClass
77 public static void cleanupAdapter() {
78 if (adapter != null) {
79 adapter.getNamedLockFactory().shutdown();
80 }
81 }
82
83 @Before
84 public void before() throws IOException {
85 Files.createDirectories(Paths.get(System.getProperty("java.io.tmpdir")));
86 LocalRepository localRepository =
87 new LocalRepository(Files.createTempDirectory("test").toFile());
88 session = mock(RepositorySystemSession.class);
89 when(session.getLocalRepository()).thenReturn(localRepository);
90 HashMap<String, Object> config = new HashMap<>();
91 config.put(NamedLockFactoryAdapter.TIME_KEY, String.valueOf(ADAPTER_TIME));
92 config.put(NamedLockFactoryAdapter.TIME_UNIT_KEY, ADAPTER_TIME_UNIT.name());
93 when(session.getConfigProperties()).thenReturn(config);
94 }
95
96 @Test
97 public void justCreateAndClose() {
98 adapter.newInstance(session, false).close();
99 }
100
101 @Test
102 public void justAcquire() {
103 try (SyncContext syncContext = adapter.newInstance(session, false)) {
104 syncContext.acquire(
105 Arrays.asList(
106 new DefaultArtifact("groupId:artifactId:1.0"),
107 new DefaultArtifact("groupId:artifactId:1.1")),
108 null);
109 }
110 }
111
112 @Test(timeout = 5000)
113 public void sharedAccess() throws InterruptedException {
114 CountDownLatch winners = new CountDownLatch(2);
115 CountDownLatch losers = new CountDownLatch(0);
116 Thread t1 = new Thread(new Access(true, winners, losers, adapter, session, null));
117 Thread t2 = new Thread(new Access(true, winners, losers, adapter, session, null));
118 t1.start();
119 t2.start();
120 t1.join();
121 t2.join();
122 winners.await();
123 losers.await();
124 }
125
126 @Test(timeout = 5000)
127 public void exclusiveAccess() throws InterruptedException {
128 CountDownLatch winners = new CountDownLatch(1);
129 CountDownLatch losers = new CountDownLatch(1);
130 Thread t1 = new Thread(new Access(false, winners, losers, adapter, session, null));
131 Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null));
132 t1.start();
133 t2.start();
134 t1.join();
135 t2.join();
136 winners.await();
137 losers.await();
138 }
139
140 @Test(timeout = 5000)
141 public void mixedAccess() throws InterruptedException {
142 CountDownLatch winners = new CountDownLatch(1);
143 CountDownLatch losers = new CountDownLatch(1);
144 Thread t1 = new Thread(new Access(true, winners, losers, adapter, session, null));
145 Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null));
146 t1.start();
147 t2.start();
148 t1.join();
149 t2.join();
150 winners.await();
151 losers.await();
152 }
153
154 @Test(timeout = 5000)
155 public void nestedSharedShared() throws InterruptedException {
156 CountDownLatch winners = new CountDownLatch(2);
157 CountDownLatch losers = new CountDownLatch(0);
158 Thread t1 = new Thread(new Access(
159 true, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null)));
160 t1.start();
161 t1.join();
162 winners.await();
163 losers.await();
164 }
165
166 @Test(timeout = 5000)
167 public void nestedExclusiveShared() throws InterruptedException {
168 CountDownLatch winners = new CountDownLatch(2);
169 CountDownLatch losers = new CountDownLatch(0);
170 Thread t1 = new Thread(new Access(
171 false, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null)));
172 t1.start();
173 t1.join();
174 winners.await();
175 losers.await();
176 }
177
178 @Test(timeout = 5000)
179 public void nestedExclusiveExclusive() throws InterruptedException {
180 CountDownLatch winners = new CountDownLatch(2);
181 CountDownLatch losers = new CountDownLatch(0);
182 Thread t1 = new Thread(new Access(
183 false, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null)));
184 t1.start();
185 t1.join();
186 winners.await();
187 losers.await();
188 }
189
190 @Test(timeout = 5000)
191 public void nestedSharedExclusive() throws InterruptedException {
192 CountDownLatch winners = new CountDownLatch(1);
193 CountDownLatch losers = new CountDownLatch(1);
194 Thread t1 = new Thread(new Access(
195 true, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null)));
196 t1.start();
197 t1.join();
198 winners.await();
199 losers.await();
200 }
201
202 @Test
203 public void fullyConsumeLockTime() throws InterruptedException {
204 long start = System.nanoTime();
205 CountDownLatch winners = new CountDownLatch(1);
206 CountDownLatch losers = new CountDownLatch(1);
207 Thread t1 = new Thread(new Access(false, winners, losers, adapter, session, null));
208 Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null));
209 t1.start();
210 t2.start();
211 t1.join();
212 t2.join();
213 winners.await();
214 losers.await();
215 long end = System.nanoTime();
216 long duration = end - start;
217 long expectedDuration = ADAPTER_TIME_UNIT.toNanos(ADAPTER_TIME);
218 assertThat(duration, greaterThanOrEqualTo(expectedDuration));
219 }
220
221 @Test
222 public void releasedExclusiveAllowAccess() throws InterruptedException {
223 CountDownLatch winners = new CountDownLatch(2);
224 CountDownLatch losers = new CountDownLatch(0);
225 Thread t1 = new Thread(new Access(false, winners, losers, adapter, session, null));
226 new Access(false, winners, losers, adapter, session, null).run();
227 t1.start();
228 t1.join();
229 winners.await();
230 losers.await();
231 }
232
233 private static class Access implements Runnable {
234 final boolean shared;
235 final CountDownLatch winner;
236 final CountDownLatch loser;
237 final NamedLockFactoryAdapter adapter;
238 final RepositorySystemSession session;
239 final Access chained;
240
241 public Access(
242 boolean shared,
243 CountDownLatch winner,
244 CountDownLatch loser,
245 NamedLockFactoryAdapter adapter,
246 RepositorySystemSession session,
247 Access chained) {
248 this.shared = shared;
249 this.winner = winner;
250 this.loser = loser;
251 this.adapter = adapter;
252 this.session = session;
253 this.chained = chained;
254 }
255
256 @Override
257 public void run() {
258 try {
259 try (SyncContext syncContext = adapter.newInstance(session, shared)) {
260 syncContext.acquire(
261 Arrays.asList(
262 new DefaultArtifact("groupId:artifactId:1.0"),
263 new DefaultArtifact("groupId:artifactId:1.1")),
264 null);
265 winner.countDown();
266 if (chained != null) {
267 chained.run();
268 }
269 loser.await();
270 } catch (IllegalStateException | LockUpgradeNotSupportedException e) {
271 loser.countDown();
272 winner.await();
273 }
274 } catch (InterruptedException e) {
275 Assert.fail("interrupted");
276 }
277 }
278 }
279 }