Merge branch 'stable-3.6'
* stable-3.6:
Remove dependency on //java/com/google/gerrit/proto
Restore dockerized integration tests
Adapt Bazel build and deps to latest stable-3.5
Adapt to the latest Index interface in stable-3.5
Also adapt account and change index implementation to removal of support
for legacy numeric type done in: I6a040f55cc.
Change-Id: I360f99595aec8430de593318eff5c403fe5a9040
diff --git a/BUILD b/BUILD
index 06352ab..4750354 100644
--- a/BUILD
+++ b/BUILD
@@ -1,6 +1,5 @@
load("@rules_java//java:defs.bzl", "java_library")
load("//tools/bzl:junit.bzl", "junit_tests")
-load("//javatests/com/google/gerrit/acceptance:tests.bzl", "acceptance_tests")
load(
"//tools/bzl:plugin.bzl",
"PLUGIN_DEPS",
@@ -8,72 +7,54 @@
"gerrit_plugin",
)
-gerrit_plugin (
+gerrit_plugin(
name = "index-elasticsearch",
srcs = glob(["src/main/java/**/*.java"]),
deps = [
- "//java/com/google/gerrit/common:annotations",
- "//java/com/google/gerrit/entities",
- "//java/com/google/gerrit/exceptions",
- "//java/com/google/gerrit/extensions:api",
- "//java/com/google/gerrit/index",
- "//java/com/google/gerrit/index:query_exception",
- "//java/com/google/gerrit/index/project",
- "//java/com/google/gerrit/lifecycle",
- "//java/com/google/gerrit/proto",
- "//java/com/google/gerrit/server",
- "//lib:gson",
- "//lib:guava",
- "//lib:jgit",
- "//lib:protobuf",
- "//lib/commons:lang",
"@elasticsearch-rest-client//jar",
- "//lib/flogger:api",
- "//lib/guice",
- "//lib/guice:guice-assistedinject",
"@httpasyncclient//jar",
- "//lib/httpcomponents:httpclient",
- "//lib/httpcomponents:httpcore",
"@httpcore-nio//jar",
"@jackson-core//jar",
],
)
+ELASTICSEARCH_DEPS = [
+ "@docker-java-api//jar",
+ "@docker-java-transport//jar",
+ "@duct-tape//jar",
+ "@httpasyncclient//jar",
+ "@jackson-annotations//jar",
+ "@jackson-core//jar",
+ "@jna//jar",
+ "@testcontainers-elasticsearch//jar",
+ "@testcontainers//jar",
+]
+
java_library(
- name = "elasticsearch_test_utils",
+ name = "index-elasticsearch__plugin_test_deps",
testonly = True,
srcs = [],
visibility = ["//visibility:public"],
- deps = [
- "//java/com/google/gerrit/index",
- "//lib:guava",
- "//lib:jgit",
- "//lib:junit",
- "//lib/guice",
- "//lib/httpcomponents:httpcore",
- "//lib/jackson:jackson-annotations",
- "//lib/testcontainers",
- "//lib/testcontainers:docker-java-api",
- "//lib/testcontainers:docker-java-transport",
- "@testcontainers-elasticsearch//jar",
+ exports = ELASTICSEARCH_DEPS,
+)
+
+java_library(
+ name = "elasticsearch_test_utils",
+ testonly = True,
+ srcs = glob(
+ ["src/test/java/**/*.java"],
+ exclude = ["src/test/java/**/*Test.java"],
+ ),
+ visibility = ["//visibility:public"],
+ deps = ELASTICSEARCH_DEPS + PLUGIN_DEPS + PLUGIN_TEST_DEPS + [
":index-elasticsearch__plugin",
],
)
-ELASTICSEARCH_DEPS = [
- ":elasticsearch_test_utils",
- "//java/com/google/gerrit/testing:gerrit-test-util",
- "//lib/guice",
- "//lib:jgit",
-]
-
-HTTP_TEST_DEPS = [
- "@httpasyncclient//jar",
- "//lib/httpcomponents:httpclient",
-]
-
QUERY_TESTS_DEP = "//javatests/com/google/gerrit/server/query/%s:abstract_query_tests"
+ACCOUNT_QUERY_TESTS_DEP = "//javatests/com/google/gerrit/server/query/account:abstract_query_tests"
+
TYPES = [
"account",
"change",
@@ -85,26 +66,30 @@
ELASTICSEARCH_TESTS_V7 = {i: "ElasticV7Query" + i.capitalize() + SUFFIX for i in TYPES}
-ELASTICSEARCH_TAGS = [
- "docker",
- "elastic",
-]
+[junit_tests(
+ name = "elasticsearch_query_%ss_test_V7" % name,
+ size = "enormous",
+ srcs = ["src/test/java/com/google/gerrit/elasticsearch/" + src],
+ tags = [
+ "docker",
+ "elastic",
+ ],
+ deps = ELASTICSEARCH_DEPS + PLUGIN_TEST_DEPS + [
+ QUERY_TESTS_DEP % name,
+ ":elasticsearch_test_utils",
+ ":index-elasticsearch__plugin",
+ ],
+) for name, src in ELASTICSEARCH_TESTS_V7.items()]
junit_tests(
name = "index-elasticsearch_tests",
size = "small",
srcs = glob(
["src/test/java/**/*Test.java"],
- exclude = ["Elastic*Query*" + SUFFIX],
+ exclude = ["src/test/java/**/Elastic*Query*" + SUFFIX],
),
tags = ["elastic"],
- deps = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [
- "//java/com/google/gerrit/testing:gerrit-test-util",
- "//lib:guava",
- "//lib:jgit",
- "//lib/guice",
- "//lib/httpcomponents:httpcore",
- "//lib/truth",
- ":elasticsearch_test_utils",
+ deps = PLUGIN_TEST_DEPS + [
+ ":index-elasticsearch__plugin",
],
)
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index b863175..fc1420c 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -5,6 +5,12 @@
# Ensure artifacts compatibility by selecting them from the Bill Of Materials
# https://search.maven.org/artifact/net.openhft/chronicle-bom/2.20.191/pom
def external_plugin_deps():
+ maven_jar(
+ name = "testcontainers",
+ artifact = "org.testcontainers:testcontainers:" + TESTCONTAINERS_VERSION,
+ sha1 = "95c6cfde71c2209f0c29cb14e432471e0b111880",
+ )
+
# When upgrading elasticsearch-rest-client, also upgrade httpcore-nio
# and httpasyncclient as necessary in tools/nongoogle.bzl. Consider
# also the other org.apache.httpcomponents dependencies in
@@ -21,6 +27,38 @@
sha1 = "595e3a50f59cd3c1d281ca6c1bc4037e277a1353",
)
+ maven_jar(
+ name = "duct-tape",
+ artifact = "org.rnorth.duct-tape:duct-tape:1.0.8",
+ sha1 = "92edc22a9ab2f3e17c9bf700aaee377d50e8b530",
+ )
+
+ maven_jar(
+ name = "visible-assertions",
+ artifact = "org.rnorth.visible-assertions:visible-assertions:2.1.2",
+ sha1 = "20d31a578030ec8e941888537267d3123c2ad1c1",
+ )
+
+ maven_jar(
+ name = "jna",
+ artifact = "net.java.dev.jna:jna:5.5.0",
+ sha1 = "0e0845217c4907822403912ad6828d8e0b256208",
+ )
+
+ DOCKER_JAVA_VERS = "3.2.8"
+
+ maven_jar(
+ name = "docker-java-api",
+ artifact = "com.github.docker-java:docker-java-api:" + DOCKER_JAVA_VERS,
+ sha1 = "4ac22a72d546a9f3523cd4b5fabffa77c4a6ec7c",
+ )
+
+ maven_jar(
+ name = "docker-java-transport",
+ artifact = "com.github.docker-java:docker-java-transport:" + DOCKER_JAVA_VERS,
+ sha1 = "c3b5598c67d0a5e2e780bf48f520da26b9915eab",
+ )
+
# elasticsearch-rest-client explicitly depends on this version
maven_jar(
name = "httpasyncclient",
@@ -42,8 +80,13 @@
)
maven_jar(
+ name = "jackson-annotations",
+ artifact = "com.fasterxml.jackson.core:jackson-annotations:2.10.3",
+ sha1 = "0f63b3b1da563767d04d2e4d3fc1ae0cdeffebe7",
+ )
+
+ maven_jar(
name = "httpasyncclient",
artifact = "org.apache.httpcomponents:httpasyncclient:4.1.4",
sha1 = "f3a3240681faae3fa46b573a4c7e50cec9db0d86",
)
-
diff --git a/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java b/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
index 562464d..90ce18b 100644
--- a/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
+++ b/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
@@ -152,6 +152,11 @@
}
@Override
+ public void insert(V obj) {
+ replace(obj);
+ }
+
+ @Override
public Schema<V> getSchema() {
return schema;
}
diff --git a/src/main/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java b/src/main/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
index 8967789..beb57bd 100644
--- a/src/main/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
+++ b/src/main/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
@@ -91,15 +91,12 @@
@Override
public DataSource<AccountState> getSource(Predicate<AccountState> p, QueryOptions opts)
throws QueryParseException {
+ boolean useLegacyNumericFields = schema.hasField(AccountField.ID);
JsonArray sortArray =
getSortArray(
- schema.useLegacyNumericFields()
- ? AccountField.ID.getName()
- : AccountField.ID_STR.getName());
+ useLegacyNumericFields ? AccountField.ID.getName() : AccountField.ID_STR.getName());
return new ElasticQuerySource(
- p,
- opts.filterFields(o -> IndexUtils.accountFields(o, schema.useLegacyNumericFields())),
- sortArray);
+ p, opts.filterFields(o -> IndexUtils.accountFields(o, useLegacyNumericFields)), sortArray);
}
@Override
@@ -129,7 +126,7 @@
source
.getAsJsonObject()
.get(
- schema.useLegacyNumericFields()
+ schema.hasField(AccountField.ID)
? AccountField.ID.getName()
: AccountField.ID_STR.getName())
.getAsInt());
diff --git a/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java b/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
index 7d4e0c7..83be597 100644
--- a/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
+++ b/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
@@ -69,7 +69,6 @@
private final ChangeMapping mapping;
private final ChangeData.Factory changeDataFactory;
private final Schema<ChangeData> schema;
- private final FieldDef<ChangeData, ?> idField;
private final ImmutableSet<String> skipFields;
@Inject
@@ -84,8 +83,6 @@
this.changeDataFactory = changeDataFactory;
this.schema = schema;
this.mapping = new ChangeMapping(schema, client.adapter());
- this.idField =
- this.schema.useLegacyNumericFields() ? ChangeField.LEGACY_ID : ChangeField.LEGACY_ID_STR;
this.skipFields =
MergeabilityComputationBehavior.fromConfig(gerritConfig).includeInIndex()
? ImmutableSet.of()
@@ -110,8 +107,7 @@
@Override
public DataSource<ChangeData> getSource(Predicate<ChangeData> p, QueryOptions opts)
throws QueryParseException {
- QueryOptions filteredOpts =
- opts.filterFields(o -> IndexUtils.changeFields(o, schema.useLegacyNumericFields()));
+ QueryOptions filteredOpts = opts.filterFields(o -> IndexUtils.changeFields(o));
return new ElasticQuerySource(p, filteredOpts, getSortArray());
}
@@ -122,7 +118,7 @@
JsonArray sortArray = new JsonArray();
addNamedElement(ChangeField.UPDATED.getName(), properties, sortArray);
addNamedElement(ChangeField.MERGED_ON.getName(), getMergedOnSortOptions(), sortArray);
- addNamedElement(idField.getName(), properties, sortArray);
+ addNamedElement(ChangeField.LEGACY_ID_STR.getName(), properties, sortArray);
return sortArray;
}
@@ -160,7 +156,7 @@
JsonElement c = source.get(ChangeField.CHANGE.getName());
if (c == null) {
- int id = source.get(idField.getName()).getAsInt();
+ int id = source.get(ChangeField.LEGACY_ID_STR.getName()).getAsInt();
// IndexUtils#changeFields ensures either CHANGE or PROJECT is always present.
String projectName = requireNonNull(source.get(ChangeField.PROJECT.getName()).getAsString());
return changeDataFactory.create(Project.nameKey(projectName), Change.id(id));
diff --git a/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java b/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
index 40ac603..9fc070a 100644
--- a/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
+++ b/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
@@ -29,7 +29,6 @@
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.index.query.RegexPredicate;
import com.google.gerrit.index.query.TimestampRangePredicate;
-import java.time.Instant;
public class ElasticQueryBuilder {
@@ -119,9 +118,8 @@
}
private <T> QueryBuilder notTimestamp(TimestampRangePredicate<T> r) throws QueryParseException {
- if (r.getMinTimestamp().getTime() == 0) {
- return QueryBuilders.rangeQuery(r.getField().getName())
- .gt(Instant.ofEpochMilli(r.getMaxTimestamp().getTime()));
+ if (r.getMinTimestamp().toEpochMilli() == 0) {
+ return QueryBuilders.rangeQuery(r.getField().getName()).gt(r.getMaxTimestamp());
}
throw new QueryParseException("cannot negate: " + r);
}
@@ -129,15 +127,14 @@
private <T> QueryBuilder timestampQuery(IndexPredicate<T> p) throws QueryParseException {
if (p instanceof TimestampRangePredicate) {
TimestampRangePredicate<T> r = (TimestampRangePredicate<T>) p;
- if (r.getMaxTimestamp().getTime() == Long.MAX_VALUE) {
+ if (r.getMaxTimestamp().toEpochMilli() == Long.MAX_VALUE) {
// The time range only has the start value, search from the start to the max supported value
// Long.MAX_VALUE
- return QueryBuilders.rangeQuery(r.getField().getName())
- .gte(Instant.ofEpochMilli(r.getMinTimestamp().getTime()));
+ return QueryBuilders.rangeQuery(r.getField().getName()).gte(r.getMinTimestamp());
}
return QueryBuilders.rangeQuery(r.getField().getName())
- .gte(Instant.ofEpochMilli(r.getMinTimestamp().getTime()))
- .lte(Instant.ofEpochMilli(r.getMaxTimestamp().getTime()));
+ .gte(r.getMinTimestamp())
+ .lte(r.getMaxTimestamp());
}
throw new QueryParseException("not a timestamp: " + p);
}
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index b6f6e51..1720f52 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -34,4 +34,20 @@
```sh
bazelisk test plugins/index-elasticsearch/...
-```
\ No newline at end of file
+```
+
+This project can be imported into the Eclipse IDE.
+Add the plugin name to the `CUSTOM_PLUGINS` and to the
+`CUSTOM_PLUGINS_TEST_DEPS` set in Gerrit core in
+`tools/bzl/plugins.bzl`, and execute:
+
+```
+ ./tools/eclipse/project.py
+```
+
+More information about Bazel can be found in the [Gerrit
+documentation](../../../Documentation/dev-bazel.html).
+
+[Back to @PLUGIN@ documentation index][index]
+
+[index]: index.html
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java
new file mode 100644
index 0000000..503852b
--- /dev/null
+++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java
@@ -0,0 +1,59 @@
+// 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 org.apache.http.HttpHost;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.elasticsearch.ElasticsearchContainer;
+import org.testcontainers.utility.DockerImageName;
+
+/* Helper class for running ES integration tests in docker container */
+public class ElasticContainer extends ElasticsearchContainer {
+ private static final int ELASTICSEARCH_DEFAULT_PORT = 9200;
+
+ public static ElasticContainer createAndStart(ElasticVersion version) {
+ ElasticContainer container = new ElasticContainer(version);
+ container.start();
+ return container;
+ }
+
+ private static String getImageName(ElasticVersion version) {
+ switch (version) {
+ case V7_6:
+ return "blacktop/elasticsearch:7.6.2";
+ case V7_7:
+ return "blacktop/elasticsearch:7.7.1";
+ case V7_8:
+ return "blacktop/elasticsearch:7.8.1";
+ }
+ throw new IllegalStateException("No tests for version: " + version.name());
+ }
+
+ private ElasticContainer(ElasticVersion version) {
+ super(
+ DockerImageName.parse(getImageName(version))
+ .asCompatibleSubstituteFor("docker.elastic.co/elasticsearch/elasticsearch"));
+ }
+
+ @Override
+ protected Logger logger() {
+ return LoggerFactory.getLogger("org.testcontainers");
+ }
+
+ public HttpHost getHttpHost() {
+ return new HttpHost(getContainerIpAddress(), getMappedPort(ELASTICSEARCH_DEFAULT_PORT));
+ }
+}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java
new file mode 100644
index 0000000..c3ca595
--- /dev/null
+++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java
@@ -0,0 +1,87 @@
+// Copyright (C) 2016 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.index.IndexDefinition;
+import com.google.gerrit.server.LibModuleType;
+import com.google.gerrit.testing.GerritTestName;
+import com.google.gerrit.testing.InMemoryModule;
+import com.google.gerrit.testing.IndexConfig;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import java.util.Collection;
+import java.util.UUID;
+import org.eclipse.jgit.lib.Config;
+
+public final class ElasticTestUtils {
+ public static void configure(Config config, ElasticContainer container, String prefix) {
+ String hostname = container.getHttpHost().getHostName();
+ int port = container.getHttpHost().getPort();
+ config.setString("index", null, "type", "elasticsearch");
+ config.setString("elasticsearch", null, "server", "http://" + hostname + ":" + port);
+ config.setString("elasticsearch", null, "prefix", prefix);
+ config.setInt("index", null, "maxLimit", 10000);
+ }
+
+ public static void createAllIndexes(Injector injector) {
+ Collection<IndexDefinition<?, ?, ?>> indexDefs =
+ injector.getInstance(Key.get(new TypeLiteral<Collection<IndexDefinition<?, ?, ?>>>() {}));
+ for (IndexDefinition<?, ?, ?> indexDef : indexDefs) {
+ indexDef.getIndexCollection().getSearchIndex().deleteAll();
+ }
+ }
+
+ public static Config getConfig(ElasticVersion version) {
+ ElasticContainer container = ElasticContainer.createAndStart(version);
+ String indicesPrefix = UUID.randomUUID().toString();
+ Config cfg = new Config();
+ configure(cfg, container, indicesPrefix);
+ return cfg;
+ }
+
+ public static Config createConfig() {
+ Config cfg = IndexConfig.create();
+
+ // For some reason enabling the staleness checker increases the flakiness of the Elasticsearch
+ // tests. Hence disable the staleness checker.
+ cfg.setBoolean("index", null, "autoReindexIfStale", false);
+
+ return cfg;
+ }
+
+ public static void configureElasticModule(Config elasticsearchConfig) {
+ elasticsearchConfig.setString(
+ "index",
+ null,
+ "install" + LibModuleType.INDEX_MODULE_TYPE.getConfigKey(),
+ "com.google.gerrit.elasticsearch.ElasticIndexModule");
+ }
+
+ public static Injector createInjector(
+ Config config, GerritTestName testName, ElasticContainer container) {
+ Config elasticsearchConfig = new Config(config);
+ ElasticTestUtils.configureElasticModule(elasticsearchConfig);
+ InMemoryModule.setDefaults(elasticsearchConfig);
+ String indicesPrefix = testName.getSanitizedMethodName();
+ ElasticTestUtils.configure(elasticsearchConfig, container, indicesPrefix);
+ return Guice.createInjector(new InMemoryModule(elasticsearchConfig));
+ }
+
+ private ElasticTestUtils() {
+ // hide default constructor
+ }
+}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java
new file mode 100644
index 0000000..4ee5a16
--- /dev/null
+++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java
@@ -0,0 +1,57 @@
+// 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.server.query.account.AbstractQueryAccountsTest;
+import com.google.gerrit.testing.ConfigSuite;
+import com.google.inject.Injector;
+import org.eclipse.jgit.lib.Config;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public class ElasticV7QueryAccountsTest extends AbstractQueryAccountsTest {
+ @ConfigSuite.Default
+ public static Config defaultConfig() {
+ return ElasticTestUtils.createConfig();
+ }
+
+ private static ElasticContainer container;
+
+ @BeforeClass
+ public static void startIndexService() {
+ if (container == null) {
+ // Only start Elasticsearch once
+ container = ElasticContainer.createAndStart(ElasticVersion.V7_8);
+ }
+ }
+
+ @AfterClass
+ public static void stopElasticsearchServer() {
+ if (container != null) {
+ container.stop();
+ }
+ }
+
+ @Override
+ protected void initAfterLifecycleStart() throws Exception {
+ super.initAfterLifecycleStart();
+ ElasticTestUtils.createAllIndexes(injector);
+ }
+
+ @Override
+ protected Injector createInjector() {
+ return ElasticTestUtils.createInjector(config, testName, container);
+ }
+}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java
new file mode 100644
index 0000000..d704e40
--- /dev/null
+++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java
@@ -0,0 +1,141 @@
+// 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 static com.google.common.truth.TruthJUnit.assume;
+import static java.util.concurrent.TimeUnit.MINUTES;
+
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.server.change.ChangeInserter;
+import com.google.gerrit.server.index.change.ChangeField;
+import com.google.gerrit.server.query.change.AbstractQueryChangesTest;
+import com.google.gerrit.testing.ConfigSuite;
+import com.google.gerrit.testing.GerritTestName;
+import com.google.gerrit.testing.InMemoryRepositoryManager.Repo;
+import com.google.inject.Injector;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
+import org.apache.http.impl.nio.client.HttpAsyncClients;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Config;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class ElasticV7QueryChangesTest extends AbstractQueryChangesTest {
+ @ConfigSuite.Default
+ public static Config defaultConfig() {
+ return ElasticTestUtils.createConfig();
+ }
+
+ private static ElasticContainer container;
+ private static CloseableHttpAsyncClient client;
+
+ @BeforeClass
+ public static void startIndexService() {
+ if (container == null) {
+ // Only start Elasticsearch once
+ container = ElasticContainer.createAndStart(ElasticVersion.V7_8);
+ client = HttpAsyncClients.createDefault();
+ client.start();
+ }
+ }
+
+ @AfterClass
+ public static void stopElasticsearchServer() {
+ if (container != null) {
+ container.stop();
+ }
+ }
+
+ @Rule public final GerritTestName testName = new GerritTestName();
+
+ @After
+ public void closeIndex() throws Exception {
+ // Close the index after each test to prevent exceeding Elasticsearch's
+ // shard limit (see Issue 10120).
+ client
+ .execute(
+ new HttpPost(
+ String.format(
+ "http://%s:%d/%s*/_close",
+ container.getHttpHost().getHostName(),
+ container.getHttpHost().getPort(),
+ testName.getSanitizedMethodName())),
+ HttpClientContext.create(),
+ null)
+ .get(5, MINUTES);
+ }
+
+ @Override
+ protected void initAfterLifecycleStart() throws Exception {
+ super.initAfterLifecycleStart();
+ ElasticTestUtils.createAllIndexes(injector);
+ }
+
+ @Test
+ @Override
+ // TODO(davido): overrides byTopic() method to adjust to ES behaviour for
+ // "prefixtopic" predicate. This should be fixed in a follow-up change.
+ public void byTopic() throws Exception {
+
+ TestRepository<Repo> repo = createProject("repo");
+ ChangeInserter ins1 = newChangeWithTopic(repo, "feature1");
+ Change change1 = insert(repo, ins1);
+
+ ChangeInserter ins2 = newChangeWithTopic(repo, "feature2");
+ Change change2 = insert(repo, ins2);
+
+ ChangeInserter ins3 = newChangeWithTopic(repo, "Cherrypick-feature2");
+ Change change3 = insert(repo, ins3);
+
+ ChangeInserter ins4 = newChangeWithTopic(repo, "feature2-fixup");
+ Change change4 = insert(repo, ins4);
+
+ ChangeInserter ins5 = newChangeWithTopic(repo, "https://gerrit.local");
+ Change change5 = insert(repo, ins5);
+
+ ChangeInserter ins6 = newChangeWithTopic(repo, "git_gerrit_training");
+ Change change6 = insert(repo, ins6);
+
+ Change change_no_topic = insert(repo, newChange(repo));
+
+ assertQuery("intopic:foo");
+ assertQuery("intopic:feature1", change1);
+ assertQuery("intopic:feature2", change4, change3, change2);
+ assertQuery("topic:feature2", change2);
+ assertQuery("intopic:feature2", change4, change3, change2);
+ assertQuery("intopic:fixup", change4);
+ assertQuery("intopic:gerrit", change6, change5);
+ assertQuery("topic:\"\"", change_no_topic);
+ assertQuery("intopic:\"\"", change_no_topic);
+
+ assume().that(getSchema().hasField(ChangeField.PREFIX_TOPIC)).isTrue();
+ // change3 is considered by ES in prefixtopic:feature query, see
+ // https://www.elastic.co/guide/en/elasticsearch/reference/8.2/query-dsl-match-query-phrase-prefix.html
+ // assertQuery("prefixtopic:feature", change4, change2, change1);
+ assertQuery("prefixtopic:feature", change4, change3, change2, change1);
+ assertQuery("prefixtopic:Cher", change3);
+ assertQuery("prefixtopic:feature22");
+ }
+
+ @Override
+ protected Injector createInjector() {
+ return ElasticTestUtils.createInjector(config, testName, container);
+ }
+}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java
new file mode 100644
index 0000000..649c0bc
--- /dev/null
+++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java
@@ -0,0 +1,57 @@
+// 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.server.query.group.AbstractQueryGroupsTest;
+import com.google.gerrit.testing.ConfigSuite;
+import com.google.inject.Injector;
+import org.eclipse.jgit.lib.Config;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public class ElasticV7QueryGroupsTest extends AbstractQueryGroupsTest {
+ @ConfigSuite.Default
+ public static Config defaultConfig() {
+ return ElasticTestUtils.createConfig();
+ }
+
+ private static ElasticContainer container;
+
+ @BeforeClass
+ public static void startIndexService() {
+ if (container == null) {
+ // Only start Elasticsearch once
+ container = ElasticContainer.createAndStart(ElasticVersion.V7_8);
+ }
+ }
+
+ @AfterClass
+ public static void stopElasticsearchServer() {
+ if (container != null) {
+ container.stop();
+ }
+ }
+
+ @Override
+ protected void initAfterLifecycleStart() throws Exception {
+ super.initAfterLifecycleStart();
+ ElasticTestUtils.createAllIndexes(injector);
+ }
+
+ @Override
+ protected Injector createInjector() {
+ return ElasticTestUtils.createInjector(config, testName, container);
+ }
+}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java
new file mode 100644
index 0000000..d3b3d44
--- /dev/null
+++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java
@@ -0,0 +1,57 @@
+// 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.server.query.project.AbstractQueryProjectsTest;
+import com.google.gerrit.testing.ConfigSuite;
+import com.google.inject.Injector;
+import org.eclipse.jgit.lib.Config;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public class ElasticV7QueryProjectsTest extends AbstractQueryProjectsTest {
+ @ConfigSuite.Default
+ public static Config defaultConfig() {
+ return ElasticTestUtils.createConfig();
+ }
+
+ private static ElasticContainer container;
+
+ @BeforeClass
+ public static void startIndexService() {
+ if (container == null) {
+ // Only start Elasticsearch once
+ container = ElasticContainer.createAndStart(ElasticVersion.V7_8);
+ }
+ }
+
+ @AfterClass
+ public static void stopElasticsearchServer() {
+ if (container != null) {
+ container.stop();
+ }
+ }
+
+ @Override
+ protected void initAfterLifecycleStart() throws Exception {
+ super.initAfterLifecycleStart();
+ ElasticTestUtils.createAllIndexes(injector);
+ }
+
+ @Override
+ protected Injector createInjector() {
+ return ElasticTestUtils.createInjector(config, testName, container);
+ }
+}