package com.limegroup.gnutella.downloader;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import org.limewire.listener.EventListener;
import org.limewire.util.AssertComparisons;
import com.limegroup.gnutella.Downloader;
import com.limegroup.gnutella.Downloader.DownloadState;
public class DownloadTestUtils {
private DownloadTestUtils() {}
/** Waits 1 second for the given state. */
public static void waitForState(Downloader downloader, DownloadState state) throws Exception {
waitForState(downloader, state, 2, TimeUnit.SECONDS);
}
/** Waits the duration for the given state. */
public static void waitForState(Downloader downloader, DownloadState state, long timeout, TimeUnit unit) throws Exception {
timeout = unit.toMillis(timeout);
while(timeout > 0 && downloader.getState() != state) {
long now = System.currentTimeMillis();
Thread.sleep(50);
timeout -= System.currentTimeMillis() - now;
}
AssertComparisons.assertEquals(state, downloader.getState());
}
/** Waits for the given state, only allowing the allowed states while waiting. */
public static void strictWaitForState(Downloader downloader, DownloadState state, DownloadState... allowed) throws Exception {
strictWaitForState(downloader, state, 2, TimeUnit.SECONDS, allowed);
}
/** Waits the duration for the given state, only allowing the allowed states while waiting. */
public static void strictWaitForState(Downloader downloader, DownloadState state, long timeout, TimeUnit unit, DownloadState... allowed) throws Exception {
timeout = unit.toMillis(timeout);
while(timeout > 0 && downloader.getState() != state) {
DownloadState current = downloader.getState();
if(!Arrays.asList(allowed).contains(current)) {
AssertComparisons.fail("Current state: " + current + ", not in allowed states: " + Arrays.asList(allowed));
}
long now = System.currentTimeMillis();
Thread.sleep(200);
timeout -= System.currentTimeMillis() - now;
}
AssertComparisons.assertEquals(state, downloader.getState());
}
public static void pumpThroughStates(Downloader downloader, Runnable pump, DownloadState startState, DownloadState endState, DownloadState... middleStates) throws Exception {
pumpThroughStates(downloader, pump, startState, endState, 2, TimeUnit.SECONDS, middleStates);
}
public static void pumpThroughStates(Downloader downloader, Runnable pump, DownloadState startState, DownloadState endState, long timeout, TimeUnit unit, DownloadState... middleStates) throws Exception {
AssertComparisons.assertEquals(startState, downloader.getState());
timeout = unit.toMillis(timeout);
// Jump out of the start state immediately.
StateListener stateListener = new StateListener();
downloader.addListener(stateListener);
timeout = waitForStatesToEnd(downloader, pump, timeout, startState);
if(downloader.getState() == startState) {
// If it's still in the start state, see if it ran through some states while getting there.
if(stateListener.states.isEmpty()) {
// This is an additional assertion incase start & end are the same,
// in which case we want to be extra certain that some middle states are involved.
AssertComparisons.fail("Still in start state: " + startState);
} else {
// It had some intermediate states, let's make sure they were valid.
for(DownloadState state : stateListener.states) {
if(!Arrays.asList(middleStates).contains(state) && state != endState) {
AssertComparisons.fail("Went to unexpected state: " + state + ", expected one of: " + endState + ", or: " + Arrays.asList(middleStates));
}
}
}
}
// Then loop through the middle states.
// (We do the first one separate to ensure that we can cycle from start -> end even if start & end are the same)
while(timeout > 0 && downloader.getState() != endState) {
timeout = waitForStatesToEnd(downloader, pump, timeout, middleStates);
if(!Arrays.asList(middleStates).contains(downloader.getState()) && downloader.getState() != endState) {
AssertComparisons.fail("In unexpected state: " + downloader.getState() + ", expected one of: " + endState + ", or: " + Arrays.asList(middleStates));
}
}
if(downloader.getState() != endState) {
AssertComparisons.fail("Invalid end state: " + downloader.getState() + ", required: " + endState);
}
}
private static long waitForStatesToEnd(Downloader downloader, Runnable pump, long timeout, DownloadState... possibleStates) throws Exception {
while(timeout > 0 && Arrays.asList(possibleStates).contains(downloader.getState())) {
// System.out.println("timeout: " + timeout + ", possible: " + Arrays.asList(possibleStates) + ", current: " + downloader.getState());
long now = System.currentTimeMillis();
Thread.sleep(50);
timeout -= System.currentTimeMillis() - now;
pump.run();
}
// System.out.println("exited. timeout: " + timeout + ", possible: " + Arrays.asList(possibleStates) + ", current: " + downloader.getState());
return timeout;
}
private static class StateListener implements EventListener<DownloadStateEvent> {
private final List<DownloadState> states = new CopyOnWriteArrayList<DownloadState>();
@Override
public void handleEvent(DownloadStateEvent event) {
states.add(event.getType());
}
}
}