2012-06-29 14:42:11 +02:00
|
|
|
/**
|
|
|
|
|
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
|
|
|
|
|
*/
|
|
|
|
|
package akka.testkit;
|
|
|
|
|
|
|
|
|
|
import scala.runtime.AbstractFunction0;
|
|
|
|
|
import akka.actor.ActorRef;
|
|
|
|
|
import akka.actor.ActorSystem;
|
|
|
|
|
import akka.event.Logging;
|
|
|
|
|
import akka.event.Logging.LogEvent;
|
2012-08-08 16:05:48 +02:00
|
|
|
import akka.japi.JavaPartialFunction;
|
2012-06-29 14:42:11 +02:00
|
|
|
import akka.japi.Util;
|
2012-07-06 17:04:04 +02:00
|
|
|
import scala.concurrent.util.Duration;
|
2012-09-14 10:08:40 +02:00
|
|
|
import scala.concurrent.util.FiniteDuration;
|
2012-06-29 14:42:11 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Java API for the TestProbe. Proper JavaDocs to come once JavaDoccing is implemented.
|
|
|
|
|
*/
|
|
|
|
|
public class JavaTestKit {
|
|
|
|
|
private final TestProbe p;
|
|
|
|
|
|
|
|
|
|
public JavaTestKit(ActorSystem system) {
|
|
|
|
|
p = new TestProbe(system);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ActorRef getRef() {
|
|
|
|
|
return p.ref();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ActorSystem getSystem() {
|
|
|
|
|
return p.system();
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
static public FiniteDuration duration(String s) {
|
|
|
|
|
final Duration ret = Duration.apply(s);
|
|
|
|
|
if (ret instanceof FiniteDuration) return (FiniteDuration) ret;
|
|
|
|
|
else throw new IllegalArgumentException("duration() is only for finite durations, use Duration.Inf() and friends");
|
2012-06-29 14:42:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Duration dilated(Duration d) {
|
|
|
|
|
return d.mul(TestKitExtension.get(p.system()).TestTimeFactor());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean msgAvailable() {
|
|
|
|
|
return p.msgAvailable();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ActorRef getLastSender() {
|
|
|
|
|
return p.lastMessage().sender();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void send(ActorRef actor, Object msg) {
|
|
|
|
|
actor.tell(msg, p.ref());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void forward(ActorRef actor) {
|
|
|
|
|
actor.tell(p.lastMessage().msg(), p.lastMessage().sender());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void reply(Object msg) {
|
|
|
|
|
p.lastMessage().sender().tell(msg, p.ref());
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
public FiniteDuration getRemainingTime() {
|
2012-06-29 14:42:11 +02:00
|
|
|
return p.remaining();
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
public FiniteDuration getRemainingTimeOr(FiniteDuration def) {
|
2012-06-29 14:42:11 +02:00
|
|
|
return p.remainingOr(def);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ActorRef watch(ActorRef ref) {
|
|
|
|
|
return p.watch(ref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ActorRef unwatch(ActorRef ref) {
|
|
|
|
|
return p.unwatch(ref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract class IgnoreMsg {
|
|
|
|
|
abstract protected boolean ignore(Object msg);
|
|
|
|
|
|
|
|
|
|
public IgnoreMsg() {
|
2012-08-08 16:05:48 +02:00
|
|
|
p.ignoreMsg(new JavaPartialFunction<Object, Object>() {
|
2012-06-29 14:42:11 +02:00
|
|
|
public Boolean apply(Object in, boolean isCheck) {
|
|
|
|
|
return ignore(in);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ignoreNoMsg() {
|
|
|
|
|
p.ignoreNoMsg();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setAutoPilot(TestActor.AutoPilot pilot) {
|
|
|
|
|
p.setAutoPilot(pilot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract class Within {
|
|
|
|
|
protected abstract void run();
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
public Within(FiniteDuration max) {
|
2012-06-29 14:42:11 +02:00
|
|
|
p.within(max, new AbstractFunction0<Object>() {
|
|
|
|
|
public Object apply() {
|
|
|
|
|
run();
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
public Within(FiniteDuration min, FiniteDuration max) {
|
2012-06-29 14:42:11 +02:00
|
|
|
p.within(min, max, new AbstractFunction0<Object>() {
|
|
|
|
|
public Object apply() {
|
|
|
|
|
run();
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract class AwaitCond {
|
|
|
|
|
protected abstract boolean cond();
|
|
|
|
|
|
|
|
|
|
public AwaitCond() {
|
|
|
|
|
this(Duration.Undefined(), p.awaitCond$default$3());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public AwaitCond(Duration max) {
|
|
|
|
|
this(max, p.awaitCond$default$3());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public AwaitCond(Duration max, Duration interval) {
|
|
|
|
|
p.awaitCond(new AbstractFunction0<Object>() {
|
|
|
|
|
public Object apply() {
|
|
|
|
|
return cond();
|
|
|
|
|
}
|
|
|
|
|
}, max, interval);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract class ExpectMsg<T> {
|
|
|
|
|
private final T result;
|
|
|
|
|
|
|
|
|
|
public ExpectMsg(String hint) {
|
|
|
|
|
this(Duration.Undefined(), hint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ExpectMsg(Duration max, String hint) {
|
|
|
|
|
final Object received = p.receiveOne(max);
|
|
|
|
|
try {
|
|
|
|
|
result = match(received);
|
2012-08-08 16:05:48 +02:00
|
|
|
} catch (JavaPartialFunction.NoMatchException ex) {
|
2012-06-29 14:42:11 +02:00
|
|
|
throw new AssertionError("while expecting '" + hint
|
|
|
|
|
+ "' received unexpected: " + received);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
abstract protected T match(Object msg);
|
|
|
|
|
|
|
|
|
|
protected RuntimeException noMatch() {
|
2012-08-08 16:05:48 +02:00
|
|
|
throw JavaPartialFunction.noMatch();
|
2012-06-29 14:42:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public T get() {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public <T> T expectMsgEquals(T msg) {
|
|
|
|
|
return p.expectMsg(msg);
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
public <T> T expectMsgEquals(FiniteDuration max, T msg) {
|
2012-06-29 14:42:11 +02:00
|
|
|
return p.expectMsg(max, msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public <T> T expectMsgClass(Class<T> clazz) {
|
|
|
|
|
return p.expectMsgClass(clazz);
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
public <T> T expectMsgClass(FiniteDuration max, Class<T> clazz) {
|
2012-06-29 14:42:11 +02:00
|
|
|
return p.expectMsgClass(max, clazz);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Object expectMsgAnyOf(Object... msgs) {
|
|
|
|
|
return p.expectMsgAnyOf(Util.arrayToSeq(msgs));
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
public Object expectMsgAnyOf(FiniteDuration max, Object... msgs) {
|
2012-06-29 14:42:11 +02:00
|
|
|
return p.expectMsgAnyOf(max, Util.arrayToSeq(msgs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Object[] expectMsgAllOf(Object... msgs) {
|
|
|
|
|
return (Object[]) p.expectMsgAllOf(Util.arrayToSeq(msgs)).toArray(
|
2012-07-06 17:04:04 +02:00
|
|
|
Util.classTag(Object.class));
|
2012-06-29 14:42:11 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
public Object[] expectMsgAllOf(FiniteDuration max, Object... msgs) {
|
2012-06-29 14:42:11 +02:00
|
|
|
return (Object[]) p.expectMsgAllOf(max, Util.arrayToSeq(msgs)).toArray(
|
2012-07-06 17:04:04 +02:00
|
|
|
Util.classTag(Object.class));
|
2012-06-29 14:42:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
public <T> T expectMsgAnyClassOf(Class<? extends T>... classes) {
|
|
|
|
|
final Object result = p.expectMsgAnyClassOf(Util.arrayToSeq(classes));
|
|
|
|
|
return (T) result;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
public Object expectMsgAnyClassOf(FiniteDuration max, Class<?>... classes) {
|
2012-06-29 14:42:11 +02:00
|
|
|
return p.expectMsgAnyClassOf(max, Util.arrayToSeq(classes));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void expectNoMsg() {
|
|
|
|
|
p.expectNoMsg();
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-14 10:08:40 +02:00
|
|
|
public void expectNoMsg(FiniteDuration max) {
|
2012-06-29 14:42:11 +02:00
|
|
|
p.expectNoMsg(max);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract class ReceiveWhile<T> {
|
2012-08-09 18:15:38 +02:00
|
|
|
abstract protected T match(Object msg) throws Exception;
|
2012-06-29 14:42:11 +02:00
|
|
|
|
|
|
|
|
private Object results;
|
|
|
|
|
|
|
|
|
|
public ReceiveWhile(Class<T> clazz) {
|
|
|
|
|
this(clazz, Duration.Undefined());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ReceiveWhile(Class<T> clazz, Duration max) {
|
|
|
|
|
this(clazz, max, Duration.Inf(), Integer.MAX_VALUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ReceiveWhile(Class<T> clazz, Duration max, int messages) {
|
|
|
|
|
this(clazz, max, Duration.Inf(), messages);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
public ReceiveWhile(Class<T> clazz, Duration max, Duration idle, int messages) {
|
|
|
|
|
results = p.receiveWhile(max, idle, messages,
|
|
|
|
|
new CachingPartialFunction<Object, T>() {
|
2012-08-09 18:15:38 +02:00
|
|
|
public T match(Object msg) throws Exception {
|
|
|
|
|
return ReceiveWhile.this.match(msg);
|
2012-06-29 14:42:11 +02:00
|
|
|
}
|
2012-07-06 17:04:04 +02:00
|
|
|
}).toArray(Util.classTag(clazz));
|
2012-06-29 14:42:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected RuntimeException noMatch() {
|
2012-08-08 16:05:48 +02:00
|
|
|
throw JavaPartialFunction.noMatch();
|
2012-06-29 14:42:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
public T[] get() {
|
|
|
|
|
return (T[]) results;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract class EventFilter<T> {
|
|
|
|
|
abstract protected T run();
|
|
|
|
|
|
|
|
|
|
private final Class<? extends Logging.LogEvent> clazz;
|
|
|
|
|
|
|
|
|
|
private String source = null;
|
|
|
|
|
private String message = null;
|
|
|
|
|
private boolean pattern = false;
|
|
|
|
|
private boolean complete = false;
|
|
|
|
|
private int occurrences = Integer.MAX_VALUE;
|
|
|
|
|
private Class<? extends Throwable> exceptionType = null;
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
public EventFilter(Class<?> clazz) {
|
|
|
|
|
if (Throwable.class.isAssignableFrom(clazz)) {
|
|
|
|
|
this.clazz = Logging.Error.class;
|
|
|
|
|
exceptionType = (Class<? extends Throwable>) clazz;
|
|
|
|
|
} else if (Logging.LogEvent.class.isAssignableFrom(clazz)) {
|
|
|
|
|
this.clazz = (Class<? extends LogEvent>) clazz;
|
|
|
|
|
} else throw new IllegalArgumentException("supplied class must either be LogEvent or Throwable");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public T exec() {
|
|
|
|
|
akka.testkit.EventFilter filter;
|
|
|
|
|
if (clazz == Logging.Error.class) {
|
|
|
|
|
if (exceptionType == null) exceptionType = Logging.noCause().getClass();
|
|
|
|
|
filter = new ErrorFilter(exceptionType, source, message, pattern, complete, occurrences);
|
|
|
|
|
} else if (clazz == Logging.Warning.class) {
|
|
|
|
|
filter = new WarningFilter(source, message, pattern, complete, occurrences);
|
|
|
|
|
} else if (clazz == Logging.Info.class) {
|
|
|
|
|
filter = new InfoFilter(source, message, pattern, complete, occurrences);
|
|
|
|
|
} else if (clazz == Logging.Debug.class) {
|
|
|
|
|
filter = new DebugFilter(source, message, pattern, complete, occurrences);
|
|
|
|
|
} else throw new IllegalArgumentException("unknown LogLevel " + clazz);
|
|
|
|
|
return filter.intercept(new AbstractFunction0<T>() {
|
|
|
|
|
public T apply() {
|
|
|
|
|
return run();
|
|
|
|
|
}
|
|
|
|
|
}, p.system());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EventFilter<T> message(String msg) {
|
|
|
|
|
message = msg;
|
|
|
|
|
pattern = false;
|
|
|
|
|
complete = true;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EventFilter<T> startsWith(String msg) {
|
|
|
|
|
message = msg;
|
|
|
|
|
pattern = false;
|
|
|
|
|
complete = false;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EventFilter<T> matches(String regex) {
|
|
|
|
|
message = regex;
|
|
|
|
|
pattern = true;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EventFilter<T> from(String source) {
|
|
|
|
|
this.source = source;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EventFilter<T> occurrences(int number) {
|
|
|
|
|
occurrences = number;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|