1

I'm testing how a new Actor I'm working on handles unexpected messages. I'd like to assert that it throws a GibberishException in these cases. Here's the test and the implementation so far:

Test:

"""throw a GibberishException for unrecognized messages""" in {
  //define a service that creates gibberish-speaking repositories
  val stubs = new svcStub(
    actorOf(new Actor{
      def receive = { case _ => {
          self.channel ! "you're savage with the cabbage"
        }
      }
    })
  )
  val model = actorOf(new HomeModel(stubs.svc,stubs.store))
  val supervisor = Supervisor(
    SupervisorConfig(
      OneForOneStrategy(List(classOf[Exception]), 3, 1000),
      Supervise(model,Permanent) :: Nil
    )
  )
  try{
    intercept[GibberishException] {
      supervisor.start
      model !! "plan"
    }
  } finally {
    supervisor.shutdown
  }
  stubs.store.plan should equal (null)
  stubs.svcIsOpen should be (false)
}

Implementation:

class HomeModel(service: PlanService, store: HomeStore)
extends Actor {
  private val loaderRepo = service.getRepo()
  private var view: Channel[Any] = null

  override def postStop() = {
    service.close()
  }

  def receive = {
    case "plan" => {
      view=self.channel
      loaderRepo ! LoadRequest()
    }
    case p: Plan => {
      store.plan=p
      view ! store.plan
    }
    case _ => throw new GibberishException(_)
  }
}

However, when I run the test, the exception details get to the Supervisor I established, but I don't know how to do anything with them (like log them or test their type). I'd like to be able to get the exception details here from the supervisor so i can rethrow and intercept them in my test. Outside of a test method, I could imagine this being useful if you wanted to report the nature of an exception in the UI of a running app. Is there a way to get this from the Supervisor when it happens?

Eugene Loy
  • 12,224
  • 8
  • 53
  • 79
traffichazard
  • 1,247
  • 1
  • 9
  • 13

1 Answers1

3

Change the OneForOneStrategy to only handle GibberishException, should solve it.

Viktor Klang
  • 26,479
  • 7
  • 51
  • 68
  • But how do I log or otherwise act upon the exception from within the Supervisor? I don't see where there is a hook to add error handling code there. I understand that it will restart the actor, but what if I want to do something more than that, like log the exception or display a message to the user? – traffichazard Aug 08 '11 at 01:36
  • The exception is already logged by Akka If you want to send a message to the user, use !!! instead of ! and you'll have the exception in the Future. – Viktor Klang Aug 08 '11 at 06:52
  • Changing the strategy to handle GibberishException only and replacing the !! in the `intercept` block of the test with a !!! followed by a `get` on the future it returns gives me the same result. The `GibberishException` goes off uncaught, dumping to my command line, and ScalaTest fails the test with `Expected exception org.thimblus.model.GibberishException to be thrown, but akka.dispatch.FutureTimeoutException was thrown.` It looks like the exception is getting thrown in a different thread than the one where the test waits for it. – traffichazard Aug 09 '11 at 02:18
  • But you only throw it as the fallthrough, but you only send "plan" which is handled by another case. – Viktor Klang Aug 09 '11 at 16:14
  • You may be missing the full flow of messages here. The test sends "plan" to `model`. `model` reacts to this by storing a reference to the test and sending a `LoadRequest` to `loaderRepo`. `loaderRepo` replies with `"you're savage with the cabbage"`. `model` can't match this message so it throws a `GibberishException`. I want the test to notice this exception. (the non-failure case, which I'm not testing in the code shown here, involves the repo sending a `Plan` object to the model, and the model sending it to the view reference it stored when it got the `"plan"` message) – traffichazard Aug 09 '11 at 17:29
  • The test is standing in for the view here, and I want it to get what the view should get, including pertinent error information. HomeModel's responsibility is to route the view's requests for information to appropriate repositories and then respond to the view with the loaded information. – traffichazard Aug 09 '11 at 23:49
  • But you aren't using "forward" so you're not preserving the original sender, so when the exception occurs it cannot be propagated to the !! – Viktor Klang Aug 10 '11 at 06:52