@Test
  public void testUnsubscribeRemovesAllSubscriptionsForThatEntity() throws Exception {
    policy.subscribe(entity, TestEntity.SEQUENCE, listener);
    policy.subscribe(entity, TestEntity.NAME, listener);
    policy.subscribe(entity, TestEntity.MY_NOTIF, listener);
    policy.subscribe(otherEntity, TestEntity.SEQUENCE, listener);
    policy.unsubscribe(entity);

    entity.setAttribute(TestEntity.SEQUENCE, 123);
    entity.setAttribute(TestEntity.NAME, "myname");
    entity.emit(TestEntity.MY_NOTIF, 456);
    otherEntity.setAttribute(TestEntity.SEQUENCE, 789);

    Thread.sleep(SHORT_WAIT_MS);
    Asserts.succeedsEventually(
        new Runnable() {
          @Override
          public void run() {
            assertEquals(
                listener.events,
                ImmutableList.of(
                    new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, otherEntity, 789)));
          }
        });
  }
  @Test
  public void testServiceReplacerWorksAfterRebind() throws Exception {
    Location origLoc =
        origManagementContext
            .getLocationManager()
            .createLocation(LocationSpec.create(SimulatedLocation.class));
    DynamicCluster origCluster =
        origApp.createAndManageChild(
            EntitySpec.create(DynamicCluster.class)
                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(TestEntity.class))
                .configure(DynamicCluster.INITIAL_SIZE, 3));
    origApp.start(ImmutableList.<Location>of(origLoc));

    origCluster.addPolicy(
        PolicySpec.create(ServiceReplacer.class)
            .configure(ServiceReplacer.FAILURE_SENSOR_TO_MONITOR, HASensors.ENTITY_FAILED));

    // rebind
    TestApplication newApp = rebind();
    final DynamicCluster newCluster =
        (DynamicCluster)
            Iterables.find(newApp.getChildren(), Predicates.instanceOf(DynamicCluster.class));

    // stimulate the policy
    final Set<Entity> initialMembers = ImmutableSet.copyOf(newCluster.getMembers());
    final TestEntity e1 = (TestEntity) Iterables.get(initialMembers, 1);

    newApp
        .getManagementContext()
        .getSubscriptionManager()
        .subscribe(e1, HASensors.ENTITY_FAILED, eventListener);
    newApp
        .getManagementContext()
        .getSubscriptionManager()
        .subscribe(e1, HASensors.ENTITY_RECOVERED, eventListener);

    e1.emit(HASensors.ENTITY_FAILED, new FailureDescriptor(e1, "simulate failure"));

    // Expect e1 to be replaced
    Asserts.succeedsEventually(
        new Runnable() {
          @Override
          public void run() {
            Set<Entity> newMembers =
                Sets.difference(ImmutableSet.copyOf(newCluster.getMembers()), initialMembers);
            Set<Entity> removedMembers =
                Sets.difference(initialMembers, ImmutableSet.copyOf(newCluster.getMembers()));
            assertEquals(removedMembers, ImmutableSet.of(e1));
            assertEquals(newMembers.size(), 1);
            assertEquals(
                ((TestEntity) Iterables.getOnlyElement(newMembers)).getCallHistory(),
                ImmutableList.of("start"));

            // TODO e1 not reporting "start" after rebind because callHistory is a field rather than
            // an attribute, so was not persisted
            Asserts.assertEqualsIgnoringOrder(e1.getCallHistory(), ImmutableList.of("stop"));
            assertFalse(Entities.isManaged(e1));
          }
        });
  }
  @Test
  public void testServiceRestarterWorksAfterRebind() throws Exception {
    origEntity.addPolicy(
        PolicySpec.create(ServiceRestarter.class)
            .configure(ServiceRestarter.FAILURE_SENSOR_TO_MONITOR, HASensors.ENTITY_FAILED));

    TestApplication newApp = rebind();
    final TestEntity newEntity =
        (TestEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(TestEntity.class));

    newEntity.emit(HASensors.ENTITY_FAILED, new FailureDescriptor(origEntity, "simulate failure"));

    Asserts.succeedsEventually(
        new Runnable() {
          @Override
          public void run() {
            assertEquals(newEntity.getCallHistory(), ImmutableList.of("restart"));
          }
        });
  }
  @Test
  public void testSubscriptionReceivesEvents() throws Exception {
    policy.subscribe(entity, TestEntity.SEQUENCE, listener);
    policy.subscribe(entity, TestEntity.NAME, listener);
    policy.subscribe(entity, TestEntity.MY_NOTIF, listener);

    otherEntity.setAttribute(TestEntity.SEQUENCE, 456);
    entity.setAttribute(TestEntity.SEQUENCE, 123);
    entity.setAttribute(TestEntity.NAME, "myname");
    entity.emit(TestEntity.MY_NOTIF, 789);

    Asserts.succeedsEventually(
        new Runnable() {
          @Override
          public void run() {
            assertEquals(
                listener.events,
                ImmutableList.of(
                    new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, entity, 123),
                    new BasicSensorEvent<String>(TestEntity.NAME, entity, "myname"),
                    new BasicSensorEvent<Integer>(TestEntity.MY_NOTIF, entity, 789)));
          }
        });
  }