/*
* Copyright 2014 Ben Manes. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.benmanes.caffeine.cache;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.github.benmanes.caffeine.testing.Awaits;
import com.github.benmanes.caffeine.testing.ConcurrentTestHarness;
import com.google.common.testing.SerializableTester;
/**
* @author ben.manes@gmail.com (Ben Manes)
*/
public final class NonReentrantLockTest {
@DataProvider(name = "lock")
public Object[][] providesLock() {
return new Object[][] {{ new NonReentrantLock() }};
}
@Test(dataProvider = "lock")
public void tryLock(NonReentrantLock lock) {
assertThat(lock.tryLock(), is(true));
lock.unlock();
}
@Test(dataProvider = "lock")
public void tryLock_timed(NonReentrantLock lock) throws InterruptedException {
assertThat(lock.tryLock(1, TimeUnit.MINUTES), is(true));
lock.unlock();
}
@Test(dataProvider = "lock")
public void lockInterruptibly(NonReentrantLock lock) throws InterruptedException {
lock.lockInterruptibly();
lock.unlock();
}
@Test(dataProvider = "lock")
public void lock(NonReentrantLock lock) {
lock.lock();
assertThat(lock.tryLock(), is(false));
assertThat(lock.isHeldByCurrentThread(), is(true));
assertThat(lock.getOwner(), is(Thread.currentThread()));
lock.unlock();
}
@Test(dataProvider = "lock")
public void lock_exclusive(NonReentrantLock lock) {
Thread testThread = Thread.currentThread();
ConcurrentTestHarness.execute(() -> {
lock.lock();
Awaits.await().until(lock::hasQueuedThreads);
assertThat(lock.getQueueLength(), is(1));
assertThat(lock.getQueuedThreads(), contains(testThread));
assertThat(lock.hasQueuedThread(testThread), is(true));
lock.unlock();
});
Awaits.await().until(lock::isLocked);
assertThat(lock.tryLock(), is(false));
lock.lock();
lock.unlock();
}
@Test(dataProvider = "lock")
public void lock_error(NonReentrantLock lock) {
Condition condition = Mockito.mock(Condition.class);
try {
lock.hasWaiters(condition);
Assert.fail();
} catch (IllegalArgumentException e) {}
try {
lock.getWaitQueueLength(condition);
Assert.fail();
} catch (IllegalArgumentException e) {}
try {
lock.getWaitingThreads(condition);
Assert.fail();
} catch (IllegalArgumentException e) {}
try {
lock.sync.tryRelease(1);
Assert.fail();
} catch (IllegalMonitorStateException e) {}
}
@Test(dataProvider = "lock")
@SuppressWarnings("WaitNotInLoop")
public void condition(NonReentrantLock lock) {
Condition condition = lock.newCondition();
AtomicBoolean ready = new AtomicBoolean();
Thread thread = new Thread(() -> {
lock.lock();
ready.set(true);
condition.awaitUninterruptibly();
});
thread.start();
Awaits.await().untilTrue(ready);
lock.lock();
assertThat(lock.hasWaiters(condition), is(true));
assertThat(lock.getWaitQueueLength(condition), is(1));
assertThat(lock.getWaitingThreads(condition), contains(thread));
condition.signal();
lock.unlock();
}
@Test(dataProvider = "lock")
public void serialize(NonReentrantLock lock) {
lock.lock();
NonReentrantLock copy = SerializableTester.reserialize(lock);
assertThat(copy.isLocked(), is(false));
}
}