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.named.support.LockUpgradeNotSupportedException;
37  import org.eclipse.aether.repository.LocalRepository;
38  import org.eclipse.aether.spi.synccontext.SyncContextFactory;
39  import org.junit.AfterClass;
40  import org.junit.Assert;
41  import org.junit.Before;
42  import org.junit.Test;
43  
44  import static org.mockito.Mockito.mock;
45  import static org.mockito.Mockito.when;
46  
47  /**
48   * UT support for {@link SyncContextFactory}.
49   */
50  public abstract class NamedLockFactoryAdapterTestSupport {
51      protected static final HazelcastClientUtils utils = new HazelcastClientUtils();
52  
53      private static final long ADAPTER_TIME = 100L;
54  
55      private static final TimeUnit ADAPTER_TIME_UNIT = TimeUnit.MILLISECONDS;
56  
57      /**
58       * Subclass should populate this field, using {@link #setNamedLockFactory(NamedLockFactory)}, but subclass
59       * must take care of proper cleanup as well, if needed!
60       */
61      private static NamedLockFactoryAdapter adapter;
62  
63      private RepositorySystemSession session;
64  
65      protected static void setNamedLockFactory(final NamedLockFactory namedLockFactory) {
66          adapter = new NamedLockFactoryAdapter(new DiscriminatingNameMapper(GAVNameMapper.gav()), namedLockFactory);
67      }
68  
69      @AfterClass
70      public static void cleanup() {
71          if (adapter != null) {
72              adapter.getNamedLockFactory().shutdown();
73          }
74  
75          utils.cleanup();
76      }
77  
78      @Before
79      public void before() throws IOException {
80          Files.createDirectories(Paths.get(System.getProperty("java.io.tmpdir"))); // hack for Surefire
81          LocalRepository localRepository =
82                  new LocalRepository(Files.createTempDirectory("test").toFile());
83          session = mock(RepositorySystemSession.class);
84          when(session.getLocalRepository()).thenReturn(localRepository);
85          HashMap<String, Object> config = new HashMap<>();
86          config.put(NamedLockFactoryAdapter.TIME_KEY, String.valueOf(ADAPTER_TIME));
87          config.put(NamedLockFactoryAdapter.TIME_UNIT_KEY, ADAPTER_TIME_UNIT.name());
88          when(session.getConfigProperties()).thenReturn(config);
89      }
90  
91      @Test
92      public void justCreateAndClose() {
93          adapter.newInstance(session, false).close();
94      }
95  
96      @Test
97      public void justAcquire() {
98          try (SyncContext syncContext = adapter.newInstance(session, false)) {
99              syncContext.acquire(
100                     Arrays.asList(
101                             new DefaultArtifact("groupId:artifactId:1.0"),
102                             new DefaultArtifact("groupId:artifactId:1.1")),
103                     null);
104         }
105     }
106 
107     @Test(timeout = 5000)
108     public void sharedAccess() throws InterruptedException {
109         CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
110         CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
111         Thread t1 = new Thread(new Access(true, winners, losers, adapter, session, null));
112         Thread t2 = new Thread(new Access(true, winners, losers, adapter, session, null));
113         t1.start();
114         t2.start();
115         t1.join();
116         t2.join();
117         winners.await();
118         losers.await();
119     }
120 
121     @Test(timeout = 5000)
122     public void exclusiveAccess() throws InterruptedException {
123         CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
124         CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
125         Thread t1 = new Thread(new Access(false, winners, losers, adapter, session, null));
126         Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null));
127         t1.start();
128         t2.start();
129         t1.join();
130         t2.join();
131         winners.await();
132         losers.await();
133     }
134 
135     @Test(timeout = 5000)
136     public void mixedAccess() throws InterruptedException {
137         CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
138         CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
139         Thread t1 = new Thread(new Access(true, winners, losers, adapter, session, null));
140         Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null));
141         t1.start();
142         t2.start();
143         t1.join();
144         t2.join();
145         winners.await();
146         losers.await();
147     }
148 
149     @Test(timeout = 5000)
150     public void nestedSharedShared() throws InterruptedException {
151         CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
152         CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
153         Thread t1 = new Thread(new Access(
154                 true, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null)));
155         t1.start();
156         t1.join();
157         winners.await();
158         losers.await();
159     }
160 
161     @Test(timeout = 5000)
162     public void nestedExclusiveShared() throws InterruptedException {
163         CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
164         CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
165         Thread t1 = new Thread(new Access(
166                 false, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null)));
167         t1.start();
168         t1.join();
169         winners.await();
170         losers.await();
171     }
172 
173     @Test(timeout = 5000)
174     public void nestedExclusiveExclusive() throws InterruptedException {
175         CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
176         CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
177         Thread t1 = new Thread(new Access(
178                 false, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null)));
179         t1.start();
180         t1.join();
181         winners.await();
182         losers.await();
183     }
184 
185     @Test(timeout = 5000)
186     public void nestedSharedExclusive() throws InterruptedException {
187         CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner (outer)
188         CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser (inner)
189         Thread t1 = new Thread(new Access(
190                 true, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null)));
191         t1.start();
192         t1.join();
193         winners.await();
194         losers.await();
195     }
196 
197     private static class Access implements Runnable {
198         final boolean shared;
199         final CountDownLatch winner;
200         final CountDownLatch loser;
201         final NamedLockFactoryAdapter adapter;
202         final RepositorySystemSession session;
203         final Access chained;
204 
205         public Access(
206                 boolean shared,
207                 CountDownLatch winner,
208                 CountDownLatch loser,
209                 NamedLockFactoryAdapter adapter,
210                 RepositorySystemSession session,
211                 Access chained) {
212             this.shared = shared;
213             this.winner = winner;
214             this.loser = loser;
215             this.adapter = adapter;
216             this.session = session;
217             this.chained = chained;
218         }
219 
220         @Override
221         public void run() {
222             try {
223                 try (SyncContext syncContext = adapter.newInstance(session, shared)) {
224                     syncContext.acquire(
225                             Arrays.asList(
226                                     new DefaultArtifact("groupId:artifactId:1.0"),
227                                     new DefaultArtifact("groupId:artifactId:1.1")),
228                             null);
229                     winner.countDown();
230                     if (chained != null) {
231                         chained.run();
232                     }
233                     loser.await();
234                 } catch (IllegalStateException | LockUpgradeNotSupportedException e) {
235                     loser.countDown();
236                     winner.await();
237                 }
238             } catch (InterruptedException e) {
239                 Assert.fail("interrupted");
240             }
241         }
242     }
243 }