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.is;
032import static org.hamcrest.Matchers.not;
033import static org.hamcrest.Matchers.sameInstance;
034
035/**
036 * UT support for {@link NamedLockFactory}.
037 */
038public abstract class NamedLockFactoryTestSupport {
039
040    protected static NamedLockFactory namedLockFactory;
041
042    @Rule
043    public TestName testName = new TestName();
044
045    protected String lockName()
046    {
047        return testName.getMethodName();
048    }
049
050    @Test
051    public void refCounting() {
052        final String name = lockName();
053        try (NamedLock one = namedLockFactory.getLock(name);
054             NamedLock two = namedLockFactory.getLock(name)) {
055            assertThat(one, sameInstance(two));
056            one.close();
057            two.close();
058
059            try (NamedLock three = namedLockFactory.getLock(name)) {
060                assertThat(three, not(sameInstance(two)));
061            }
062        }
063    }
064
065    @Test(expected = IllegalStateException.class)
066    public void unlockWoLock() {
067        final String name = lockName();
068        try (NamedLock one = namedLockFactory.getLock(name)) {
069            one.unlock();
070        }
071    }
072
073    @Test
074    public void wwBoxing() throws InterruptedException {
075        final String name = lockName();
076        try (NamedLock one = namedLockFactory.getLock(name)) {
077            assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true));
078            assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true));
079            one.unlock();
080            one.unlock();
081        }
082    }
083
084    @Test
085    public void rrBoxing() throws InterruptedException {
086        final String name = lockName();
087        try (NamedLock one = namedLockFactory.getLock(name)) {
088            assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
089            assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
090            one.unlock();
091            one.unlock();
092        }
093    }
094
095    @Test
096    public void wrBoxing() throws InterruptedException {
097        final String name = lockName();
098        try (NamedLock one = namedLockFactory.getLock(name)) {
099            assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(true));
100            assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
101            one.unlock();
102            one.unlock();
103        }
104    }
105
106    @Test
107    public void rwBoxing() throws InterruptedException {
108        final String name = lockName();
109        try (NamedLock one = namedLockFactory.getLock(name)) {
110            assertThat(one.lockShared(1L, TimeUnit.MILLISECONDS), is(true));
111            assertThat(one.lockExclusively(1L, TimeUnit.MILLISECONDS), is(false));
112            one.unlock();
113        }
114    }
115
116    @Test(timeout = 5000)
117    public void sharedAccess() throws InterruptedException {
118        final String name = lockName();
119        CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners
120        CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers
121        Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
122        Thread t2 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
123        t1.start();
124        t2.start();
125        t1.join();
126        t2.join();
127        winners.await();
128        losers.await();
129    }
130
131    @Test(timeout = 5000)
132    public void exclusiveAccess() throws InterruptedException {
133        final String name = lockName();
134        CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
135        CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
136        Thread t1 = new Thread(new Access(namedLockFactory, name, false, winners, losers));
137        Thread t2 = new Thread(new Access(namedLockFactory, name, false, winners, losers));
138        t1.start();
139        t2.start();
140        t1.join();
141        t2.join();
142        winners.await();
143        losers.await();
144    }
145
146    @Test(timeout = 5000)
147    public void mixedAccess() throws InterruptedException {
148        final String name = lockName();
149        CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner
150        CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser
151        Thread t1 = new Thread(new Access(namedLockFactory, name, true, winners, losers));
152        Thread t2 = new Thread(new Access(namedLockFactory, name, false, winners, losers));
153        t1.start();
154        t2.start();
155        t1.join();
156        t2.join();
157        winners.await();
158        losers.await();
159    }
160
161    private static class Access implements Runnable {
162        final NamedLockFactory namedLockFactory;
163        final String name;
164        final boolean shared;
165        final CountDownLatch winner;
166        final CountDownLatch loser;
167
168        public Access(NamedLockFactory namedLockFactory,
169                      String name,
170                      boolean shared,
171                      CountDownLatch winner,
172                      CountDownLatch loser) {
173            this.namedLockFactory = namedLockFactory;
174            this.name = name;
175            this.shared = shared;
176            this.winner = winner;
177            this.loser = loser;
178        }
179
180        @Override
181        public void run() {
182            try (NamedLock lock = namedLockFactory.getLock(name)) {
183                if (shared ? lock.lockShared(100L, TimeUnit.MILLISECONDS) : lock.lockExclusively(100L, TimeUnit.MILLISECONDS)) {
184                    try {
185                        winner.countDown();
186                        loser.await();
187                    } finally {
188                        lock.unlock();
189                    }
190                } else {
191                    loser.countDown();
192                    winner.await();
193                }
194            } catch (InterruptedException e) {
195                Assert.fail(e.getMessage());
196            }
197        }
198    }
199}