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