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