@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(groups = "Integration")
  public void testWaitsForServiceUp() throws Exception {
    entity.setAttribute(TestEntity.SERVICE_UP, false);

    entity.addEnricher(
        HttpLatencyDetector.builder().url(baseUrl).period(100, TimeUnit.MILLISECONDS).build());

    // nothing until url is set
    EntityTestUtils.assertAttributeEqualsContinually(
        MutableMap.of("timeout", 200),
        entity,
        HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_MOST_RECENT,
        null);

    // gets value after url is set, and gets rolling average
    entity.setAttribute(TestEntity.SERVICE_UP, true);
    assertLatencyAttributesNonNull(entity);
  }
  // Previously failed because immutable-map builder threw exception if put same key multiple times,
  // and the NamedActionWithUrl did not have equals/hashCode
  @Test
  public void testSensorWithMultipleOpenUrlActionsRegistered() throws IOException {
    AttributeSensor<String> sensor = Sensors.newStringSensor("sensor1");
    entity.setAttribute(sensor, "http://myval");
    RendererHints.register(sensor, RendererHints.namedActionWithUrl());
    RendererHints.register(sensor, RendererHints.namedActionWithUrl());

    SensorSummary summary = SensorTransformer.sensorSummary(entity, sensor);

    assertEquals(summary.getLinks().get("action:open"), URI.create("http://myval"));
  }
  @Test(groups = "Integration")
  public void testPollsUrl() throws Exception {
    entity.setAttribute(TestEntity.SERVICE_UP, true);

    entity.addEnricher(
        HttpLatencyDetector.builder()
            .url(baseUrl)
            .rollup(500, TimeUnit.MILLISECONDS)
            .period(100, TimeUnit.MILLISECONDS)
            .build());

    assertLatencyAttributesNonNull(entity);
  }
  @Test
  public void testServiceFailureDetectorWorksAfterRebind() throws Exception {
    origEntity.addEnricher(EnricherSpec.create(ServiceFailureDetector.class));

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

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

    newEntity.setAttribute(TestEntity.SERVICE_UP, true);
    ServiceStateLogic.setExpectedState(newEntity, Lifecycle.RUNNING);

    // trigger the failure
    newEntity.setAttribute(TestEntity.SERVICE_UP, false);

    assertHasEventEventually(HASensors.ENTITY_FAILED, Predicates.<Object>equalTo(newEntity), null);
    assertEquals(events.size(), 1, "events=" + events);
  }
  @Test(groups = "Integration")
  public void testGetsSensorIfAlredySetThenPolls() throws Exception {
    entity.setAttribute(TEST_URL, baseUrl.toString());

    entity.addEnricher(
        HttpLatencyDetector.builder()
            .url(TEST_URL)
            .noServiceUp()
            .rollup(500, TimeUnit.MILLISECONDS)
            .period(100, TimeUnit.MILLISECONDS)
            .build());

    assertLatencyAttributesNonNull(entity);
  }
  @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)));
          }
        });
  }
  @Test
  public void testUnsubscribeUsingHandleStopsEvents() throws Exception {
    SubscriptionHandle handle1 = policy.subscribe(entity, TestEntity.SEQUENCE, listener);
    SubscriptionHandle handle2 = policy.subscribe(entity, TestEntity.NAME, listener);
    SubscriptionHandle handle3 = policy.subscribe(otherEntity, TestEntity.SEQUENCE, listener);

    policy.unsubscribe(entity, handle2);

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

    Asserts.succeedsEventually(
        new Runnable() {
          @Override
          public void run() {
            assertEquals(
                listener.events,
                ImmutableList.of(
                    new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, entity, 123),
                    new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, otherEntity, 456)));
          }
        });
  }