/*
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Jun 26, 2009
*/
package com.bigdata.util.concurrent;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import com.bigdata.util.DaemonThreadFactory;
import junit.framework.TestCase2;
/**
* Unit tests for {@link Latch}.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class TestLatch extends TestCase2 {
/**
*
*/
public TestLatch() {
}
/**
* @param name
*/
public TestLatch(String name) {
super(name);
}
/**
* Basic tests of the counter.
*/
public void test1() {
final Latch latch = new Latch();
assertEquals(latch.get(), 0);
assertEquals(latch.inc(), 1);
assertEquals(latch.inc(), 2);
assertEquals(latch.dec(), 1);
assertEquals(latch.dec(), 0);
try {
latch.dec();
fail("Expecting: " + IllegalStateException.class);
} catch (IllegalStateException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected error: " + ex);
}
assertEquals(latch.get(), 0);
}
/**
* Basic tests releasing blocked threads.
*
* @throws InterruptedException
* @throws ExecutionException
*
* @todo should have variants of these where the expectations are violated
* in order to verify correct failure mores. For example, where the
* timeout is to short in the Callable, where the outer thread fails
* to dec() or where the inner thread fails to inc().
*/
public void test2() throws InterruptedException, ExecutionException {
final Latch latch = new Latch();
final Callable<?> r = new Callable<Void>() {
public Void call() throws Exception {
latch.inc();
if (!latch.await(100, TimeUnit.MILLISECONDS))
fail("Expecting latch to decrement to zero.");
return null;
}
};
final ExecutorService service = Executors
.newSingleThreadExecutor(DaemonThreadFactory
.defaultThreadFactory());
try {
final Future<?> future = service.submit(r);
Thread.sleep(50);
latch.dec();
// Verify normal return.
assertNull(future.get());
} finally {
service.shutdownNow();
}
}
/**
* Verify that dec() does not allow the counter to become negative.
*/
public void test3() {
final Latch latch = new Latch();
try {
latch.dec();
fail("Counter is negative");
} catch (IllegalStateException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
assertEquals(0, latch.get());
assertEquals(1, latch.inc());
assertEquals(0,latch.dec());
try {
latch.dec();
fail("Counter is negative: "+latch.get());
} catch (IllegalStateException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
}
/**
* Verify that addAndGet() allows the counter to return to zero but does not
* allow the counter to become negative.
*/
public void test4() {
final Latch latch = new Latch();
assertEquals(1, latch.inc());
assertEquals(0, latch.addAndGet(-1));
assertEquals(1, latch.inc());
try {
latch.addAndGet(-2);
fail("Counter is negative: "+latch.get());
} catch (IllegalStateException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
assertEquals(0, latch.addAndGet(-1));
}
/**
* Test of {@link Latch#await(long, TimeUnit)}.
* @throws InterruptedException
*/
public void test5() throws InterruptedException {
final Latch latch = new Latch();
assertEquals(latch.get(), 0);
assertEquals(latch.inc(), 1);
assertEquals(latch.get(), 1);
{
final long timeout = TimeUnit.SECONDS.toNanos(1L);
final long begin = System.nanoTime();
// await latch to decrement to zero.
assertFalse(latch.await(timeout, TimeUnit.NANOSECONDS));
final long elapsed = System.nanoTime() - begin;
if (elapsed < timeout || (elapsed > (2 * timeout))) {
fail("elapsed=" + elapsed + ", timeout=" + timeout);
}
}
assertEquals(latch.get(), 1);
assertEquals(latch.dec(), 0);
assertTrue(latch.await(1, TimeUnit.SECONDS));
try {
latch.dec();
fail("Expecting: " + IllegalStateException.class);
} catch (IllegalStateException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected error: " + ex);
}
assertEquals(latch.get(), 0);
}
}