View Javadoc
1   package org.eclipse.aether.internal.impl.synccontext;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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.Objects;
39  import java.util.concurrent.CountDownLatch;
40  import java.util.concurrent.TimeUnit;
41  
42  import static org.mockito.Mockito.mock;
43  import static org.mockito.Mockito.when;
44  
45  /**
46   * UT support for {@link SyncContextFactory}.
47   */
48  public abstract class NamedLockFactoryAdapterTestSupport {
49      private static final long ADAPTER_TIME = 100L;
50  
51      private static final TimeUnit ADAPTER_TIME_UNIT = TimeUnit.MILLISECONDS;
52  
53      /**
54       * Subclass MAY populate this field but subclass must take care of proper cleanup as well, if needed!
55       */
56      protected static NameMapper nameMapper = new DiscriminatingNameMapper(new GAVNameMapper());
57  
58      /**
59       * Subclass MUST populate this field but subclass must take care of proper cleanup as well, if needed! Once set,
60       * subclass must MUST call {@link #createAdapter()}.
61       */
62      protected static NamedLockFactory namedLockFactory;
63  
64      private static NamedLockFactoryAdapter adapter;
65  
66      private RepositorySystemSession session;
67  
68      public static void createAdapter() {
69          Objects.requireNonNull(namedLockFactory, "NamedLockFactory not set");
70          adapter = new NamedLockFactoryAdapter(nameMapper, namedLockFactory, ADAPTER_TIME, ADAPTER_TIME_UNIT);
71      }
72  
73      @AfterClass
74      public static void cleanupAdapter() {
75          if (adapter != null) {
76              adapter.shutdown();
77          }
78      }
79  
80      @Before
81      public void before() throws IOException {
82          Files.createDirectories(Paths.get(System.getProperty("java.io.tmpdir"))); // hack for Surefire
83          LocalRepository localRepository = new LocalRepository(Files.createTempDirectory("test").toFile());
84          session = mock(RepositorySystemSession.class);
85          when(session.getLocalRepository()).thenReturn(localRepository);
86      }
87  
88      @Test
89      public void justCreateAndClose() {
90          adapter.newInstance(session, false).close();
91      }
92  
93      @Test
94      public void justAcquire() {
95          try (SyncContext syncContext = adapter.newInstance(session, false)) {
96              syncContext.acquire(
97                      Arrays.asList(new DefaultArtifact("groupId:artifactId:1.0"), new DefaultArtifact("groupId:artifactId:1.1")),
98                      null
99              );
100         }
101     }
102 
103     @Test(timeout = 5000)
104     public void sharedAccess() throws InterruptedException {
105         CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
106         CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
107         Thread t1 = new Thread(new Access(true, winners, losers, adapter, session, null));
108         Thread t2 = new Thread(new Access(true, winners, losers, adapter, session, null));
109         t1.start();
110         t2.start();
111         t1.join();
112         t2.join();
113         winners.await();
114         losers.await();
115     }
116 
117     @Test(timeout = 5000)
118     public void exclusiveAccess() throws InterruptedException {
119         CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
120         CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
121         Thread t1 = new Thread(new Access(false, winners, losers, adapter, session, null));
122         Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null));
123         t1.start();
124         t2.start();
125         t1.join();
126         t2.join();
127         winners.await();
128         losers.await();
129     }
130 
131     @Test(timeout = 5000)
132     public void mixedAccess() throws InterruptedException {
133         CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
134         CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
135         Thread t1 = new Thread(new Access(true, winners, losers, adapter, session, null));
136         Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null));
137         t1.start();
138         t2.start();
139         t1.join();
140         t2.join();
141         winners.await();
142         losers.await();
143     }
144 
145     @Test(timeout = 5000)
146     public void nestedSharedShared() throws InterruptedException {
147         CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
148         CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
149         Thread t1 = new Thread(
150                 new Access(true, winners, losers, adapter, session,
151                         new Access(true, winners, losers, adapter, session, null)
152                 )
153         );
154         t1.start();
155         t1.join();
156         winners.await();
157         losers.await();
158     }
159 
160     @Test(timeout = 5000)
161     public void nestedExclusiveShared() throws InterruptedException {
162         CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
163         CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
164         Thread t1 = new Thread(
165                 new Access(false, winners, losers, adapter, session,
166                         new Access(true, winners, losers, adapter, session, null)
167                 )
168         );
169         t1.start();
170         t1.join();
171         winners.await();
172         losers.await();
173     }
174 
175     @Test(timeout = 5000)
176     public void nestedExclusiveExclusive() throws InterruptedException {
177         CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
178         CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
179         Thread t1 = new Thread(
180                 new Access(false, winners, losers, adapter, session,
181                         new Access(false, winners, losers, adapter, session, null)
182                 )
183         );
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); // we expect 1 winner (outer)
193         CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser (inner)
194         Thread t1 = new Thread(
195                 new Access(true, winners, losers, adapter, session,
196                         new Access(false, winners, losers, adapter, session, null)
197                 )
198         );
199         t1.start();
200         t1.join();
201         winners.await();
202         losers.await();
203     }
204 
205     private static class Access implements Runnable {
206         final boolean shared;
207         final CountDownLatch winner;
208         final CountDownLatch loser;
209         final NamedLockFactoryAdapter adapter;
210         final RepositorySystemSession session;
211         final Access chained;
212 
213         public Access(boolean shared,
214                       CountDownLatch winner,
215                       CountDownLatch loser,
216                       NamedLockFactoryAdapter adapter,
217                       RepositorySystemSession session,
218                       Access chained) {
219             this.shared = shared;
220             this.winner = winner;
221             this.loser = loser;
222             this.adapter = adapter;
223             this.session = session;
224             this.chained = chained;
225         }
226 
227         @Override
228         public void run() {
229             try {
230                 try (SyncContext syncContext = adapter.newInstance(session, shared)) {
231                     syncContext.acquire(
232                             Arrays.asList(new DefaultArtifact("groupId:artifactId:1.0"), new DefaultArtifact("groupId:artifactId:1.1")),
233                             null
234                     );
235                     winner.countDown();
236                     if (chained != null) {
237                         chained.run();
238                     }
239                     loser.await();
240                 } catch (IllegalStateException e) {
241                     e.printStackTrace(); // for ref purposes
242                     loser.countDown();
243                     winner.await();
244                 }
245             } catch (InterruptedException e) {
246                 Assert.fail("interrupted");
247             }
248         }
249     }
250 }