package org.dcache.services.info.base;
import org.hamcrest.Matcher;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* A collection of methods that are useful to multiple tests.
*
* @author Paul Millar <paul.millar@desy.de>
*/
public class InfoBaseTestHelper
{
private static final long ROUNDING_PERIOD_IN_MS = 500;
private static final long TIMING_TOLERANCE = 400;
/**
* A test-and-set routine that checks whether a hashCode has already been
* seen. If it has not, an Integer is added to the Set.
* @param seenHashCodes the Set for storing the hashes
* @param hash the hash value to test-and-set.
* @return true if the hash has already been seen, false otherwise.
*/
protected boolean hashAlreadySeen( Set<Integer> seenHashCodes, int hash) {
Integer hashInt = hash;
if( seenHashCodes.contains(hash)) {
return true;
}
seenHashCodes.add( hashInt);
return false;
}
/**
* Assert that a StateComponent is not null and ephemeral.
* @param msg a String message to display if the StateComponent is not ephemeral.
* @param component the StateComponent to test.
*/
protected void assertIsEphemeral( String msg, StateComponent component) {
assertNotNull( msg, component);
assertFalse( msg, component.isImmortal());
assertTrue( msg, component.isEphemeral());
assertFalse( msg, component.isMortal());
assertNull(msg, component.getExpiryDate());
assertFalse( msg, component.hasExpired());
}
/**
* Assert that a StateComponent is not null and immortal.
* @param msg a String message to display if the StateComponent is not immortal.
* @param component the StateComponent to test.
*/
protected void assertIsImmortal( String msg, StateComponent component) {
assertNotNull( msg, component);
assertTrue( msg, component.isImmortal());
assertFalse( msg, component.isEphemeral());
assertFalse( msg, component.isMortal());
assertNull(msg, component.getExpiryDate());
assertFalse( msg, component.hasExpired());
}
/**
* Assert that a StateComponent is not null is mortal and will expire at the expected number
* of seconds in the future.
* @param msg a String message to display if the StateComponent is not mortal.
* @param component the StateComponent to test.
* @param lifetime the expected lifetime of this StateComponent, in seconds.
*/
protected void assertIsMortal(String msg, StateComponent component, long lifetime)
{
assertNotNull(msg, component);
assertFalse(msg + " [isImmortal]", component.isImmortal());
assertFalse(msg + " [isEphemeral]", component.isEphemeral());
assertTrue(msg + " [isMortal]", component.isMortal());
long duration = SECONDS.toMillis((lifetime < 0) ? 0 : lifetime);
long expectedExpiry = System.currentTimeMillis() + duration;
// Ideally expected and actual times match exactly; but,
// because System.currentTimeMillis() is called at different
// times (here and in the StateComponent constructor) the value
// can be different.
// We provide different matchers to make as strong a statement
// as possible while allowing for this discrepency.
Matcher<Long> matcher;
if (component instanceof StateValue && duration > 0) {
// As there is rounding, the difference should be exactly 0
// or exactly ROUNDING_PERIOD_IN_MS, provided not more than
// ROUNDING_PERIOD_IN_MS has elapsed.
expectedExpiry = ROUNDING_PERIOD_IN_MS * (1 + (expectedExpiry - 1) / ROUNDING_PERIOD_IN_MS);
matcher = either(equalTo(0L)).or(equalTo(ROUNDING_PERIOD_IN_MS));
} else {
// No rounding, simply check it is close enough.
matcher = both(greaterThanOrEqualTo(0L)).and(lessThan(TIMING_TOLERANCE));
}
long delta = expectedExpiry - component.getExpiryDate().getTime();
assertThat(msg + " [expected-getExpiryDate]", delta, matcher);
}
/**
* Assert that the laterDate is between earlierDate + timeInFuture-tolerance and
* earlierDate + timeInFuture+tolerance.
* @param msg
* @param earlierDate
* @param laterDate
* @param timeInFuture
* @param tolerance
*/
protected void assertDatedDuration( String msg, Date earlierDate, Date laterDate, long timeInFuture, long tolerance) {
long s = TimeUnit.SECONDS.convert( laterDate.getTime() - earlierDate.getTime(), TimeUnit.MILLISECONDS);
assertTrue( msg + " (time mismatch; expected: " + Long.toString(timeInFuture) + ", got: " + Long.toString( s)+")", Math.abs( timeInFuture - s) <= tolerance);
}
public static StateTransition buildTransition( StatePath path, StateValue metric) throws BadStatePathException {
StateTransition transition = new StateTransition();
StateUpdate update = new StateUpdate();
update.appendUpdate( path, metric);
update.updateTransition( new StateComposite(), transition);
return transition;
}
}