package com.workshare.msnos.core;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import com.workshare.msnos.core.Cloud.Internal;
import com.workshare.msnos.core.Gateway.Listener;
import com.workshare.msnos.core.MsnosException.Code;
import com.workshare.msnos.core.cloud.IdentifiablesList;
import com.workshare.msnos.core.cloud.MessageValidators;
import com.workshare.msnos.core.protocols.ip.Endpoint;
import com.workshare.msnos.core.protocols.ip.Endpoints;
import com.workshare.msnos.core.protocols.ip.Network;
import com.workshare.msnos.soup.threading.Multicaster;
import com.workshare.msnos.soup.time.SystemTime;
public class CoreHelper {
private CoreHelper() {
}
public static void sleep(long duration, TimeUnit unit) {
try {
Thread.sleep(TimeUnit.MILLISECONDS.convert(duration, unit));
} catch (InterruptedException e) {
Thread.interrupted();
throw new RuntimeException("wtf?");
}
}
public static UUID randomUUID() {
return UUID.randomUUID();
}
public static Iden newCloudIden() {
return new Iden(Iden.Type.CLD, UUID.randomUUID());
}
public static Iden newAgentIden() {
return new Iden(Iden.Type.AGT, UUID.randomUUID());
}
public static <T> Set<T> asSet(T... items) {
return new HashSet<T>(Arrays.asList(items));
}
public static Network asPublicNetwork(String host) {
return asNetwork(host, (short) 1);
}
public static Network asNetwork(String host, short prefix) {
return new Network(toByteArray(host), prefix);
}
public static byte[] toByteArray(String host) {
String[] tokens = host.split("\\.");
byte[] addr = new byte[4];
for (int i = 0; i < addr.length; i++) {
addr[i] = (byte) (Integer.valueOf(tokens[i]) & 0xff);
}
return addr;
}
public static Multicaster<Listener, Message> synchronousGatewayMulticaster() {
Executor executor = new Executor() {
@Override
public void execute(Runnable task) {
task.run();
}
};
return new Multicaster<Listener, Message>(executor) {
@Override
protected void dispatch(Listener listener, Message message) {
listener.onMessage(message);
}
};
}
public static AtomicLong fakeSystemTime() {
return fakeSystemTime(0l);
}
public static AtomicLong fakeSystemTime(final long timeInMillis) {
final AtomicLong counter = new AtomicLong();
SystemTime.setTimeSource(new SystemTime.TimeSource() {
public long millis() {
if (timeInMillis == 0l)
return System.currentTimeMillis();
else
return timeInMillis;
}
public void sleep(long millis) throws InterruptedException {
Thread.sleep(millis);
counter.addAndGet(millis);
}
});
return counter;
}
public static void fakeElapseTime(final long elapsedInMillis) {
final long current = SystemTime.asMillis();
SystemTime.setTimeSource(new SystemTime.TimeSource() {
public long millis() {
return current + elapsedInMillis;
}
public void sleep(long millis) throws InterruptedException {
Thread.sleep(millis);
}
});
}
public static Endpoints makeImmutableEndpoints(final Set<Endpoint> all) {
return makeEndpoints(Collections.unmodifiableSet(all));
}
public static Endpoints makeMutableEndpoints() {
final Set<Endpoint> all = new HashSet<Endpoint>();
return makeEndpoints(Collections.unmodifiableSet(all));
}
private static Endpoints makeEndpoints(final Set<Endpoint> all) {
Endpoints endpoints = new Endpoints() {
@Override
public Set<? extends Endpoint> all() {
return all;
}
@Override
public Set<? extends Endpoint> publics() {
return asSet();
}
@Override
public Set<? extends Endpoint> of(Agent agent) {
return asSet();
}
@Override
public Endpoint install(Endpoint endpoint) throws MsnosException {
throw new MsnosException("I am a test :)", Code.UNRECOVERABLE_FAILURE);
}
@Override
public Endpoint remove(Endpoint endpoint) throws MsnosException {
throw new MsnosException("I am a test :)", Code.UNRECOVERABLE_FAILURE);
}
};
return endpoints;
}
public static com.workshare.msnos.core.cloud.Multicaster synchronousCloudMulticaster() {
return new com.workshare.msnos.core.cloud.Multicaster(new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
});
}
public static MessageBuilder newAPPMesage(Agent from, Identifiable to) {
return new MessageBuilder(Message.Type.APP, from, to);
}
public static MessageBuilder newAPPMesage(Iden from, Iden to) {
return new MessageBuilder(Message.Type.APP, from, to);
}
public static Cloud createMockCloud() {
return createMockCloud(null, null);
}
public static Cloud createMockCloud(final Iden iden, final Ring ring) {
Cloud cloud = mock(Cloud.class);
when(cloud.getIden()).thenReturn(iden == null ? newCloudIden() : iden);
when(cloud.getRing()).thenReturn(ring == null ? Ring.random() : ring);
Internal internal = mock(Cloud.Internal.class);
when(internal.sign(any(Message.class))).thenAnswer(new Answer<Message>(){
@Override
public Message answer(InvocationOnMock invocation) throws Throwable {
return (Message) invocation.getArguments()[0];
}});
when(internal.localAgents()).thenReturn(new IdentifiablesList<LocalAgent>());
when(internal.remoteAgents()).thenReturn(new IdentifiablesList<RemoteAgent>());
when(internal.remoteClouds()).thenReturn(new IdentifiablesList<RemoteEntity>());
when(internal.cloud()).thenReturn(cloud);
when(cloud.internal()).thenReturn(internal);
when(cloud.validators()).thenReturn(new MessageValidators(internal));
return cloud;
}
public static Agent createMockAgent() {
return createMockAgent(newAgentIden());
}
public static Agent createMockAgent(final Iden iden) {
Agent agent = mock(Agent.class);
when(agent.getIden()).thenReturn(iden);
when(agent.toString()).thenReturn(iden.toString());
return agent;
}
public static Cloud.Internal getCloudInternal(Cloud cloud) {
return cloud.internal();
}
@SuppressWarnings("rawtypes")
public static void runScheduledTasks(ScheduledExecutorService executor) throws Exception {
for (Callable callable : extractCallables(executor)) {
callable.call();
}
for (Runnable runnable : extractRunnables(executor)) {
runnable.run();
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private static List<Callable> extractCallables(ScheduledExecutorService executor) {
ArgumentCaptor<Callable> captor = ArgumentCaptor.forClass(Callable.class);
verify(executor, atMost(9999)).schedule(captor.capture(), anyLong(), any(TimeUnit.class));
return captor.getAllValues();
}
private static List<Runnable> extractRunnables(ScheduledExecutorService executor) {
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
verify(executor, atMost(9999)).schedule(captor.capture(), anyLong(), any(TimeUnit.class));
verify(executor, atMost(9999)).scheduleAtFixedRate(captor.capture(), anyLong(), anyLong(), any(TimeUnit.class));
verify(executor, atMost(9999)).scheduleWithFixedDelay(captor.capture(), anyLong(), anyLong(), any(TimeUnit.class));
return captor.getAllValues();
}
}