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