001package org.eclipse.aether.named; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.junit.Assert; 023import org.junit.Rule; 024import org.junit.Test; 025import org.junit.rules.TestName; 026 027import java.util.concurrent.CountDownLatch; 028import java.util.concurrent.TimeUnit; 029 030import static org.hamcrest.MatcherAssert.assertThat; 031import static org.hamcrest.Matchers.*; 032 033/** 034 * UT support for {@link NamedLockFactory}. 035 */ 036public abstract class NamedLockFactoryTestSupport { 037 038 protected static NamedLockFactory namedLockFactory; 039 040 @Rule 041 public TestName testName = new TestName(); 042 043 protected String lockName() 044 { 045 return testName.getMethodName(); 046 } 047 048 @Test 049 public void refCounting() { 050 final String name = lockName(); 051 try (NamedLock one = namedLockFactory.getLock(name); 052 NamedLock two = namedLockFactory.getLock(name)) { 053 assertThat(one, sameInstance(two)); 054 one.close(); 055 two.close(); 056 057 try (NamedLock three = namedLockFactory.getLock(name)) { 058 assertThat(three, not(sameInstance(two))); 059 } 060 } 061 } 062 063 @Test(expected = IllegalStateException.class) 064 public void unlockWoLock() { 065 final String name = lockName(); 066 try (NamedLock one = namedLockFactory.getLock(name)) { 067 one.unlock(); 068 } 069 } 070 071 @Test 072 public void wwBoxing() throws InterruptedException { 073 final String name = lockName(); 074 try (NamedLock one = namedLockFactory.getLock(name)) { 075 assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true)); 076 assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true)); 077 one.unlock(); 078 one.unlock(); 079 } 080 } 081 082 @Test 083 public void rrBoxing() throws InterruptedException { 084 final String name = lockName(); 085 try (NamedLock one = namedLockFactory.getLock(name)) { 086 assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true)); 087 assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true)); 088 one.unlock(); 089 one.unlock(); 090 } 091 } 092 093 @Test 094 public void wrBoxing() throws InterruptedException { 095 final String name = lockName(); 096 try (NamedLock one = namedLockFactory.getLock(name)) { 097 assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true)); 098 assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true)); 099 one.unlock(); 100 one.unlock(); 101 } 102 } 103 104 @Test 105 public void rwBoxing() throws InterruptedException { 106 final String name = lockName(); 107 try (NamedLock one = namedLockFactory.getLock(name)) { 108 assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true)); 109 assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(false)); 110 one.unlock(); 111 } 112 } 113 114 @Test(timeout = 5000) 115 public void sharedAccess() throws InterruptedException { 116 final String name = lockName(); 117 CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners 118 CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers 119 Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers)); 120 Thread t2 = new Thread(new Access(namedLockFactory, name, true, winners, losers)); 121 t1.start(); 122 t2.start(); 123 t1.join(); 124 t2.join(); 125 winners.await(); 126 losers.await(); 127 } 128 129 @Test(timeout = 5000) 130 public void exclusiveAccess() throws InterruptedException { 131 final String name = lockName(); 132 CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner 133 CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser 134 Thread t1 = new Thread(new Access(namedLockFactory, name, false, winners, losers)); 135 Thread t2 = new Thread(new Access(namedLockFactory, name, false, winners, losers)); 136 t1.start(); 137 t2.start(); 138 t1.join(); 139 t2.join(); 140 winners.await(); 141 losers.await(); 142 } 143 144 @Test(timeout = 5000) 145 public void mixedAccess() throws InterruptedException { 146 final String name = lockName(); 147 CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner 148 CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser 149 Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers)); 150 Thread t2 = new Thread(new Access(namedLockFactory, name, false, winners, losers)); 151 t1.start(); 152 t2.start(); 153 t1.join(); 154 t2.join(); 155 winners.await(); 156 losers.await(); 157 } 158 159 @Test(timeout = 5000) 160 public void fullyConsumeLockTime() throws InterruptedException { 161 long start = System.nanoTime(); 162 final String name = lockName(); 163 CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner 164 CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser 165 Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers)); 166 Thread t2 = new Thread(new Access(namedLockFactory, name, false, winners, losers)); 167 t1.start(); 168 t2.start(); 169 t1.join(); 170 t2.join(); 171 winners.await(); 172 losers.await(); 173 long end = System.nanoTime(); 174 long duration = end - start; 175 long expectedDuration = TimeUnit.MILLISECONDS.toNanos( ACCESS_WAIT_MILLIS ); 176 assertThat(duration, greaterThanOrEqualTo(expectedDuration)); // equal in ideal case 177 } 178 179 @Test(timeout = 5000) 180 public void releasedExclusiveAllowAccess() throws InterruptedException { 181 final String name = lockName(); 182 CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner 183 CountDownLatch losers = new CountDownLatch(0); // we expect 0 loser 184 Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers)); 185 try (NamedLock namedLock = namedLockFactory.getLock(name)) 186 { 187 assertThat( namedLock.lockExclusively( 50L, TimeUnit.MILLISECONDS ), is( true )); 188 try { 189 t1.start(); 190 Thread.sleep(50L ); 191 } 192 finally 193 { 194 namedLock.unlock(); 195 } 196 } 197 t1.join(); 198 winners.await(); 199 losers.await(); 200 } 201 202 private static final long ACCESS_WAIT_MILLIS = 1000L; 203 204 private static class Access implements Runnable { 205 final NamedLockFactory namedLockFactory; 206 final String name; 207 final boolean shared; 208 final CountDownLatch winner; 209 final CountDownLatch loser; 210 211 public Access(NamedLockFactory namedLockFactory, 212 String name, 213 boolean shared, 214 CountDownLatch winner, 215 CountDownLatch loser) { 216 this.namedLockFactory = namedLockFactory; 217 this.name = name; 218 this.shared = shared; 219 this.winner = winner; 220 this.loser = loser; 221 } 222 223 @Override 224 public void run() { 225 try (NamedLock lock = namedLockFactory.getLock(name)) { 226 if (shared ? lock.lockShared(ACCESS_WAIT_MILLIS, TimeUnit.MILLISECONDS) : lock.lockExclusively(ACCESS_WAIT_MILLIS, TimeUnit.MILLISECONDS)) { 227 try { 228 winner.countDown(); 229 loser.await(); 230 } finally { 231 lock.unlock(); 232 } 233 } else { 234 loser.countDown(); 235 winner.await(); 236 } 237 } catch (InterruptedException e) { 238 Assert.fail(e.getMessage()); 239 } 240 } 241 } 242}