Testing
Testing concurrent systems can be more difficult than single threaded applications, since the test itself and the application are running on separate threads. Moreover, because of Riker's resilient self-healing approach where panics are isolated, handled and the failed component restarted, detecting failures in tests proves challenging.
To help make testing easier, the riker-testkit
introduces a 'probe' that can be sent to actors either through messaging or as part of an actor's Props
. Probes can then emit values back to the test thread.
Here's an example of testing an actor restart:
#[macro_use]
extern crate riker_testkit;
use riker::actors::*;
use riker_testkit::probe::{Probe, ProbeReceive};
use riker_testkit::probe::channel::{probe, ChannelProbe};
#[derive(Clone, Debug)]
pub struct Add;
#[derive(Clone, Debug)]
pub struct TestProbe(ChannelProbe<(), ()>);
#[actor(TestProbe, Add)]
struct Counter {
probe: Option<TestProbe>,
count: u32,
}
impl Counter {
fn actor() -> Counter {
Counter {
probe: None,
count: 0
}
}
}
impl Actor for Counter {
// we used the #[actor] attribute so CounterMsg is the Msg type
type Msg = CounterMsg;
type Evt = ();
fn recv(&mut self,
ctx: &Context<Self::Msg>,
msg: Self::Msg,
sender: Sender) {
self.receive(ctx, msg, sender);
}
}
impl Receive<TestProbe> for Counter {
type Msg = CounterMsg;
fn receive(&mut self,
_ctx: &Context<Self::Msg>,
msg: TestProbe,
_sender: Sender) {
self.probe = Some(msg)
}
}
impl Receive<Add> for Counter {
type Msg = CounterMsg;
fn receive(&mut self,
_ctx: &Context<Self::Msg>,
_msg: Add,
_sender: Sender) {
self.count += 1;
if self.count == 1_000_000 {
self.probe.as_ref().unwrap().0.event(())
}
}
}
#[test]
fn actor_tell() {
let sys = ActorSystem::new().unwrap();
let props = Props::new(Box::new(Counter::actor));
let actor = sys.actor_of(props, "me").unwrap();
let (probe, listen) = probe();
actor.tell(TestProbe(probe), None);
for _ in 0..1_000_000 {
actor.tell(Add, None);
}
p_assert_eq!(listen, ());
}
This test sends a test probe to the test actor, which is keeps and uses to signal back after one million test messages were received. The macro p_assert_eq!
waits (blocks) on the listener until a value is received from the probe.