/**
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 Apr 27, 2010
*/
package com.bigdata.io;
import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import junit.framework.TestCase2;
import com.bigdata.journal.TestHelper;
import com.bigdata.util.BytesUtil;
/**
* Base class for some <code>assertEquals</code> methods not covered by
* {@link TestCase} or {@link TestCase2}.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class TestCase3 extends TestCase2 {
/**
* A random number generated - the seed is NOT fixed.
*/
protected Random r;
/**
*
*/
public TestCase3() {
}
/**
* @param name
*/
public TestCase3(final String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
super.setUp();
r = new Random();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
r = null;
TestHelper.checkJournalsClosed(this);
}
/**
* Helper method verifies that the contents of <i>actual</i> from
* position() to limit() are consistent with the expected byte[]. A
* read-only view of <i>actual</i> is used to avoid side effects on the
* position, mark or limit properties of the buffer.
*
* @param expected
* Non-null byte[].
* @param actual
* Buffer.
*/
public static void assertEquals(ByteBuffer expectedBuffer,
final ByteBuffer actual) {
if (expectedBuffer == null)
throw new IllegalArgumentException();
if (actual == null)
fail("actual is null");
if (expectedBuffer.hasArray() && expectedBuffer.arrayOffset() == 0
&& expectedBuffer.position() == 0
&& expectedBuffer.limit() == expectedBuffer.capacity()) {
// evaluate byte[] against actual.
assertEquals(expectedBuffer.array(), actual);
return;
}
/*
* Copy the expected data into a byte[] using a read-only view on the
* buffer so that we do not mess with its position, mark, or limit.
*/
final byte[] expected;
{
expectedBuffer = expectedBuffer.asReadOnlyBuffer();
final int len = expectedBuffer.remaining();
expected = new byte[len];
expectedBuffer.get(expected);
}
// evaluate byte[] against actual.
assertEquals(expected, actual);
}
/**
* Helper method verifies that the contents of <i>actual</i> from
* position() to limit() are consistent with the expected byte[]. A
* read-only view of <i>actual</i> is used to avoid side effects on the
* position, mark or limit properties of the buffer.
*
* @param expected
* Non-null byte[].
* @param actual
* Buffer.
*/
public static void assertEquals(final byte[] expected, ByteBuffer actual) {
if (expected == null)
throw new IllegalArgumentException();
if (actual == null)
fail("actual is null");
if (actual.hasArray() && actual.arrayOffset() == 0
&& actual.position() == 0
&& actual.limit() == actual.capacity()) {
assertEquals(expected, actual.array());
return;
}
/*
* Create a read-only view on the buffer so that we do not mess with its
* position, mark, or limit.
*/
actual = actual.asReadOnlyBuffer();
final int len = actual.remaining();
final byte[] actual2 = new byte[len];
actual.get(actual2);
// compare byte[]s.
assertEquals(expected, actual2);
}
/**
* Return the data in the buffer.
*/
public static byte[] getBytes(final ByteBuffer buf) {
return BytesUtil.getBytes(buf);
}
/**
* Wait up to a timeout until some condition succeeds.
*
* @param cond
* The condition, which must throw an
* {@link AssertionFailedError} if it does not succeed.
* @param timeout
* The timeout.
* @param unit
*
* @throws AssertionFailedError
* if the condition does not succeed within the timeout.
*/
static public void assertCondition(final Runnable cond,
final long timeout, final TimeUnit units) {
final long begin = System.nanoTime();
final long nanos = units.toNanos(timeout);
long remaining = nanos;
// remaining = nanos - (now - begin) [aka elapsed]
remaining = nanos - (System.nanoTime() - begin);
while (true) {
try {
// try the condition
cond.run();
// success.
return;
} catch (final Throwable e) {
// final boolean interesting = //
// InnerCause.isInnerCause(e, AssertionFailedError.class) || //
// InnerCause.isInnerCause(e, TimeoutException.class);
remaining = nanos - (System.nanoTime() - begin);
if (remaining < 0) {
// Timeout - rethrow the failed assertion.
throw new RuntimeException(e);
}
// Sleep up to 10ms or the remaining nanos, which ever is less.
final int millis = (int) Math.min(
TimeUnit.NANOSECONDS.toMillis(remaining), 10);
if (millis > 0) {
// sleep and retry.
try {
Thread.sleep(millis);
} catch (InterruptedException e1) {
// propagate the interrupt.
Thread.currentThread().interrupt();
return;
}
remaining = nanos - (System.nanoTime() - begin);
if (remaining < 0) {
// Timeout - rethrow the failed assertion.
throw new RuntimeException(e);
}
}
}
}
}
/**
* Waits up to 5 seconds for the condition to succeed.
*
* @param cond
* The condition, which must throw an
* {@link AssertionFailedError} if it does not succeed.
*
* @throws AssertionFailedError
* if the condition does not succeed within the timeout.
*
* @see #assertCondition(Runnable, long, TimeUnit)
*/
static public void assertCondition(final Runnable cond) {
assertCondition(cond, 5, TimeUnit.SECONDS);
}
/**
* Returns random data that will fit in <i>nbytes</i>.
*
* @return A new {@link ByteBuffer} wrapping a new <code>byte[]</code>
* having random contents.
*/
protected ByteBuffer getRandomData(final int nbytes) {
final byte[] bytes = new byte[nbytes];
r.nextBytes(bytes);
return ByteBuffer.wrap(bytes);
}
/**
* Returns random data that will fit in <i>nbytes</i>.
*
* @return A new {@link ByteBuffer} wrapping a new <code>byte[]</code>
* having random contents.
*/
protected ByteBuffer getRandomData(final ByteBuffer b, final int nbytes) {
final byte[] a = new byte[nbytes];
r.nextBytes(a);
b.limit(nbytes);
b.position(0);
b.put(a);
b.flip();
return b;
}
/**
* Return an open port on current machine. Try the suggested port first. If
* suggestedPort is zero, just select a random port
*/
protected static int getPort(int suggestedPort) throws IOException {
ServerSocket openSocket;
try {
openSocket = new ServerSocket(suggestedPort);
} catch (BindException ex) {
// the port is busy, so look for a random open port
openSocket = new ServerSocket(0);
}
final int port = openSocket.getLocalPort();
openSocket.close();
if (suggestedPort != 0 && port != suggestedPort) {
log.warn("suggestedPort is busy: suggestedPort=" + suggestedPort + ", using port=" + port + " instead");
}
return port;
}
}