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