Merge branch 'stable-2.14' into stable-2.15
* stable-2.14:
ElasticReindexIT: Add tests against Elasticsearch version 6
Elasticsearch: Add tests for queries against version 6
Elasticsearch: Add support for V6 / one index type
The changes done in I04f275dd9 ("ElasticReindexIT: Add tests against
Elasticsearch version 6") are not included in this merge since the
reindex tests currently don't work on stable-2.15 (see issue 8799).
Change-Id: I1c940f6a95d39710dc7fb8c1cac605fa4c8efac6
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
index 5c0182c..eefcc09 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
@@ -20,6 +20,7 @@
import com.google.common.collect.FluentIterable;
import com.google.common.io.CharStreams;
+import com.google.gerrit.elasticsearch.ElasticMapping.MappingProperties;
import com.google.gerrit.elasticsearch.builders.SearchSourceBuilder;
import com.google.gerrit.elasticsearch.bulk.DeleteRequest;
import com.google.gerrit.index.Index;
@@ -50,6 +51,7 @@
abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
protected static final String BULK = "_bulk";
+ protected static final String MAPPINGS = "mappings";
protected static final String ORDER = "order";
protected static final String SEARCH = "_search";
@@ -79,6 +81,7 @@
private final Schema<V> schema;
private final SitePaths sitePaths;
private final String indexNameRaw;
+ private final String type;
protected final ElasticRestClientProvider client;
protected final String indexName;
@@ -98,6 +101,7 @@
this.indexName = cfg.getIndexName(indexName, schema.getVersion());
this.indexNameRaw = indexName;
this.client = client;
+ this.type = client.adapter().getType(indexName);
}
@Override
@@ -117,7 +121,7 @@
@Override
public void delete(K id) throws IOException {
- String uri = getURI(indexNameRaw, BULK);
+ String uri = getURI(type, BULK);
Response response = postRequest(getDeleteActions(id), uri, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
@@ -156,8 +160,20 @@
protected abstract String getId(V v);
+ protected String getMappingsForSingleType(String candidateType, MappingProperties properties) {
+ return getMappingsFor(client.adapter().getType(candidateType), properties);
+ }
+
+ protected String getMappingsFor(String type, MappingProperties properties) {
+ JsonObject mappingType = new JsonObject();
+ mappingType.add(type, gson.toJsonTree(properties));
+ JsonObject mappings = new JsonObject();
+ mappings.add(MAPPINGS, gson.toJsonTree(mappingType));
+ return gson.toJson(mappings);
+ }
+
protected String delete(String type, K id) {
- return new DeleteRequest(id.toString(), indexName, type).toString();
+ return new DeleteRequest(id.toString(), indexName, type, client.adapter()).toString();
}
protected void addNamedElement(String name, JsonObject element, JsonArray array) {
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
index 2a889ed..466614a 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
@@ -16,7 +16,6 @@
import static com.google.gerrit.server.index.account.AccountField.ID;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.gerrit.elasticsearch.ElasticMapping.MappingProperties;
import com.google.gerrit.elasticsearch.builders.QueryBuilder;
@@ -73,6 +72,7 @@
private final AccountMapping mapping;
private final Provider<AccountCache> accountCache;
private final Schema<AccountState> schema;
+ private final String type;
@AssistedInject
ElasticAccountIndex(
@@ -85,14 +85,16 @@
this.accountCache = accountCache;
this.mapping = new AccountMapping(schema, client.adapter());
this.schema = schema;
+ this.type = client.adapter().getType(ACCOUNTS);
}
@Override
public void replace(AccountState as) throws IOException {
BulkRequest bulk =
- new IndexRequest(getId(as), indexName, ACCOUNTS).add(new UpdateRequest<>(schema, as));
+ new IndexRequest(getId(as), indexName, type, client.adapter())
+ .add(new UpdateRequest<>(schema, as));
- String uri = getURI(ACCOUNTS, BULK);
+ String uri = getURI(type, BULK);
Response response = postRequest(bulk, uri, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
@@ -111,13 +113,12 @@
@Override
protected String getDeleteActions(Account.Id a) {
- return delete(ACCOUNTS, a);
+ return delete(type, a);
}
@Override
protected String getMappings() {
- ImmutableMap<String, AccountMapping> mappings = ImmutableMap.of("mappings", mapping);
- return gson.toJson(mappings);
+ return getMappingsForSingleType(ACCOUNTS, mapping.accounts);
}
@Override
@@ -152,7 +153,7 @@
public ResultSet<AccountState> read() throws OrmException {
try {
List<AccountState> results = Collections.emptyList();
- String uri = getURI(ACCOUNTS, SEARCH);
+ String uri = getURI(type, SEARCH);
Response response = postRequest(search, uri, Collections.emptyMap());
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
index 8d7ffa6..1a20906 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
@@ -84,11 +84,13 @@
private static final Logger log = LoggerFactory.getLogger(ElasticChangeIndex.class);
static class ChangeMapping {
- MappingProperties openChanges;
- MappingProperties closedChanges;
+ public MappingProperties changes;
+ public MappingProperties openChanges;
+ public MappingProperties closedChanges;
ChangeMapping(Schema<ChangeData> schema, ElasticQueryAdapter adapter) {
MappingProperties mapping = ElasticMapping.createMapping(schema, adapter);
+ this.changes = mapping;
this.openChanges = mapping;
this.closedChanges = mapping;
}
@@ -102,6 +104,7 @@
private final Provider<ReviewDb> db;
private final ChangeData.Factory changeDataFactory;
private final Schema<ChangeData> schema;
+ private final String type;
@Inject
ElasticChangeIndex(
@@ -116,6 +119,7 @@
this.changeDataFactory = changeDataFactory;
this.schema = schema;
this.mapping = new ChangeMapping(schema, client.adapter());
+ this.type = client.adapter().getType(CHANGES);
}
@Override
@@ -135,12 +139,15 @@
throw new IOException(e);
}
+ ElasticQueryAdapter adapter = client.adapter();
BulkRequest bulk =
- new IndexRequest(getId(cd), indexName, insertIndex)
- .add(new UpdateRequest<>(schema, cd))
- .add(new DeleteRequest(cd.getId().toString(), indexName, deleteIndex));
+ new IndexRequest(getId(cd), indexName, adapter.getType(insertIndex), adapter)
+ .add(new UpdateRequest<>(schema, cd));
+ if (!adapter.usePostV5Type()) {
+ bulk.add(new DeleteRequest(cd.getId().toString(), indexName, deleteIndex, adapter));
+ }
- String uri = getURI(CHANGES, BULK);
+ String uri = getURI(type, BULK);
Response response = postRequest(bulk, uri, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
@@ -155,23 +162,36 @@
throws QueryParseException {
Set<Change.Status> statuses = ChangeIndexRewriter.getPossibleStatus(p);
List<String> indexes = Lists.newArrayListWithCapacity(2);
- if (!Sets.intersection(statuses, OPEN_STATUSES).isEmpty()) {
- indexes.add(OPEN_CHANGES);
- }
- if (!Sets.intersection(statuses, CLOSED_STATUSES).isEmpty()) {
- indexes.add(CLOSED_CHANGES);
+ if (client.adapter().usePostV5Type()) {
+ if (!Sets.intersection(statuses, OPEN_STATUSES).isEmpty()
+ || !Sets.intersection(statuses, CLOSED_STATUSES).isEmpty()) {
+ indexes.add(ElasticQueryAdapter.POST_V5_TYPE);
+ }
+ } else {
+ if (!Sets.intersection(statuses, OPEN_STATUSES).isEmpty()) {
+ indexes.add(OPEN_CHANGES);
+ }
+ if (!Sets.intersection(statuses, CLOSED_STATUSES).isEmpty()) {
+ indexes.add(CLOSED_CHANGES);
+ }
}
return new QuerySource(indexes, p, opts);
}
@Override
protected String getDeleteActions(Id c) {
+ if (client.adapter().usePostV5Type()) {
+ return delete(ElasticQueryAdapter.POST_V5_TYPE, c);
+ }
return delete(OPEN_CHANGES, c) + delete(CLOSED_CHANGES, c);
}
@Override
protected String getMappings() {
- return gson.toJson(ImmutableMap.of("mappings", mapping));
+ if (client.adapter().usePostV5Type()) {
+ return getMappingsFor(ElasticQueryAdapter.POST_V5_TYPE, mapping.changes);
+ }
+ return gson.toJson(ImmutableMap.of(MAPPINGS, mapping));
}
@Override
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
index 9311c20..00caeae 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
@@ -14,7 +14,6 @@
package com.google.gerrit.elasticsearch;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.gerrit.elasticsearch.ElasticMapping.MappingProperties;
import com.google.gerrit.elasticsearch.builders.QueryBuilder;
@@ -72,6 +71,7 @@
private final GroupMapping mapping;
private final Provider<GroupCache> groupCache;
private final Schema<InternalGroup> schema;
+ private final String type;
@AssistedInject
ElasticGroupIndex(
@@ -84,14 +84,16 @@
this.groupCache = groupCache;
this.mapping = new GroupMapping(schema, client.adapter());
this.schema = schema;
+ this.type = client.adapter().getType(GROUPS);
}
@Override
public void replace(InternalGroup group) throws IOException {
BulkRequest bulk =
- new IndexRequest(getId(group), indexName, GROUPS).add(new UpdateRequest<>(schema, group));
+ new IndexRequest(getId(group), indexName, type, client.adapter())
+ .add(new UpdateRequest<>(schema, group));
- String uri = getURI(GROUPS, BULK);
+ String uri = getURI(type, BULK);
Response response = postRequest(bulk, uri, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
@@ -110,13 +112,12 @@
@Override
protected String getDeleteActions(AccountGroup.UUID g) {
- return delete(GROUPS, g);
+ return delete(type, g);
}
@Override
protected String getMappings() {
- ImmutableMap<String, GroupMapping> mappings = ImmutableMap.of("mappings", mapping);
- return gson.toJson(mappings);
+ return getMappingsForSingleType(GROUPS, mapping.groups);
}
@Override
@@ -151,7 +152,7 @@
public ResultSet<InternalGroup> read() throws OrmException {
try {
List<InternalGroup> results = Collections.emptyList();
- String uri = getURI(GROUPS, SEARCH);
+ String uri = getURI(type, SEARCH);
Response response = postRequest(search, uri, Collections.emptyMap());
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java
index 72af49a..6eb9384 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java
@@ -17,7 +17,11 @@
import com.google.gson.JsonObject;
public class ElasticQueryAdapter {
+ static final String POST_V5_TYPE = "_doc";
+
private final boolean ignoreUnmapped;
+ private final boolean usePostV5Type;
+
private final String searchFilteringName;
private final String indicesExistParam;
private final String exactFieldType;
@@ -26,6 +30,8 @@
ElasticQueryAdapter(ElasticVersion version) {
this.ignoreUnmapped = version == ElasticVersion.V2_4;
+ this.usePostV5Type = version == ElasticVersion.V6_2;
+
switch (version) {
case V5_6:
case V6_2:
@@ -52,6 +58,12 @@
}
}
+ public void setType(JsonObject properties, String type) {
+ if (!usePostV5Type) {
+ properties.addProperty("_type", type);
+ }
+ }
+
public String searchFilteringName() {
return searchFilteringName;
}
@@ -71,4 +83,12 @@
String indexProperty() {
return indexProperty;
}
+
+ boolean usePostV5Type() {
+ return usePostV5Type;
+ }
+
+ String getType(String preV6Type) {
+ return usePostV5Type() ? POST_V5_TYPE : preV6Type;
+ }
}
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/ActionRequest.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/ActionRequest.java
index c7757b2..7392d09 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/ActionRequest.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/ActionRequest.java
@@ -14,6 +14,7 @@
package com.google.gerrit.elasticsearch.bulk;
+import com.google.gerrit.elasticsearch.ElasticQueryAdapter;
import com.google.gson.JsonObject;
abstract class ActionRequest extends BulkRequest {
@@ -22,12 +23,15 @@
private final String id;
private final String index;
private final String type;
+ private final ElasticQueryAdapter adapter;
- protected ActionRequest(String action, String id, String index, String type) {
+ protected ActionRequest(
+ String action, String id, String index, String type, ElasticQueryAdapter adapter) {
this.action = action;
this.id = id;
this.index = index;
this.type = type;
+ this.adapter = adapter;
}
@Override
@@ -35,7 +39,7 @@
JsonObject properties = new JsonObject();
properties.addProperty("_id", id);
properties.addProperty("_index", index);
- properties.addProperty("_type", type);
+ adapter.setType(properties, type);
JsonObject jsonAction = new JsonObject();
jsonAction.add(action, properties);
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/DeleteRequest.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/DeleteRequest.java
index 7d549ca..570d5a0 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/DeleteRequest.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/DeleteRequest.java
@@ -14,9 +14,11 @@
package com.google.gerrit.elasticsearch.bulk;
+import com.google.gerrit.elasticsearch.ElasticQueryAdapter;
+
public class DeleteRequest extends ActionRequest {
- public DeleteRequest(String id, String index, String type) {
- super("delete", id, index, type);
+ public DeleteRequest(String id, String index, String type, ElasticQueryAdapter adapter) {
+ super("delete", id, index, type, adapter);
}
}
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/IndexRequest.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/IndexRequest.java
index b131501..c571a0e 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/IndexRequest.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/bulk/IndexRequest.java
@@ -14,9 +14,11 @@
package com.google.gerrit.elasticsearch.bulk;
+import com.google.gerrit.elasticsearch.ElasticQueryAdapter;
+
public class IndexRequest extends ActionRequest {
- public IndexRequest(String id, String index, String type) {
- super("index", id, index, type);
+ public IndexRequest(String id, String index, String type, ElasticQueryAdapter adapter) {
+ super("index", id, index, type, adapter);
}
}
diff --git a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java
index cbbd764..44725dc 100644
--- a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java
+++ b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java
@@ -47,7 +47,7 @@
case V5_6:
return "elasticsearch:5.6.9-alpine";
case V6_2:
- return "docker.elastic.co/elasticsearch/elasticsearch:6.2.4";
+ return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4";
}
throw new IllegalStateException("No tests for version: " + version.name());
}
diff --git a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticV6QueryAccountsTest.java b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticV6QueryAccountsTest.java
new file mode 100644
index 0000000..669fca0
--- /dev/null
+++ b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticV6QueryAccountsTest.java
@@ -0,0 +1,66 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.elasticsearch;
+
+import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo;
+import com.google.gerrit.server.query.account.AbstractQueryAccountsTest;
+import com.google.gerrit.testutil.InMemoryModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.eclipse.jgit.lib.Config;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public class ElasticV6QueryAccountsTest extends AbstractQueryAccountsTest {
+ private static ElasticNodeInfo nodeInfo;
+ private static ElasticContainer<?> container;
+
+ @BeforeClass
+ public static void startIndexService() {
+ if (nodeInfo != null) {
+ // do not start Elasticsearch twice
+ return;
+ }
+
+ container = ElasticContainer.createAndStart(ElasticVersion.V6_2);
+ nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
+ }
+
+ @AfterClass
+ public static void stopElasticsearchServer() {
+ if (container != null) {
+ container.stop();
+ }
+ }
+
+ private String testName() {
+ return testName.getMethodName().toLowerCase() + "_";
+ }
+
+ @Override
+ protected void initAfterLifecycleStart() throws Exception {
+ super.initAfterLifecycleStart();
+ ElasticTestUtils.createAllIndexes(injector);
+ }
+
+ @Override
+ protected Injector createInjector() {
+ Config elasticsearchConfig = new Config(config);
+ InMemoryModule.setDefaults(elasticsearchConfig);
+ String indicesPrefix = testName();
+ ElasticTestUtils.configure(elasticsearchConfig, nodeInfo.port, indicesPrefix);
+ return Guice.createInjector(new InMemoryModule(elasticsearchConfig, notesMigration));
+ }
+}
diff --git a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticV6QueryChangesTest.java b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticV6QueryChangesTest.java
new file mode 100644
index 0000000..36d90d5
--- /dev/null
+++ b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticV6QueryChangesTest.java
@@ -0,0 +1,67 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.elasticsearch;
+
+import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo;
+import com.google.gerrit.server.query.change.AbstractQueryChangesTest;
+import com.google.gerrit.testutil.InMemoryModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.eclipse.jgit.lib.Config;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public class ElasticV6QueryChangesTest extends AbstractQueryChangesTest {
+
+ private static ElasticNodeInfo nodeInfo;
+ private static ElasticContainer<?> container;
+
+ @BeforeClass
+ public static void startIndexService() {
+ if (nodeInfo != null) {
+ // do not start Elasticsearch twice
+ return;
+ }
+
+ container = ElasticContainer.createAndStart(ElasticVersion.V6_2);
+ nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
+ }
+
+ @AfterClass
+ public static void stopElasticsearchServer() {
+ if (container != null) {
+ container.stop();
+ }
+ }
+
+ private String testName() {
+ return testName.getMethodName().toLowerCase() + "_";
+ }
+
+ @Override
+ protected void initAfterLifecycleStart() throws Exception {
+ super.initAfterLifecycleStart();
+ ElasticTestUtils.createAllIndexes(injector);
+ }
+
+ @Override
+ protected Injector createInjector() {
+ Config elasticsearchConfig = new Config(config);
+ InMemoryModule.setDefaults(elasticsearchConfig);
+ String indicesPrefix = testName();
+ ElasticTestUtils.configure(elasticsearchConfig, nodeInfo.port, indicesPrefix);
+ return Guice.createInjector(new InMemoryModule(elasticsearchConfig, notesMigration));
+ }
+}
diff --git a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticV6QueryGroupsTest.java b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticV6QueryGroupsTest.java
new file mode 100644
index 0000000..029c665
--- /dev/null
+++ b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticV6QueryGroupsTest.java
@@ -0,0 +1,66 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.elasticsearch;
+
+import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo;
+import com.google.gerrit.server.query.group.AbstractQueryGroupsTest;
+import com.google.gerrit.testutil.InMemoryModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.eclipse.jgit.lib.Config;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public class ElasticV6QueryGroupsTest extends AbstractQueryGroupsTest {
+ private static ElasticNodeInfo nodeInfo;
+ private static ElasticContainer<?> container;
+
+ @BeforeClass
+ public static void startIndexService() {
+ if (nodeInfo != null) {
+ // do not start Elasticsearch twice
+ return;
+ }
+
+ container = ElasticContainer.createAndStart(ElasticVersion.V6_2);
+ nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
+ }
+
+ @AfterClass
+ public static void stopElasticsearchServer() {
+ if (container != null) {
+ container.stop();
+ }
+ }
+
+ private String testName() {
+ return testName.getMethodName().toLowerCase() + "_";
+ }
+
+ @Override
+ protected void initAfterLifecycleStart() throws Exception {
+ super.initAfterLifecycleStart();
+ ElasticTestUtils.createAllIndexes(injector);
+ }
+
+ @Override
+ protected Injector createInjector() {
+ Config elasticsearchConfig = new Config(config);
+ InMemoryModule.setDefaults(elasticsearchConfig);
+ String indicesPrefix = testName();
+ ElasticTestUtils.configure(elasticsearchConfig, nodeInfo.port, indicesPrefix);
+ return Guice.createInjector(new InMemoryModule(elasticsearchConfig, notesMigration));
+ }
+}