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;
20  
21  import java.util.concurrent.CountDownLatch;
22  import java.util.concurrent.TimeUnit;
23  
24  import org.junit.Assert;
25  import org.junit.Rule;
26  import org.junit.Test;
27  import org.junit.rules.TestName;
28  
29  import static org.hamcrest.MatcherAssert.assertThat;
30  import static org.hamcrest.Matchers.*;
31  
32  /**
33   * UT support for {@link NamedLockFactory}.
34   */
35  public abstract class NamedLockFactoryTestSupport {
36  
37      protected static NamedLockFactory namedLockFactory;
38  
39      @Rule
40      public TestName testName = new TestName();
41  
42      protected String lockName() {
43          return testName.getMethodName();
44      }
45  
46      @Test
47      public void refCounting() {
48          final String name = lockName();
49          try (NamedLock one = namedLockFactory.getLock(name);
50                  NamedLock two = namedLockFactory.getLock(name)) {
51              assertThat(one, sameInstance(two));
52              one.close();
53              two.close();
54  
55              try (NamedLock three = namedLockFactory.getLock(name)) {
56                  assertThat(three, not(sameInstance(two)));
57              }
58          }
59      }
60  
61      @Test(expected = IllegalStateException.class)
62      public void unlockWoLock() {
63          final String name = lockName();
64          try (NamedLock one = namedLockFactory.getLock(name)) {
65              one.unlock();
66          }
67      }
68  
69      @Test
70      public void wwBoxing() throws InterruptedException {
71          final String name = lockName();
72          try (NamedLock one = namedLockFactory.getLock(name)) {
73              assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true));
74              assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true));
75              one.unlock();
76              one.unlock();
77          }
78      }
79  
80      @Test
81      public void rrBoxing() throws InterruptedException {
82          final String name = lockName();
83          try (NamedLock one = namedLockFactory.getLock(name)) {
84              assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
85              assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
86              one.unlock();
87              one.unlock();
88          }
89      }
90  
91      @Test
92      public void wrBoxing() throws InterruptedException {
93          final String name = lockName();
94          try (NamedLock one = namedLockFactory.getLock(name)) {
95              assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true));
96              assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
97              one.unlock();
98              one.unlock();
99          }
100     }
101 
102     @Test
103     public void rwBoxing() throws InterruptedException {
104         final String name = lockName();
105         try (NamedLock one = namedLockFactory.getLock(name)) {
106             assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
107             assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(false));
108             one.unlock();
109         }
110     }
111 
112     @Test(timeout = 5000)
113     public void sharedAccess() throws InterruptedException {
114         final String name = lockName();
115         CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
116         CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
117         Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
118         Thread t2 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
119         t1.start();
120         t2.start();
121         t1.join();
122         t2.join();
123         winners.await();
124         losers.await();
125     }
126 
127     @Test(timeout = 5000)
128     public void exclusiveAccess() throws InterruptedException {
129         final String name = lockName();
130         CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
131         CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
132         Thread t1 = new Thread(new Access(namedLockFactory, name, false, winners, losers));
133         Thread t2 = new Thread(new Access(namedLockFactory, name, false, winners, losers));
134         t1.start();
135         t2.start();
136         t1.join();
137         t2.join();
138         winners.await();
139         losers.await();
140     }
141 
142     @Test(timeout = 5000)
143     public void mixedAccess() throws InterruptedException {
144         final String name = lockName();
145         CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
146         CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
147         Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
148         Thread t2 = new Thread(new Access(namedLockFactory, name, false, winners, losers));
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 fullyConsumeLockTime() throws InterruptedException {
159         long start = System.nanoTime();
160         final String name = lockName();
161         CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
162         CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
163         Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
164         Thread t2 = new Thread(new Access(namedLockFactory, name, false, winners, losers));
165         t1.start();
166         t2.start();
167         t1.join();
168         t2.join();
169         winners.await();
170         losers.await();
171         long end = System.nanoTime();
172         long duration = end - start;
173         long expectedDuration = TimeUnit.MILLISECONDS.toNanos(ACCESS_WAIT_MILLIS);
174         assertThat(duration, greaterThanOrEqualTo(expectedDuration)); // equal in ideal case
175     }
176 
177     @Test(timeout = 5000)
178     public void releasedExclusiveAllowAccess() throws InterruptedException {
179         final String name = lockName();
180         CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
181         CountDownLatch losers = new CountDownLatch(0); // we expect 0 loser
182         Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
183         try (NamedLock namedLock = namedLockFactory.getLock(name)) {
184             assertThat(namedLock.lockExclusively(50L, TimeUnit.MILLISECONDS), is(true));
185             try {
186                 t1.start();
187                 Thread.sleep(50L);
188             } finally {
189                 namedLock.unlock();
190             }
191         }
192         t1.join();
193         winners.await();
194         losers.await();
195     }
196 
197     private static final long ACCESS_WAIT_MILLIS = 1000L;
198 
199     private static class Access implements Runnable {
200         final NamedLockFactory namedLockFactory;
201         final String name;
202         final boolean shared;
203         final CountDownLatch winner;
204         final CountDownLatch loser;
205 
206         public Access(
207                 NamedLockFactory namedLockFactory,
208                 String name,
209                 boolean shared,
210                 CountDownLatch winner,
211                 CountDownLatch loser) {
212             this.namedLockFactory = namedLockFactory;
213             this.name = name;
214             this.shared = shared;
215             this.winner = winner;
216             this.loser = loser;
217         }
218 
219         @Override
220         public void run() {
221             try (NamedLock lock = namedLockFactory.getLock(name)) {
222                 if (shared
223                         ? lock.lockShared(ACCESS_WAIT_MILLIS, TimeUnit.MILLISECONDS)
224                         : lock.lockExclusively(ACCESS_WAIT_MILLIS, TimeUnit.MILLISECONDS)) {
225                     try {
226                         winner.countDown();
227                         loser.await();
228                     } finally {
229                         lock.unlock();
230                     }
231                 } else {
232                     loser.countDown();
233                     winner.await();
234                 }
235             } catch (InterruptedException e) {
236                 Assert.fail(e.getMessage());
237             }
238         }
239     }
240 }