2

我对我的系统编程很陌生Akka并且习惯于Java编程。

问题定义
- 我有一个TenantMonitor在接收TenantMonitorMessage()时启动一个新角色的方法DiskMonitorActor
-DiskMonitorActor可能因各种原因失败并可能抛出DiskException. DiskMonitorActor已经过单元测试 。

我需要的?
- 我想测试行为TenantMonitorActor,这样当DiskException发生时,它会采取正确的行动,比如stop()resume()或任何(取决于我的应用程序可能需要什么)

我试过什么?
根据文档,我可以执行的最接近的是名为Expecting Log Messages的部分。

我在哪里需要帮助?
- 虽然我理解期望正确的错误日志很重要,但它只是断言第一部分,该异常被抛出并被正确记录,但无助于断言正确strategy被调用

代码?
TenantMonitorActor

public class TenantMonitorActor extends UntypedActor {

  public static final String DISK_MONITOR = "diskMonitor";
  private static final String assetsLocationKey = "tenant.assetsLocation";
  private static final String schedulerKey = "monitoring.tenant.disk.schedule.seconds";
  private static final String thresholdPercentKey = "monitoring.tenant.disk.threshold.percent";

  private final LoggingAdapter logging = Logging.getLogger(getContext().system(), this);
  private final Config config;

  private TenantMonitorActor(final Config config) {
    this.config = config;
  }

  private static final SupervisorStrategy strategy =
      new OneForOneStrategy(1, Duration.create(1, TimeUnit.SECONDS),
                            new Function<Throwable, Directive>() {

                              public Directive apply(final Throwable param) throws Exception {
                                if (param instanceof DiskException) {
                                  return stop();
                                }
                                return restart();
                              }
                            });

  public static Props props(final Config config) {
    return Props.create(new Creator<TenantMonitorActor>(){
      public TenantMonitorActor create() throws Exception {
        return new TenantMonitorActor(config);
      }
    });
  }

  @Override
  public void onReceive(final Object message) throws Exception {
    if (message instanceof TenantMonitorMessage) {
      logging.info("Tenant Monitor Setup");
      setupDiskMonitoring();
    }
  }

  @Override
  public SupervisorStrategy supervisorStrategy() {
    return strategy;
  }



  private void setupDiskMonitoring() {
    final ActorRef diskMonitorActorRef = getDiskMonitorActorRef(config);

    final FiniteDuration start = Duration.create(0, TimeUnit.SECONDS);
    final FiniteDuration recurring = Duration.create(config.getInt(schedulerKey),
                                                     TimeUnit.SECONDS);

    final ActorSystem system = getContext().system();
    system.scheduler()
        .schedule(start, recurring, diskMonitorActorRef,
                  new DiskMonitorMessage(), system.dispatcher(), null);
  }

  private ActorRef getDiskMonitorActorRef(final Config monitoringConf) {
    final Props diskMonitorProps =
        DiskMonitorActor.props(new File(monitoringConf.getString(assetsLocationKey)),
                               monitoringConf.getLong(thresholdPercentKey));
    return getContext().actorOf(diskMonitorProps, DISK_MONITOR);

  }
}

测试

  @Test
  public void testActorForNonExistentLocation() throws Exception {
    final Map<String, String> configValues =
        Collections.singletonMap("tenant.assetsLocation", "/non/existentLocation");
    final Config config = mergeConfig(configValues);

    new JavaTestKit(system) {{
      assertEquals("system", system.name());

      final Props props = TenantMonitorActor.props(config);
      final ActorRef supervisor = system.actorOf(props, "supervisor");
      new EventFilter<Void>(DiskException.class) {

        @Override
        protected Void run() {
          supervisor.tell(new TenantMonitorMessage(), ActorRef.noSender());
          return null;
        }
      }.from("akka://system/user/supervisor/diskMonitor").occurrences(1).exec();

    }};
  }

更新
我能写的最好的方法是确保DiskMonitor一旦发生异常就停止

@Test
  public void testSupervisorForFailure() {
    new JavaTestKit(system) {{

      final Map<String, String> configValues =
          Collections.singletonMap("tenant.assetsLocation", "/non/existentLocation");
      final Config config = mergeConfig(configValues);

      final TestActorRef<TenantMonitorActor> tenantTestActorRef = getTenantMonitorActor(config);
      final ActorRef diskMonitorRef = tenantTestActorRef.underlyingActor().getContext()
          .getChild(TenantMonitorActor.DISK_MONITOR);

      final TestProbe testProbeDiskMonitor = new TestProbe(system);
      testProbeDiskMonitor.watch(diskMonitorRef);
      tenantTestActorRef.tell(new TenantMonitorMessage(), getRef());
      testProbeDiskMonitor.expectMsgClass(Terminated.class);
    }};
  }

有没有更好的方法?

4

1 回答 1

1

I have the feeling that testing supervisor strategy is some sort of grey area -- it is up to personal opinion where we start testing Akka itself, instead of one's understanding of how the framework works. Testing validation of entities in ORM frameworks strikes me as a similar problem. We don't want to test whether email validation logic is correct (e.g. in Hibernate), but rather if our rule is correctly declared.

Following this logic, I would write the test as follows:

final TestActorRef<TenantMonitorActor> tenantTestActorRef =
  getTenantMonitorActor(config);
SupervisorStrategy.Directive directive = tenantTestActorRef.underlyingActor()
  .supervisorStrategy().decider().apply(new DiskException());
assertEquals(SupervisorStrategy.stop(), directive);
于 2016-01-30T14:38:46.537 回答