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