@Test
  public void testLocalNodeMasterListenerCallbacks() throws Exception {
    Settings settings =
        settingsBuilder()
            .put("discovery.type", "zen")
            .put("discovery.zen.minimum_master_nodes", 1)
            .put("discovery.zen.ping_timeout", "400ms")
            .put("discovery.initial_state_timeout", "500ms")
            .put("plugin.types", TestPlugin.class.getName())
            .build();

    internalCluster().startNode(settings);
    ClusterService clusterService = internalCluster().getInstance(ClusterService.class);
    MasterAwareService testService = internalCluster().getInstance(MasterAwareService.class);

    ClusterHealthResponse clusterHealth =
        client()
            .admin()
            .cluster()
            .prepareHealth()
            .setWaitForEvents(Priority.LANGUID)
            .setWaitForNodes("1")
            .get();
    assertThat(clusterHealth.isTimedOut(), equalTo(false));

    // the first node should be a master as the minimum required is 1
    assertThat(clusterService.state().nodes().masterNode(), notNullValue());
    assertThat(clusterService.state().nodes().localNodeMaster(), is(true));
    assertThat(testService.master(), is(true));

    String node_1 = internalCluster().startNode(settings);
    final ClusterService clusterService1 =
        internalCluster().getInstance(ClusterService.class, node_1);
    MasterAwareService testService1 =
        internalCluster().getInstance(MasterAwareService.class, node_1);

    clusterHealth =
        client()
            .admin()
            .cluster()
            .prepareHealth()
            .setWaitForEvents(Priority.LANGUID)
            .setWaitForNodes("2")
            .get();
    assertThat(clusterHealth.isTimedOut(), equalTo(false));

    // the second node should not be the master as node1 is already the master.
    assertThat(clusterService1.state().nodes().localNodeMaster(), is(false));
    assertThat(testService1.master(), is(false));

    internalCluster().stopCurrentMasterNode();
    clusterHealth =
        client()
            .admin()
            .cluster()
            .prepareHealth()
            .setWaitForEvents(Priority.LANGUID)
            .setWaitForNodes("1")
            .get();
    assertThat(clusterHealth.isTimedOut(), equalTo(false));

    // now that node1 is closed, node2 should be elected as master
    assertThat(clusterService1.state().nodes().localNodeMaster(), is(true));
    assertThat(testService1.master(), is(true));

    Settings transientSettings =
        settingsBuilder().put("discovery.zen.minimum_master_nodes", 2).build();
    client()
        .admin()
        .cluster()
        .prepareUpdateSettings()
        .setTransientSettings(transientSettings)
        .get();

    // there should not be any master as the minimum number of required eligible masters is not met
    awaitBusy(
        new Predicate<Object>() {
          public boolean apply(Object obj) {
            return clusterService1.state().nodes().masterNode() == null;
          }
        });
    assertThat(testService1.master(), is(false));

    String node_2 =
        internalCluster()
            .startNode(ImmutableSettings.builder().put(settings).put(transientSettings));
    ClusterService clusterService2 = internalCluster().getInstance(ClusterService.class, node_2);
    MasterAwareService testService2 =
        internalCluster().getInstance(MasterAwareService.class, node_2);

    // make sure both nodes see each other otherwise the masternode below could be null if node 2 is
    // master and node 1 did'r receive the updated cluster state...
    assertThat(
        internalCluster()
            .client(node_1)
            .admin()
            .cluster()
            .prepareHealth()
            .setWaitForEvents(Priority.LANGUID)
            .setLocal(true)
            .setWaitForNodes("2")
            .get()
            .isTimedOut(),
        is(false));
    assertThat(
        internalCluster()
            .client(node_2)
            .admin()
            .cluster()
            .prepareHealth()
            .setWaitForEvents(Priority.LANGUID)
            .setLocal(true)
            .setWaitForNodes("2")
            .get()
            .isTimedOut(),
        is(false));

    // now that we started node1 again, a new master should be elected
    assertThat(clusterService2.state().nodes().masterNode(), is(notNullValue()));
    if (node_2.equals(clusterService2.state().nodes().masterNode().name())) {
      assertThat(testService1.master(), is(false));
      assertThat(testService2.master(), is(true));
    } else {
      assertThat(testService1.master(), is(true));
      assertThat(testService2.master(), is(false));
    }
  }
  @Test
  public void dynamicUpdates() throws Exception {
    client()
        .admin()
        .indices()
        .prepareCreate("test")
        .setSettings(
            ImmutableSettings.settingsBuilder()
                .put("index.number_of_shards", 1)
                .put("index.number_of_replicas", 0))
        .execute()
        .actionGet();
    client()
        .admin()
        .cluster()
        .prepareHealth()
        .setWaitForEvents(Priority.LANGUID)
        .setWaitForGreenStatus()
        .execute()
        .actionGet();

    int recCount = randomIntBetween(200, 600);
    int numberOfTypes = randomIntBetween(1, 5);
    List<IndexRequestBuilder> indexRequests = Lists.newArrayList();
    for (int rec = 0; rec < recCount; rec++) {
      String type = "type" + (rec % numberOfTypes);
      String fieldName = "field_" + type + "_" + rec;
      indexRequests.add(
          client()
              .prepareIndex("test", type, Integer.toString(rec))
              .setSource(fieldName, "some_value"));
    }
    indexRandom(true, indexRequests);

    logger.info("checking all the documents are there");
    RefreshResponse refreshResponse =
        client().admin().indices().prepareRefresh().execute().actionGet();
    assertThat(refreshResponse.getFailedShards(), equalTo(0));
    CountResponse response = client().prepareCount("test").execute().actionGet();
    assertThat(response.getCount(), equalTo((long) recCount));

    logger.info("checking all the fields are in the mappings");

    reRunTest:
    while (true) {
      Map<String, String> typeToSource = Maps.newHashMap();
      ClusterState state = client().admin().cluster().prepareState().get().getState();
      for (ObjectObjectCursor<String, MappingMetaData> cursor :
          state.getMetaData().getIndices().get("test").getMappings()) {
        typeToSource.put(cursor.key, cursor.value.source().string());
      }
      for (int rec = 0; rec < recCount; rec++) {
        String type = "type" + (rec % numberOfTypes);
        String fieldName = "field_" + type + "_" + rec;
        fieldName = "\"" + fieldName + "\""; // quote it, so we make sure we catch the exact one
        if (!typeToSource.containsKey(type) || !typeToSource.get(type).contains(fieldName)) {
          client()
              .admin()
              .cluster()
              .prepareHealth()
              .setWaitForEvents(Priority.LANGUID)
              .execute()
              .actionGet();
          awaitBusy(
              new Predicate<Object>() {
                @Override
                public boolean apply(Object input) {
                  PendingClusterTasksResponse pendingTasks =
                      client().admin().cluster().preparePendingClusterTasks().get();
                  return pendingTasks.pendingTasks().isEmpty();
                }
              });
          client()
              .admin()
              .cluster()
              .prepareHealth()
              .setWaitForEvents(Priority.LANGUID)
              .execute()
              .actionGet();
          // its going to break, before we do, make sure that the cluster state hasn't changed on
          // us...
          ClusterState state2 = client().admin().cluster().prepareState().get().getState();
          if (state.version() != state2.version()) {
            logger.info(
                "not the same version, used for test {}, new one {}, re-running test, first wait for mapping to wait",
                state.version(),
                state2.version());
            continue reRunTest;
          }
          logger.info(
              "failing, type {}, field {}, mapping {}", type, fieldName, typeToSource.get(type));
          assertThat(typeToSource.get(type), containsString(fieldName));
        }
      }
      break;
    }
  }
  @Test
  public void testAbortByPattern() throws Exception {
    final int iters =
        between(1, 3); // we run this more than once to make sure metadata is cleaned up propperly
    for (int i = 0; i < iters; i++) {
      List<BenchmarkRequest> requests = new ArrayList<>();
      List<ActionFuture<BenchmarkResponse>> responses = new ArrayList<>();

      SearchRequest searchRequest = prepareBlockingScriptQuery();
      final int benches = between(1, 3);
      String[] names = new String[benches];
      for (int k = 0; k < benches; k++) {
        final BenchmarkRequest request =
            BenchmarkTestUtil.randomRequest(
                client(), indices, numExecutorNodes, competitionSettingsMap, searchRequest);
        request.settings().iterations(Integer.MAX_VALUE, true); // massive amount of iterations
        names[k] = BENCHMARK_NAME + Integer.toString(k);
        request.benchmarkName(names[k]);
        requests.add(request);
        logger.info(
            "--> Submitting benchmark - competitors [{}] iterations [{}]",
            request.competitors().size(),
            request.settings().iterations());
      }

      boolean aborted = false;
      for (BenchmarkRequest r : requests) {
        final ActionFuture<BenchmarkResponse> benchmarkResponse = client().bench(r);
        responses.add(benchmarkResponse);
      }
      try {
        waitForQuery.await();
        if (benches > 1) {
          awaitBusy(
              new Predicate<Object>() {
                @Override
                public boolean apply(java.lang.Object input) {
                  return client().prepareBenchStatus().get().benchmarkResponses().size() == benches;
                }
              });
        }
        final String badPatternA = "*z";
        final String badPatternB = "xxx";
        final String[] patterns;
        switch (getRandom().nextInt(3)) {
          case 0:
            patterns = new String[] {"*"};
            break;
          case 1:
            patterns = new String[] {BENCHMARK_NAME_WILDCARD, badPatternA, badPatternB};
            break;
          case 2:
            patterns = names;
            break;
          default:
            patterns = new String[] {BENCHMARK_NAME_WILDCARD};
        }
        final AbortBenchmarkResponse abortResponse = client().prepareAbortBench(patterns).get();
        aborted = true;
        assertAcked(abortResponse);

        // Confirm that there are no active benchmarks in the cluster
        final BenchmarkStatusResponse statusResponse =
            client().prepareBenchStatus().execute().actionGet();
        waitForTestLatch.countDown(); // let the queries go - we already aborted and got the status
        assertThat(statusResponse.totalActiveBenchmarks(), equalTo(0));

        // Confirm that benchmark was indeed aborted
        for (ActionFuture<BenchmarkResponse> r : responses) {
          assertThat(r.get().state(), is(BenchmarkResponse.State.ABORTED));
        }
      } finally {
        if (waitForTestLatch.getCount() == 1) {
          waitForTestLatch.countDown();
        }
        if (!aborted) {
          client().prepareAbortBench(BENCHMARK_NAME).get();
        }
        assertThat(waitForTestLatch.getCount(), is(0l));
      }
    }
  }