@Test
  public void testDeleteWarmerAcknowledgement() {
    createIndex("test");
    index("test", "type", "1", "f", 1);

    assertAcked(
        client()
            .admin()
            .indices()
            .preparePutWarmer("custom_warmer")
            .setSearchRequest(
                client()
                    .prepareSearch("test")
                    .setTypes("test")
                    .setQuery(QueryBuilders.matchAllQuery())));

    assertAcked(
        client()
            .admin()
            .indices()
            .prepareDeleteWarmer()
            .setIndices("test")
            .setNames("custom_warmer"));

    for (Client client : clients()) {
      GetWarmersResponse getWarmersResponse =
          client.admin().indices().prepareGetWarmers().setLocal(true).get();
      assertThat(getWarmersResponse.warmers().size(), equalTo(0));
    }
  }
  @Test
  public void testPutWarmerAcknowledgement() {
    createIndex("test");
    // make sure one shard is started so the search during put warmer will not fail
    index("test", "type", "1", "f", 1);

    assertAcked(
        client()
            .admin()
            .indices()
            .preparePutWarmer("custom_warmer")
            .setSearchRequest(
                client()
                    .prepareSearch("test")
                    .setTypes("test")
                    .setQuery(QueryBuilders.matchAllQuery())));

    for (Client client : clients()) {
      GetWarmersResponse getWarmersResponse =
          client.admin().indices().prepareGetWarmers().setLocal(true).get();
      assertThat(getWarmersResponse.warmers().size(), equalTo(1));
      ObjectObjectCursor<String, List<IndexWarmersMetaData.Entry>> entry =
          getWarmersResponse.warmers().iterator().next();
      assertThat(entry.key, equalTo("test"));
      assertThat(entry.value.size(), equalTo(1));
      assertThat(entry.value.get(0).name(), equalTo("custom_warmer"));
    }
  }
  @Test
  @TestLogging(value = "cluster.service:TRACE")
  public void testDeleteCreateInOneBulk() throws Exception {
    internalCluster()
        .startNodesAsync(
            2, Settings.builder().put(DiscoveryModule.DISCOVERY_TYPE_KEY, "zen").build())
        .get();
    assertFalse(client().admin().cluster().prepareHealth().setWaitForNodes("2").get().isTimedOut());
    prepareCreate("test")
        .setSettings(IndexMetaData.SETTING_AUTO_EXPAND_REPLICAS, true)
        .addMapping("type")
        .get();
    ensureGreen("test");

    // now that the cluster is stable, remove publishing timeout
    assertAcked(
        client()
            .admin()
            .cluster()
            .prepareUpdateSettings()
            .setTransientSettings(Settings.builder().put(DiscoverySettings.PUBLISH_TIMEOUT, "0")));

    Set<String> nodes = new HashSet<>(Arrays.asList(internalCluster().getNodeNames()));
    nodes.remove(internalCluster().getMasterName());

    // block none master node.
    BlockClusterStateProcessing disruption =
        new BlockClusterStateProcessing(nodes.iterator().next(), getRandom());
    internalCluster().setDisruptionScheme(disruption);
    logger.info("--> indexing a doc");
    index("test", "type", "1");
    refresh();
    disruption.startDisrupting();
    logger.info("--> delete index and recreate it");
    assertFalse(
        client()
            .admin()
            .indices()
            .prepareDelete("test")
            .setTimeout("200ms")
            .get()
            .isAcknowledged());
    assertFalse(
        prepareCreate("test")
            .setTimeout("200ms")
            .setSettings(IndexMetaData.SETTING_AUTO_EXPAND_REPLICAS, true)
            .get()
            .isAcknowledged());
    logger.info("--> letting cluster proceed");
    disruption.stopDisrupting();
    ensureGreen(TimeValue.timeValueMinutes(30), "test");
    assertHitCount(client().prepareSearch("test").get(), 0);
  }
  @Test
  public void testPointsOnly() throws Exception {
    String mapping =
        XContentFactory.jsonBuilder()
            .startObject()
            .startObject("type1")
            .startObject("properties")
            .startObject("location")
            .field("type", "geo_shape")
            .field("tree", randomBoolean() ? "quadtree" : "geohash")
            .field("tree_levels", "6")
            .field("distance_error_pct", "0.01")
            .field("points_only", true)
            .endObject()
            .endObject()
            .endObject()
            .endObject()
            .string();

    assertAcked(prepareCreate("geo_points_only").addMapping("type1", mapping));
    ensureGreen();

    ShapeBuilder shape = RandomShapeGenerator.createShape(random());
    try {
      index(
          "geo_points_only",
          "type1",
          "1",
          jsonBuilder().startObject().field("location", shape).endObject());
    } catch (MapperParsingException e) {
      // RandomShapeGenerator created something other than a POINT type, verify the correct
      // exception is thrown
      assertThat(e.getCause().getMessage(), containsString("is configured for points only"));
      return;
    }

    refresh();
    // test that point was inserted
    SearchResponse response =
        client()
            .prepareSearch()
            .setQuery(geoIntersectionQuery("location", shape))
            .execute()
            .actionGet();

    assertEquals(1, response.getHits().getTotalHits());
  }
  @Test
  public void testPutWarmerNoAcknowledgement() throws InterruptedException {
    createIndex("test");
    // make sure one shard is started so the search during put warmer will not fail
    index("test", "type", "1", "f", 1);

    PutWarmerResponse putWarmerResponse =
        client()
            .admin()
            .indices()
            .preparePutWarmer("custom_warmer")
            .setTimeout("0s")
            .setSearchRequest(
                client()
                    .prepareSearch("test")
                    .setTypes("test")
                    .setQuery(QueryBuilders.matchAllQuery()))
            .get();
    assertThat(putWarmerResponse.isAcknowledged(), equalTo(false));
    /* Since we don't wait for the ack here we have to wait until the search request has been executed from the master
     * otherwise the test infra might have already deleted the index and the search request fails on all shards causing
     * the test to fail too. We simply wait until the the warmer has been installed and also clean it up afterwards.*/
    assertTrue(
        awaitBusy(
            new Predicate<Object>() {
              @Override
              public boolean apply(Object input) {
                for (Client client : clients()) {
                  GetWarmersResponse getWarmersResponse =
                      client.admin().indices().prepareGetWarmers().setLocal(true).get();
                  if (getWarmersResponse.warmers().size() != 1) {
                    return false;
                  }
                }
                return true;
              }
            }));
    assertAcked(
        client()
            .admin()
            .indices()
            .prepareDeleteWarmer()
            .setIndices("test")
            .setNames("custom_warmer"));
  }
  @Test
  public void testDeleteWarmerNoAcknowledgement() throws InterruptedException {
    createIndex("test");
    index("test", "type", "1", "f", 1);

    assertAcked(
        client()
            .admin()
            .indices()
            .preparePutWarmer("custom_warmer")
            .setSearchRequest(
                client()
                    .prepareSearch("test")
                    .setTypes("test")
                    .setQuery(QueryBuilders.matchAllQuery())));

    DeleteWarmerResponse deleteWarmerResponse =
        client()
            .admin()
            .indices()
            .prepareDeleteWarmer()
            .setIndices("test")
            .setNames("custom_warmer")
            .setTimeout("0s")
            .get();
    assertFalse(deleteWarmerResponse.isAcknowledged());
    assertTrue(
        awaitBusy(
            new Predicate<Object>() { // wait until they are all deleted
              @Override
              public boolean apply(Object input) {
                for (Client client : clients()) {
                  GetWarmersResponse getWarmersResponse =
                      client.admin().indices().prepareGetWarmers().setLocal(true).get();
                  if (getWarmersResponse.warmers().size() > 0) {
                    return false;
                  }
                }
                return true;
              }
            }));
  }
  @SuppressWarnings("unchecked")
  @Test
  public void updateIncludeExclude() throws Exception {
    assertAcked(
        prepareCreate("test")
            .addMapping(
                "type",
                jsonBuilder()
                    .startObject()
                    .startObject("type")
                    .startObject("properties")
                    .startObject("normal")
                    .field("type", "long")
                    .endObject()
                    .startObject("exclude")
                    .field("type", "long")
                    .endObject()
                    .startObject("include")
                    .field("type", "long")
                    .endObject()
                    .endObject()
                    .endObject()
                    .endObject()));
    ensureGreen(); // make sure that replicas are initialized so the refresh command will work them
                   // too

    logger.info("Index doc");
    index(
        "test",
        "type",
        "1",
        JsonXContent.contentBuilder()
            .startObject()
            .field("normal", 1)
            .field("exclude", 1)
            .field("include", 1)
            .endObject());
    refresh(); // commit it for later testing.

    logger.info("Adding exclude settings");
    PutMappingResponse putResponse =
        client()
            .admin()
            .indices()
            .preparePutMapping("test")
            .setType("type")
            .setSource(
                JsonXContent.contentBuilder()
                    .startObject()
                    .startObject("type")
                    .startObject("_source")
                    .startArray("excludes")
                    .value("exclude")
                    .endArray()
                    .endObject()
                    .endObject())
            .get();

    assertTrue(putResponse.isAcknowledged());

    // changed mapping doesn't affect indexed documents (checking backward compatibility)
    GetResponse getResponse = client().prepareGet("test", "type", "1").setRealtime(false).get();
    assertThat(getResponse.getSource(), hasKey("normal"));
    assertThat(getResponse.getSource(), hasKey("exclude"));
    assertThat(getResponse.getSource(), hasKey("include"));

    logger.info("Index doc again");
    index(
        "test",
        "type",
        "1",
        JsonXContent.contentBuilder()
            .startObject()
            .field("normal", 2)
            .field("exclude", 1)
            .field("include", 2)
            .endObject());

    // but do affect newly indexed docs
    getResponse = get("test", "type", "1");
    assertThat(getResponse.getSource(), hasKey("normal"));
    assertThat(getResponse.getSource(), not(hasKey("exclude")));
    assertThat(getResponse.getSource(), hasKey("include"));

    logger.info("Changing mapping to includes");
    putResponse =
        client()
            .admin()
            .indices()
            .preparePutMapping("test")
            .setType("type")
            .setSource(
                JsonXContent.contentBuilder()
                    .startObject()
                    .startObject("type")
                    .startObject("_source")
                    .startArray("excludes")
                    .endArray()
                    .startArray("includes")
                    .value("include")
                    .endArray()
                    .endObject()
                    .endObject())
            .get();
    assertTrue(putResponse.isAcknowledged());

    GetMappingsResponse getMappingsResponse =
        client().admin().indices().prepareGetMappings("test").get();
    MappingMetaData typeMapping = getMappingsResponse.getMappings().get("test").get("type");
    assertThat(
        (Map<String, Object>) typeMapping.getSourceAsMap().get("_source"), hasKey("includes"));
    ArrayList<String> includes =
        (ArrayList<String>)
            ((Map<String, Object>) typeMapping.getSourceAsMap().get("_source")).get("includes");
    assertThat(includes, contains("include"));
    assertThat(
        (Map<String, Object>) typeMapping.getSourceAsMap().get("_source"), hasKey("excludes"));
    assertThat(
        (ArrayList<String>)
            ((Map<String, Object>) typeMapping.getSourceAsMap().get("_source")).get("excludes"),
        emptyIterable());

    logger.info("Indexing doc yet again");
    index(
        "test",
        "type",
        "1",
        JsonXContent.contentBuilder()
            .startObject()
            .field("normal", 3)
            .field("exclude", 3)
            .field("include", 3)
            .endObject());

    getResponse = get("test", "type", "1");
    assertThat(getResponse.getSource(), not(hasKey("normal")));
    assertThat(getResponse.getSource(), not(hasKey("exclude")));
    assertThat(getResponse.getSource(), hasKey("include"));

    logger.info("Adding excludes, but keep includes");
    putResponse =
        client()
            .admin()
            .indices()
            .preparePutMapping("test")
            .setType("type")
            .setSource(
                JsonXContent.contentBuilder()
                    .startObject()
                    .startObject("type")
                    .startObject("_source")
                    .startArray("excludes")
                    .value("*.excludes")
                    .endArray()
                    .endObject()
                    .endObject())
            .get();
    assertTrue(putResponse.isAcknowledged());

    getMappingsResponse = client().admin().indices().prepareGetMappings("test").get();
    typeMapping = getMappingsResponse.getMappings().get("test").get("type");
    assertThat(
        (Map<String, Object>) typeMapping.getSourceAsMap().get("_source"), hasKey("includes"));
    includes =
        (ArrayList<String>)
            ((Map<String, Object>) typeMapping.getSourceAsMap().get("_source")).get("includes");
    assertThat(includes, contains("include"));
    assertThat(
        (Map<String, Object>) typeMapping.getSourceAsMap().get("_source"), hasKey("excludes"));
    ArrayList<String> excludes =
        (ArrayList<String>)
            ((Map<String, Object>) typeMapping.getSourceAsMap().get("_source")).get("excludes");
    assertThat(excludes, contains("*.excludes"));
  }
  @Test
  public void testSimpleWorkflow() {
    Client client = client();
    logger.info("-->  creating hdfs repository with path [{}]", path);

    PutRepositoryResponse putRepositoryResponse =
        client
            .admin()
            .cluster()
            .preparePutRepository("test-repo")
            .setType("hdfs")
            .setSettings(
                Settings.settingsBuilder()
                    .put("uri", "file://./")
                    .put("path", path)
                    .put("conf", "additional-cfg.xml, conf-2.xml")
                    .put("chunk_size", randomIntBetween(100, 1000) + "k")
                    .put("compress", randomBoolean()))
            .get();
    assertThat(putRepositoryResponse.isAcknowledged(), equalTo(true));

    createIndex("test-idx-1", "test-idx-2", "test-idx-3");
    ensureGreen();

    logger.info("--> indexing some data");
    for (int i = 0; i < 100; i++) {
      index("test-idx-1", "doc", Integer.toString(i), "foo", "bar" + i);
      index("test-idx-2", "doc", Integer.toString(i), "foo", "baz" + i);
      index("test-idx-3", "doc", Integer.toString(i), "foo", "baz" + i);
    }
    refresh();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-2").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-3").get().getCount(), equalTo(100L));

    logger.info("--> snapshot");
    CreateSnapshotResponse createSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareCreateSnapshot("test-repo", "test-snap")
            .setWaitForCompletion(true)
            .setIndices("test-idx-*", "-test-idx-3")
            .get();
    assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
    assertThat(
        createSnapshotResponse.getSnapshotInfo().successfulShards(),
        equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));

    assertThat(
        client
            .admin()
            .cluster()
            .prepareGetSnapshots("test-repo")
            .setSnapshots("test-snap")
            .get()
            .getSnapshots()
            .get(0)
            .state(),
        equalTo(SnapshotState.SUCCESS));

    logger.info("--> delete some data");
    for (int i = 0; i < 50; i++) {
      client.prepareDelete("test-idx-1", "doc", Integer.toString(i)).get();
    }
    for (int i = 50; i < 100; i++) {
      client.prepareDelete("test-idx-2", "doc", Integer.toString(i)).get();
    }
    for (int i = 0; i < 100; i += 2) {
      client.prepareDelete("test-idx-3", "doc", Integer.toString(i)).get();
    }
    refresh();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(50L));
    assertThat(client.prepareCount("test-idx-2").get().getCount(), equalTo(50L));
    assertThat(client.prepareCount("test-idx-3").get().getCount(), equalTo(50L));

    logger.info("--> close indices");
    client.admin().indices().prepareClose("test-idx-1", "test-idx-2").get();

    logger.info("--> restore all indices from the snapshot");
    RestoreSnapshotResponse restoreSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareRestoreSnapshot("test-repo", "test-snap")
            .setWaitForCompletion(true)
            .execute()
            .actionGet();
    assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));

    ensureGreen();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-2").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-3").get().getCount(), equalTo(50L));

    // Test restore after index deletion
    logger.info("--> delete indices");
    wipeIndices("test-idx-1", "test-idx-2");
    logger.info("--> restore one index after deletion");
    restoreSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareRestoreSnapshot("test-repo", "test-snap")
            .setWaitForCompletion(true)
            .setIndices("test-idx-*", "-test-idx-2")
            .execute()
            .actionGet();
    assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
    ensureGreen();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));
    ClusterState clusterState = client.admin().cluster().prepareState().get().getState();
    assertThat(clusterState.getMetaData().hasIndex("test-idx-1"), equalTo(true));
    assertThat(clusterState.getMetaData().hasIndex("test-idx-2"), equalTo(false));
  }
  @Test
  @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch-cloud-aws/issues/211")
  public void testSimpleWorkflow() {
    Client client = client();
    logger.info(
        "-->  creating s3 repository with bucket[{}] and path [{}]",
        internalCluster().getInstance(Settings.class).get("repositories.s3.bucket"),
        basePath);
    PutRepositoryResponse putRepositoryResponse =
        client
            .admin()
            .cluster()
            .preparePutRepository("test-repo")
            .setType("s3")
            .setSettings(
                Settings.settingsBuilder()
                    .put("base_path", basePath)
                    .put("chunk_size", randomIntBetween(1000, 10000)))
            .get();
    assertThat(putRepositoryResponse.isAcknowledged(), equalTo(true));

    createIndex("test-idx-1", "test-idx-2", "test-idx-3");
    ensureGreen();

    logger.info("--> indexing some data");
    for (int i = 0; i < 100; i++) {
      index("test-idx-1", "doc", Integer.toString(i), "foo", "bar" + i);
      index("test-idx-2", "doc", Integer.toString(i), "foo", "baz" + i);
      index("test-idx-3", "doc", Integer.toString(i), "foo", "baz" + i);
    }
    refresh();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-2").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-3").get().getCount(), equalTo(100L));

    logger.info("--> snapshot");
    CreateSnapshotResponse createSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareCreateSnapshot("test-repo", "test-snap")
            .setWaitForCompletion(true)
            .setIndices("test-idx-*", "-test-idx-3")
            .get();
    assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
    assertThat(
        createSnapshotResponse.getSnapshotInfo().successfulShards(),
        equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));

    assertThat(
        client
            .admin()
            .cluster()
            .prepareGetSnapshots("test-repo")
            .setSnapshots("test-snap")
            .get()
            .getSnapshots()
            .get(0)
            .state(),
        equalTo(SnapshotState.SUCCESS));

    logger.info("--> delete some data");
    for (int i = 0; i < 50; i++) {
      client.prepareDelete("test-idx-1", "doc", Integer.toString(i)).get();
    }
    for (int i = 50; i < 100; i++) {
      client.prepareDelete("test-idx-2", "doc", Integer.toString(i)).get();
    }
    for (int i = 0; i < 100; i += 2) {
      client.prepareDelete("test-idx-3", "doc", Integer.toString(i)).get();
    }
    refresh();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(50L));
    assertThat(client.prepareCount("test-idx-2").get().getCount(), equalTo(50L));
    assertThat(client.prepareCount("test-idx-3").get().getCount(), equalTo(50L));

    logger.info("--> close indices");
    client.admin().indices().prepareClose("test-idx-1", "test-idx-2").get();

    logger.info("--> restore all indices from the snapshot");
    RestoreSnapshotResponse restoreSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareRestoreSnapshot("test-repo", "test-snap")
            .setWaitForCompletion(true)
            .execute()
            .actionGet();
    assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));

    ensureGreen();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-2").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-3").get().getCount(), equalTo(50L));

    // Test restore after index deletion
    logger.info("--> delete indices");
    cluster().wipeIndices("test-idx-1", "test-idx-2");
    logger.info("--> restore one index after deletion");
    restoreSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareRestoreSnapshot("test-repo", "test-snap")
            .setWaitForCompletion(true)
            .setIndices("test-idx-*", "-test-idx-2")
            .execute()
            .actionGet();
    assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
    ensureGreen();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));
    ClusterState clusterState = client.admin().cluster().prepareState().get().getState();
    assertThat(clusterState.getMetaData().hasIndex("test-idx-1"), equalTo(true));
    assertThat(clusterState.getMetaData().hasIndex("test-idx-2"), equalTo(false));
  }
  private void assertRepositoryIsOperational(Client client, String repository) {
    createIndex("test-idx-1");
    ensureGreen();

    logger.info("--> indexing some data");
    for (int i = 0; i < 100; i++) {
      index("test-idx-1", "doc", Integer.toString(i), "foo", "bar" + i);
    }
    refresh();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));

    logger.info("--> snapshot");
    CreateSnapshotResponse createSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareCreateSnapshot(repository, "test-snap")
            .setWaitForCompletion(true)
            .setIndices("test-idx-*")
            .get();
    assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
    assertThat(
        createSnapshotResponse.getSnapshotInfo().successfulShards(),
        equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));

    assertThat(
        client
            .admin()
            .cluster()
            .prepareGetSnapshots(repository)
            .setSnapshots("test-snap")
            .get()
            .getSnapshots()
            .get(0)
            .state(),
        equalTo(SnapshotState.SUCCESS));

    logger.info("--> delete some data");
    for (int i = 0; i < 50; i++) {
      client.prepareDelete("test-idx-1", "doc", Integer.toString(i)).get();
    }
    refresh();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(50L));

    logger.info("--> close indices");
    client.admin().indices().prepareClose("test-idx-1").get();

    logger.info("--> restore all indices from the snapshot");
    RestoreSnapshotResponse restoreSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareRestoreSnapshot(repository, "test-snap")
            .setWaitForCompletion(true)
            .execute()
            .actionGet();
    assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));

    ensureGreen();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));
  }
  @Test
  @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch-cloud-aws/issues/211")
  public void testEncryption() {
    Client client = client();
    logger.info(
        "-->  creating s3 repository with bucket[{}] and path [{}]",
        internalCluster().getInstance(Settings.class).get("repositories.s3.bucket"),
        basePath);
    PutRepositoryResponse putRepositoryResponse =
        client
            .admin()
            .cluster()
            .preparePutRepository("test-repo")
            .setType("s3")
            .setSettings(
                Settings.settingsBuilder()
                    .put("base_path", basePath)
                    .put("chunk_size", randomIntBetween(1000, 10000))
                    .put("server_side_encryption", true))
            .get();
    assertThat(putRepositoryResponse.isAcknowledged(), equalTo(true));

    createIndex("test-idx-1", "test-idx-2", "test-idx-3");
    ensureGreen();

    logger.info("--> indexing some data");
    for (int i = 0; i < 100; i++) {
      index("test-idx-1", "doc", Integer.toString(i), "foo", "bar" + i);
      index("test-idx-2", "doc", Integer.toString(i), "foo", "baz" + i);
      index("test-idx-3", "doc", Integer.toString(i), "foo", "baz" + i);
    }
    refresh();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-2").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-3").get().getCount(), equalTo(100L));

    logger.info("--> snapshot");
    CreateSnapshotResponse createSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareCreateSnapshot("test-repo", "test-snap")
            .setWaitForCompletion(true)
            .setIndices("test-idx-*", "-test-idx-3")
            .get();
    assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
    assertThat(
        createSnapshotResponse.getSnapshotInfo().successfulShards(),
        equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));

    assertThat(
        client
            .admin()
            .cluster()
            .prepareGetSnapshots("test-repo")
            .setSnapshots("test-snap")
            .get()
            .getSnapshots()
            .get(0)
            .state(),
        equalTo(SnapshotState.SUCCESS));

    Settings settings = internalCluster().getInstance(Settings.class);
    Settings bucket = settings.getByPrefix("repositories.s3.");
    AmazonS3 s3Client =
        internalCluster()
            .getInstance(AwsS3Service.class)
            .client(
                null,
                null,
                bucket.get("region", settings.get("repositories.s3.region")),
                bucket.get("access_key", settings.get("cloud.aws.access_key")),
                bucket.get("secret_key", settings.get("cloud.aws.secret_key")));

    String bucketName = bucket.get("bucket");
    logger.info("--> verify encryption for bucket [{}], prefix [{}]", bucketName, basePath);
    List<S3ObjectSummary> summaries =
        s3Client.listObjects(bucketName, basePath).getObjectSummaries();
    for (S3ObjectSummary summary : summaries) {
      assertThat(
          s3Client.getObjectMetadata(bucketName, summary.getKey()).getSSEAlgorithm(),
          equalTo("AES256"));
    }

    logger.info("--> delete some data");
    for (int i = 0; i < 50; i++) {
      client.prepareDelete("test-idx-1", "doc", Integer.toString(i)).get();
    }
    for (int i = 50; i < 100; i++) {
      client.prepareDelete("test-idx-2", "doc", Integer.toString(i)).get();
    }
    for (int i = 0; i < 100; i += 2) {
      client.prepareDelete("test-idx-3", "doc", Integer.toString(i)).get();
    }
    refresh();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(50L));
    assertThat(client.prepareCount("test-idx-2").get().getCount(), equalTo(50L));
    assertThat(client.prepareCount("test-idx-3").get().getCount(), equalTo(50L));

    logger.info("--> close indices");
    client.admin().indices().prepareClose("test-idx-1", "test-idx-2").get();

    logger.info("--> restore all indices from the snapshot");
    RestoreSnapshotResponse restoreSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareRestoreSnapshot("test-repo", "test-snap")
            .setWaitForCompletion(true)
            .execute()
            .actionGet();
    assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));

    ensureGreen();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-2").get().getCount(), equalTo(100L));
    assertThat(client.prepareCount("test-idx-3").get().getCount(), equalTo(50L));

    // Test restore after index deletion
    logger.info("--> delete indices");
    cluster().wipeIndices("test-idx-1", "test-idx-2");
    logger.info("--> restore one index after deletion");
    restoreSnapshotResponse =
        client
            .admin()
            .cluster()
            .prepareRestoreSnapshot("test-repo", "test-snap")
            .setWaitForCompletion(true)
            .setIndices("test-idx-*", "-test-idx-2")
            .execute()
            .actionGet();
    assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
    ensureGreen();
    assertThat(client.prepareCount("test-idx-1").get().getCount(), equalTo(100L));
    ClusterState clusterState = client.admin().cluster().prepareState().get().getState();
    assertThat(clusterState.getMetaData().hasIndex("test-idx-1"), equalTo(true));
    assertThat(clusterState.getMetaData().hasIndex("test-idx-2"), equalTo(false));
  }
  @Test
  public void testVersionedUpdate() throws Exception {
    createIndex("test");
    ensureGreen();

    index("test", "type", "1", "text", "value"); // version is now 1

    assertThrows(
        client()
            .prepareUpdate("test", "type", "1")
            .setScript("ctx._source.text = 'v2'", ScriptService.ScriptType.INLINE)
            .setVersion(2)
            .execute(),
        VersionConflictEngineException.class);

    client()
        .prepareUpdate("test", "type", "1")
        .setScript("ctx._source.text = 'v2'", ScriptService.ScriptType.INLINE)
        .setVersion(1)
        .get();
    assertThat(client().prepareGet("test", "type", "1").get().getVersion(), equalTo(2l));

    // and again with a higher version..
    client()
        .prepareUpdate("test", "type", "1")
        .setScript("ctx._source.text = 'v3'", ScriptService.ScriptType.INLINE)
        .setVersion(2)
        .get();

    assertThat(client().prepareGet("test", "type", "1").get().getVersion(), equalTo(3l));

    // after delete
    client().prepareDelete("test", "type", "1").get();
    assertThrows(
        client()
            .prepareUpdate("test", "type", "1")
            .setScript("ctx._source.text = 'v2'", ScriptService.ScriptType.INLINE)
            .setVersion(3)
            .execute(),
        DocumentMissingException.class);

    // external versioning
    client()
        .prepareIndex("test", "type", "2")
        .setSource("text", "value")
        .setVersion(10)
        .setVersionType(VersionType.EXTERNAL)
        .get();

    assertThrows(
        client()
            .prepareUpdate("test", "type", "2")
            .setScript("ctx._source.text = 'v2'", ScriptService.ScriptType.INLINE)
            .setVersion(2)
            .setVersionType(VersionType.EXTERNAL)
            .execute(),
        ActionRequestValidationException.class);

    // upserts - the combination with versions is a bit weird. Test are here to ensure we do not
    // change our behavior unintentionally

    // With internal versions, tt means "if object is there with version X, update it or explode. If
    // it is not there, index.
    client()
        .prepareUpdate("test", "type", "3")
        .setScript("ctx._source.text = 'v2'", ScriptService.ScriptType.INLINE)
        .setVersion(10)
        .setUpsert("{ \"text\": \"v0\" }")
        .get();
    GetResponse get = get("test", "type", "3");
    assertThat(get.getVersion(), equalTo(1l));
    assertThat((String) get.getSource().get("text"), equalTo("v0"));

    // With force version
    client()
        .prepareUpdate("test", "type", "4")
        .setScript("ctx._source.text = 'v2'", ScriptService.ScriptType.INLINE)
        .setVersion(10)
        .setVersionType(VersionType.FORCE)
        .setUpsert("{ \"text\": \"v0\" }")
        .get();

    get = get("test", "type", "4");
    assertThat(get.getVersion(), equalTo(10l));
    assertThat((String) get.getSource().get("text"), equalTo("v0"));

    // retry on conflict is rejected:

    assertThrows(
        client().prepareUpdate("test", "type", "1").setVersion(10).setRetryOnConflict(5),
        ActionRequestValidationException.class);
  }