@Test
  public void testCopyHeadersClusterAdminRequest() {
    Map<String, String> transportHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> restHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> copiedHeaders = randomHeadersFrom(restHeaders);
    Set<String> usefulRestHeaders = new HashSet<>(copiedHeaders.keySet());
    usefulRestHeaders.addAll(randomMap(randomIntBetween(0, 10), "useful-").keySet());
    Map<String, String> restContext = randomContext(randomIntBetween(0, 10));
    Map<String, String> transportContext =
        Maps.difference(randomContext(randomIntBetween(0, 10)), restContext).entriesOnlyOnLeft();

    HashMap<String, String> expectedHeaders = new HashMap<>();
    expectedHeaders.putAll(transportHeaders);
    expectedHeaders.putAll(copiedHeaders);

    Map<String, String> expectedContext = new HashMap<>();
    expectedContext.putAll(transportContext);
    expectedContext.putAll(restContext);

    Client client =
        client(
            new NoOpClient(), new FakeRestRequest(restHeaders, expectedContext), usefulRestHeaders);

    ClusterHealthRequest clusterHealthRequest = Requests.clusterHealthRequest();
    putHeaders(clusterHealthRequest, transportHeaders);
    putContext(clusterHealthRequest, transportContext);
    assertHeaders(clusterHealthRequest, transportHeaders);
    client.admin().cluster().health(clusterHealthRequest);
    assertHeaders(clusterHealthRequest, expectedHeaders);
    assertContext(clusterHealthRequest, expectedContext);

    ClusterStateRequest clusterStateRequest = Requests.clusterStateRequest();
    putHeaders(clusterStateRequest, transportHeaders);
    putContext(clusterStateRequest, transportContext);
    assertHeaders(clusterStateRequest, transportHeaders);
    client.admin().cluster().state(clusterStateRequest);
    assertHeaders(clusterStateRequest, expectedHeaders);
    assertContext(clusterStateRequest, expectedContext);

    ClusterStatsRequest clusterStatsRequest = Requests.clusterStatsRequest();
    putHeaders(clusterStatsRequest, transportHeaders);
    putContext(clusterStatsRequest, transportContext);
    assertHeaders(clusterStatsRequest, transportHeaders);
    client.admin().cluster().clusterStats(clusterStatsRequest);
    assertHeaders(clusterStatsRequest, expectedHeaders);
    assertContext(clusterStatsRequest, expectedContext);
  }
  @Test
  public void testCopyHeadersRequest() {
    Map<String, String> transportHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> restHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> copiedHeaders = randomHeadersFrom(restHeaders);
    Set<String> usefulRestHeaders = new HashSet<>(copiedHeaders.keySet());
    usefulRestHeaders.addAll(randomMap(randomIntBetween(0, 10), "useful-").keySet());
    Map<String, String> restContext = randomContext(randomIntBetween(0, 10));
    Map<String, String> transportContext =
        Maps.difference(randomContext(randomIntBetween(0, 10)), restContext).entriesOnlyOnLeft();

    Map<String, String> expectedHeaders = new HashMap<>();
    expectedHeaders.putAll(transportHeaders);
    expectedHeaders.putAll(copiedHeaders);

    Map<String, String> expectedContext = new HashMap<>();
    expectedContext.putAll(transportContext);
    expectedContext.putAll(restContext);

    Client client =
        client(new NoOpClient(), new FakeRestRequest(restHeaders, restContext), usefulRestHeaders);

    SearchRequest searchRequest = Requests.searchRequest();
    putHeaders(searchRequest, transportHeaders);
    putContext(searchRequest, transportContext);
    assertHeaders(searchRequest, transportHeaders);
    client.search(searchRequest);
    assertHeaders(searchRequest, expectedHeaders);
    assertContext(searchRequest, expectedContext);

    GetRequest getRequest = Requests.getRequest("index");
    putHeaders(getRequest, transportHeaders);
    putContext(getRequest, transportContext);
    assertHeaders(getRequest, transportHeaders);
    client.get(getRequest);
    assertHeaders(getRequest, expectedHeaders);
    assertContext(getRequest, expectedContext);

    IndexRequest indexRequest = Requests.indexRequest();
    putHeaders(indexRequest, transportHeaders);
    putContext(indexRequest, transportContext);
    assertHeaders(indexRequest, transportHeaders);
    client.index(indexRequest);
    assertHeaders(indexRequest, expectedHeaders);
    assertContext(indexRequest, expectedContext);
  }
 private static Client client(
     Client noOpClient, RestRequest restRequest, Set<String> usefulRestHeaders) {
   if (usefulRestHeaders.isEmpty() && randomBoolean()) {
     return noOpClient;
   }
   return new BaseRestHandler.HeadersAndContextCopyClient(
       noOpClient, restRequest, usefulRestHeaders);
 }
  @Test
  public void testCopyHeadersIndicesAdminRequest() {
    Map<String, String> transportHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> restHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> copiedHeaders = randomHeadersFrom(restHeaders);
    Set<String> usefulRestHeaders = new HashSet<>(copiedHeaders.keySet());
    usefulRestHeaders.addAll(randomMap(randomIntBetween(0, 10), "useful-").keySet());
    Map<String, String> restContext = randomContext(randomIntBetween(0, 10));
    Map<String, String> transportContext =
        Maps.difference(randomContext(randomIntBetween(0, 10)), restContext).entriesOnlyOnLeft();

    HashMap<String, String> expectedHeaders = new HashMap<>();
    expectedHeaders.putAll(transportHeaders);
    expectedHeaders.putAll(copiedHeaders);

    Map<String, String> expectedContext = new HashMap<>();
    expectedContext.putAll(transportContext);
    expectedContext.putAll(restContext);

    Client client =
        client(new NoOpClient(), new FakeRestRequest(restHeaders, restContext), usefulRestHeaders);

    CreateIndexRequest createIndexRequest = Requests.createIndexRequest("test");
    putHeaders(createIndexRequest, transportHeaders);
    putContext(createIndexRequest, transportContext);
    assertHeaders(createIndexRequest, transportHeaders);
    client.admin().indices().create(createIndexRequest);
    assertHeaders(createIndexRequest, expectedHeaders);
    assertContext(createIndexRequest, expectedContext);

    CloseIndexRequest closeIndexRequest = Requests.closeIndexRequest("test");
    putHeaders(closeIndexRequest, transportHeaders);
    putContext(closeIndexRequest, transportContext);
    assertHeaders(closeIndexRequest, transportHeaders);
    client.admin().indices().close(closeIndexRequest);
    assertHeaders(closeIndexRequest, expectedHeaders);
    assertContext(closeIndexRequest, expectedContext);

    FlushRequest flushRequest = Requests.flushRequest();
    putHeaders(flushRequest, transportHeaders);
    putContext(flushRequest, transportContext);
    assertHeaders(flushRequest, transportHeaders);
    client.admin().indices().flush(flushRequest);
    assertHeaders(flushRequest, expectedHeaders);
    assertContext(flushRequest, expectedContext);
  }
  @Test
  public void testCopyHeadersRequestBuilder() {
    Map<String, String> transportHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> restHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> copiedHeaders = randomHeadersFrom(restHeaders);
    Set<String> usefulRestHeaders = new HashSet<>(copiedHeaders.keySet());
    usefulRestHeaders.addAll(randomMap(randomIntBetween(0, 10), "useful-").keySet());
    Map<String, String> restContext = randomContext(randomIntBetween(0, 10));
    Map<String, String> transportContext =
        Maps.difference(randomContext(randomIntBetween(0, 10)), restContext).entriesOnlyOnLeft();

    HashMap<String, String> expectedHeaders = new HashMap<>();
    expectedHeaders.putAll(transportHeaders);
    expectedHeaders.putAll(copiedHeaders);

    Map<String, String> expectedContext = new HashMap<>();
    expectedContext.putAll(transportContext);
    expectedContext.putAll(restContext);

    Client client =
        client(new NoOpClient(), new FakeRestRequest(restHeaders, restContext), usefulRestHeaders);

    ActionRequestBuilder requestBuilders[] =
        new ActionRequestBuilder[] {
          client.prepareIndex("index", "type"),
          client.prepareGet("index", "type", "id"),
          client.prepareBulk(),
          client.prepareDelete(),
          client.prepareIndex(),
          client.prepareClearScroll(),
          client.prepareMultiGet(),
          client.prepareBenchStatus()
        };

    for (ActionRequestBuilder requestBuilder : requestBuilders) {
      putHeaders(requestBuilder.request(), transportHeaders);
      putContext(requestBuilder.request(), transportContext);
      assertHeaders(requestBuilder.request(), transportHeaders);
      requestBuilder.get();
      assertHeaders(requestBuilder.request(), expectedHeaders);
      assertContext(requestBuilder.request(), expectedContext);
    }
  }
  @Test
  public void testCopyHeadersIndicesAdminRequestBuilder() {
    Map<String, String> transportHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> restHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> copiedHeaders = randomHeadersFrom(restHeaders);
    Set<String> usefulRestHeaders = new HashSet<>(copiedHeaders.keySet());
    usefulRestHeaders.addAll(randomMap(randomIntBetween(0, 10), "useful-").keySet());
    Map<String, String> restContext = randomContext(randomIntBetween(0, 10));
    Map<String, String> transportContext =
        Maps.difference(randomContext(randomIntBetween(0, 10)), restContext).entriesOnlyOnLeft();

    HashMap<String, String> expectedHeaders = new HashMap<>();
    expectedHeaders.putAll(transportHeaders);
    expectedHeaders.putAll(copiedHeaders);

    Map<String, String> expectedContext = new HashMap<>();
    expectedContext.putAll(transportContext);
    expectedContext.putAll(restContext);

    Client client =
        client(new NoOpClient(), new FakeRestRequest(restHeaders, restContext), usefulRestHeaders);

    ActionRequestBuilder requestBuilders[] =
        new ActionRequestBuilder[] {
          client.admin().indices().prepareValidateQuery(),
          client.admin().indices().prepareCreate("test"),
          client.admin().indices().prepareAliases(),
          client.admin().indices().prepareAnalyze("text"),
          client.admin().indices().prepareDeleteWarmer(),
          client.admin().indices().prepareTypesExists("type"),
          client.admin().indices().prepareClose()
        };

    for (ActionRequestBuilder requestBuilder : requestBuilders) {
      putHeaders(requestBuilder.request(), transportHeaders);
      putContext(requestBuilder.request(), transportContext);
      assertHeaders(requestBuilder.request(), transportHeaders);
      requestBuilder.get();
      assertHeaders(requestBuilder.request(), expectedHeaders);
      assertContext(requestBuilder.request(), expectedContext);
    }
  }
  @Test
  public void testCopyHeadersClusterAdminRequestBuilder() {
    Map<String, String> transportHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> restHeaders = randomHeaders(randomIntBetween(0, 10));
    Map<String, String> copiedHeaders = randomHeadersFrom(restHeaders);
    Set<String> usefulRestHeaders = new HashSet<>(copiedHeaders.keySet());
    usefulRestHeaders.addAll(randomMap(randomIntBetween(0, 10), "useful-").keySet());
    Map<String, String> restContext = randomContext(randomIntBetween(0, 10));
    Map<String, String> transportContext =
        Maps.difference(randomContext(randomIntBetween(0, 10)), restContext).entriesOnlyOnLeft();

    HashMap<String, String> expectedHeaders = new HashMap<>();
    expectedHeaders.putAll(transportHeaders);
    expectedHeaders.putAll(copiedHeaders);

    Map<String, String> expectedContext = new HashMap<>();
    expectedContext.putAll(transportContext);
    expectedContext.putAll(restContext);

    Client client =
        client(new NoOpClient(), new FakeRestRequest(restHeaders, restContext), usefulRestHeaders);

    ActionRequestBuilder requestBuilders[] =
        new ActionRequestBuilder[] {
          client.admin().cluster().prepareNodesInfo(),
          client.admin().cluster().prepareClusterStats(),
          client.admin().cluster().prepareState(),
          client.admin().cluster().prepareCreateSnapshot("repo", "name"),
          client.admin().cluster().prepareHealth(),
          client.admin().cluster().prepareReroute()
        };

    for (ActionRequestBuilder requestBuilder : requestBuilders) {
      putHeaders(requestBuilder.request(), transportHeaders);
      putContext(requestBuilder.request(), transportContext);
      assertHeaders(requestBuilder.request(), transportHeaders);
      requestBuilder.get();
      assertHeaders(requestBuilder.request(), expectedHeaders);
      assertContext(requestBuilder.request(), expectedContext);
    }
  }
  @Test
  public void testAddUsefulHeaders() throws InterruptedException {
    // take the existing headers into account to make sure this test runs with tests.iters>1 as the
    // list is static
    final Set<String> headers = new HashSet<>();
    headers.addAll(BaseRestHandler.usefulHeaders());
    int iterations = randomIntBetween(1, 5);

    ExecutorService executorService = Executors.newFixedThreadPool(iterations);
    for (int i = 0; i < iterations; i++) {
      int headersCount = randomInt(10);
      final Set<String> newHeaders = new HashSet<>();
      for (int j = 0; j < headersCount; j++) {
        String usefulHeader = randomRealisticUnicodeOfLengthBetween(1, 30);
        newHeaders.add(usefulHeader);
        headers.add(usefulHeader);
      }

      executorService.submit(
          new Runnable() {
            @Override
            public void run() {
              BaseRestHandler.addUsefulHeaders(newHeaders.toArray(new String[newHeaders.size()]));
            }
          });
    }

    executorService.shutdown();
    assertThat(executorService.awaitTermination(1, TimeUnit.SECONDS), equalTo(true));
    String[] usefulHeaders =
        BaseRestHandler.usefulHeaders().toArray(new String[BaseRestHandler.usefulHeaders().size()]);
    assertThat(usefulHeaders.length, equalTo(headers.size()));

    Arrays.sort(usefulHeaders);
    String[] headersArray = new String[headers.size()];
    headersArray = headers.toArray(headersArray);
    Arrays.sort(headersArray);
    assertThat(usefulHeaders, equalTo(headersArray));
  }