Merge branch 'stable-3.8' into stable-3.9 * stable-3.8: test: Simplify SSL setup Add 8.9.* to supported versions test: Always enable SSL for ES containers Bump testcontainers to 1.19.7 Remove unused build var test: Add assert for closing indexes test: Use the 'withTag' helper to get DockerImageName Include an 'Accept' header for Content-Type in requests Add a debug log while insert/replace change index operation Release-Notes: skip Change-Id: Ib1d2a6507aaa653fabbadd78c575db3e0534598b
diff --git a/BUILD b/BUILD index 94ce436..858c03a 100644 --- a/BUILD +++ b/BUILD
@@ -53,8 +53,6 @@ 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", @@ -64,6 +62,20 @@ SUFFIX = "sTest.java" +ABSTRACT_ELASTICSEARCH_TESTS = {i: "Elastic*Query" + i.capitalize() + SUFFIX for i in TYPES} + +[java_library( + name = "abstract_elasticsearch_query_%ss_test" % name, + testonly = True, + srcs = glob(["src/test/java/com/google/gerrit/elasticsearch/" + src]), + visibility = ["//visibility:public"], + deps = ELASTICSEARCH_DEPS + PLUGIN_TEST_DEPS + [ + QUERY_TESTS_DEP % name, + ":elasticsearch_test_utils", + ":index-elasticsearch__plugin", + ], +) for name, src in ABSTRACT_ELASTICSEARCH_TESTS.items()] + ELASTICSEARCH_TESTS_V7 = {i: "ElasticV7Query" + i.capitalize() + SUFFIX for i in TYPES} [junit_tests( @@ -79,9 +91,29 @@ QUERY_TESTS_DEP % name, ":elasticsearch_test_utils", ":index-elasticsearch__plugin", + ":abstract_elasticsearch_query_%ss_test" % name, ], ) for name, src in ELASTICSEARCH_TESTS_V7.items()] +ELASTICSEARCH_TESTS_V8 = {i: "ElasticV8Query" + i.capitalize() + SUFFIX for i in TYPES} + +[junit_tests( + name = "elasticsearch_query_%ss_test_V8" % name, + size = "enormous", + srcs = ["src/test/java/com/google/gerrit/elasticsearch/" + src], + tags = [ + "docker", + "elastic", + "exclusive", + ], + deps = ELASTICSEARCH_DEPS + PLUGIN_TEST_DEPS + [ + QUERY_TESTS_DEP % name, + ":elasticsearch_test_utils", + ":index-elasticsearch__plugin", + ":abstract_elasticsearch_query_%ss_test" % name, + ], +) for name, src in ELASTICSEARCH_TESTS_V8.items()] + junit_tests( name = "index-elasticsearch_tests", size = "small",
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl index 7ab2c29..72549a8 100644 --- a/external_plugin_deps.bzl +++ b/external_plugin_deps.bzl
@@ -8,19 +8,19 @@ ) # Ensure artifacts compatibility by selecting them from the Bill Of Materials - # https://search.maven.org/artifact/org.testcontainers/testcontainers/1.17.5/pom - TESTCONTAINERS_VERSION = "1.17.5" + # https://search.maven.org/artifact/org.testcontainers/testcontainers/1.19.7/pom + TESTCONTAINERS_VERSION = "1.19.7" maven_jar( name = "testcontainers", artifact = "org.testcontainers:testcontainers:" + TESTCONTAINERS_VERSION, - sha1 = "7c5ad975fb789ecd09b1ee5f72907f48a300bc61", + sha1 = "2dd7b1497fc444755582b0efc88636c4d299601f", ) maven_jar( name = "testcontainers-elasticsearch", artifact = "org.testcontainers:elasticsearch:" + TESTCONTAINERS_VERSION, - sha1 = "060895f2fc6640ab4a6c383bc98c5c39ef644fbb", + sha1 = "8cd9f4ae67c9299143eb718541ff544b66273283", ) maven_jar( @@ -29,36 +29,36 @@ sha1 = "92edc22a9ab2f3e17c9bf700aaee377d50e8b530", ) - DOCKER_JAVA_VERS = "3.2.13" + DOCKER_JAVA_VERS = "3.3.6" maven_jar( name = "docker-java-api", artifact = "com.github.docker-java:docker-java-api:" + DOCKER_JAVA_VERS, - sha1 = "5817ef8f770cb7e740d590090bf352df9491f3c1", + sha1 = "8e152880bfe595c81a25501e21a6d7b1d4df97be", ) maven_jar( name = "docker-java-transport", artifact = "com.github.docker-java:docker-java-transport:" + DOCKER_JAVA_VERS, - sha1 = "e9d308d1822181a9d48c99739f5eca014ec89199", + sha1 = "0d536d16a297f9139b833955390a3d581e336e67", ) maven_jar( name = "docker-java-transport-zerodep", artifact = "com.github.docker-java:docker-java-transport-zerodep:" + DOCKER_JAVA_VERS, - sha1 = "4cbc2c09d6c264767a39624066987ed4a152bc68", + sha1 = "c9cde0239ce03376f6dfd0465bd461853af22196", ) # Match version used in docker-java-transport - # https://search.maven.org/artifact/com.github.docker-java/docker-java-transport/3.2.12/pom + # https://search.maven.org/artifact/com.github.docker-java/docker-java-transport/3.3.6/pom maven_jar( name = "jna", - artifact = "net.java.dev.jna:jna:5.8.0", - sha1 = "3551d8d827e54858214107541d3aff9c615cb615", + artifact = "net.java.dev.jna:jna:5.13.0", + sha1 = "1200e7ebeedbe0d10062093f32925a912020e747", ) # Match jackson.version from docker-java - # https://search.maven.org/artifact/com.github.docker-java/docker-java-parent/3.2.12/pom + # https://search.maven.org/artifact/com.github.docker-java/docker-java-parent/3.3.6/pom maven_jar( name = "jackson-annotations", artifact = "com.fasterxml.jackson.core:jackson-annotations:2.10.3",
diff --git a/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java b/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java index 65eaaf0..c022978 100644 --- a/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java +++ b/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
@@ -284,9 +284,9 @@ protected boolean hasErrors(Response response) { try { - String contentType = response.getEntity().getContentType().getValue(); + ContentType contentType = ContentType.get(response.getEntity()); Preconditions.checkState( - contentType.equals(ContentType.APPLICATION_JSON.toString()), + contentType.toString().equalsIgnoreCase(ContentType.APPLICATION_JSON.toString()), String.format("Expected %s, but was: %s", ContentType.APPLICATION_JSON, contentType)); String responseStr = EntityUtils.toString(response.getEntity()); JsonObject responseJson = (JsonObject) new JsonParser().parse(responseStr);
diff --git a/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java b/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java index 1cc00cd..ec12a7a 100644 --- a/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java +++ b/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
@@ -17,6 +17,7 @@ import static java.util.Objects.requireNonNull; import com.google.common.collect.ImmutableSet; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.elasticsearch.ElasticMapping.Mapping; import com.google.gerrit.elasticsearch.bulk.BulkRequest; import com.google.gerrit.elasticsearch.bulk.IndexRequest; @@ -52,6 +53,8 @@ /** Secondary index implementation using Elasticsearch. */ class ElasticChangeIndex extends AbstractElasticIndex<Change.Id, ChangeData> implements ChangeIndex { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + static class ChangeMapping { final Mapping changes; final Mapping openChanges; @@ -96,6 +99,17 @@ BulkRequest bulk = new IndexRequest(getId(cd), indexName).add(new UpdateRequest<>(schema, cd, skipFields)); + if (logger.atFine().isEnabled()) { + String metaRevision = null; + try { + metaRevision = cd.metaRevisionOrThrow().name(); + } catch (Exception ignored) { + } + logger.atFine().log( + "Indexing: change: %s, status: %s, meta revision: %s", + cd.change().currentPatchSetId(), cd.change().getStatus(), metaRevision); + } + String uri = getURI(BULK); Response response = postRequestWithRefreshParam(uri, bulk); int statusCode = response.getStatusLine().getStatusCode();
diff --git a/src/main/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java b/src/main/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java index b41f365..9caa14d 100644 --- a/src/main/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java +++ b/src/main/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java
@@ -22,14 +22,17 @@ import com.google.inject.Provider; import com.google.inject.Singleton; import java.io.IOException; +import org.apache.http.Header; import org.apache.http.HttpStatus; import org.apache.http.StatusLine; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig; +import org.apache.http.entity.ContentType; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.apache.http.message.BasicHeader; import org.elasticsearch.client.Request; import org.elasticsearch.client.Response; import org.elasticsearch.client.RestClient; @@ -129,6 +132,8 @@ private RestClient build() { RestClientBuilder builder = RestClient.builder(cfg.getHosts()); + builder.setDefaultHeaders( + new Header[] {new BasicHeader("Accept", ContentType.APPLICATION_JSON.toString())}); setConfiguredTimeouts(builder); setConfiguredCredentialsIfAny(builder); return builder.build(); @@ -150,8 +155,13 @@ credentialsProvider.setCredentials( AuthScope.ANY, new UsernamePasswordCredentials(username, password)); builder.setHttpClientConfigCallback( - (HttpAsyncClientBuilder httpClientBuilder) -> - httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)); + (HttpAsyncClientBuilder httpClientBuilder) -> { + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + configureHttpClientBuilder(httpClientBuilder); + return httpClientBuilder; + }); } } + + protected void configureHttpClientBuilder(HttpAsyncClientBuilder httpClientBuilder) {} }
diff --git a/src/main/java/com/google/gerrit/elasticsearch/ElasticVersion.java b/src/main/java/com/google/gerrit/elasticsearch/ElasticVersion.java index dffdf3e..2fad786 100644 --- a/src/main/java/com/google/gerrit/elasticsearch/ElasticVersion.java +++ b/src/main/java/com/google/gerrit/elasticsearch/ElasticVersion.java
@@ -18,7 +18,8 @@ import java.util.regex.Pattern; public enum ElasticVersion { - V7_16("7.16.*"); + V7_16("7.16.*"), + V8_9("8.9.*"); private final String version; private final Pattern pattern;
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryAccountsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryAccountsTest.java new file mode 100644 index 0000000..ce16b2e --- /dev/null +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryAccountsTest.java
@@ -0,0 +1,78 @@ +// Copyright (C) 2024 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.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; + +import com.google.gerrit.exceptions.StorageException; +import com.google.gerrit.server.query.account.AbstractQueryAccountsTest; +import com.google.gerrit.testing.ConfigSuite; +import com.google.inject.Injector; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.eclipse.jgit.lib.Config; +import org.junit.AfterClass; +import org.junit.Test; + +public abstract class ElasticAbstractQueryAccountsTest extends AbstractQueryAccountsTest { + @ConfigSuite.Default + public static Config defaultConfig() { + return ElasticTestUtils.createConfig(); + } + + @ConfigSuite.Config + public static Config searchAfterPaginationType() { + Config config = defaultConfig(); + config.setString("index", null, "paginationType", "SEARCH_AFTER"); + return config; + } + + private static ElasticContainer container; + private static CloseableHttpAsyncClient client; + + protected static void startIndexService(ElasticVersion elasticVersion) { + container = ElasticContainer.createAndStart(elasticVersion); + client = ElasticTestUtils.createHttpAsyncClient(container); + client.start(); + } + + @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); + } + + @Test + public void testErrorResponseFromAccountIndex() throws Exception { + gApi.accounts().self().index(); + + ElasticTestUtils.closeIndex(client, container, testName); + StorageException thrown = + assertThrows(StorageException.class, () -> gApi.accounts().self().index()); + assertThat(thrown).hasMessageThat().contains("Failed to replace account"); + } +}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryChangesTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryChangesTest.java new file mode 100644 index 0000000..d5c60ad --- /dev/null +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryChangesTest.java
@@ -0,0 +1,96 @@ +// Copyright (C) 2024 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.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; + +import com.google.gerrit.entities.Change; +import com.google.gerrit.exceptions.StorageException; +import com.google.gerrit.server.query.change.AbstractQueryChangesTest; +import com.google.gerrit.testing.ConfigSuite; +import com.google.gerrit.testing.GerritTestName; +import com.google.inject.Injector; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.Repository; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Rule; +import org.junit.Test; + +public abstract class ElasticAbstractQueryChangesTest extends AbstractQueryChangesTest { + @ConfigSuite.Default + public static Config defaultConfig() { + return ElasticTestUtils.createConfig(); + } + + @ConfigSuite.Config + public static Config searchAfterPaginationType() { + Config config = defaultConfig(); + config.setString("index", null, "paginationType", "SEARCH_AFTER"); + return config; + } + + private static ElasticContainer container; + private static CloseableHttpAsyncClient client; + + protected static void startIndexService(ElasticVersion elasticVersion) { + container = ElasticContainer.createAndStart(elasticVersion); + client = ElasticTestUtils.createHttpAsyncClient(container); + 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). + ElasticTestUtils.closeIndex(client, container, testName); + } + + @Override + protected void initAfterLifecycleStart() throws Exception { + super.initAfterLifecycleStart(); + ElasticTestUtils.createAllIndexes(injector); + } + + @Override + protected Injector createInjector() { + return ElasticTestUtils.createInjector(config, testName, container); + } + + @Test + public void testErrorResponseFromChangeIndex() throws Exception { + String repository = "repo"; + TestRepository<Repository> repo = createAndOpenProject(repository); + Change c = insert(repository, newChangeWithStatus(repo, Change.Status.NEW)); + gApi.changes().id(c.getChangeId()).index(); + + ElasticTestUtils.closeIndex(client, container, testName); + StorageException thrown = + assertThrows(StorageException.class, () -> gApi.changes().id(c.getChangeId()).index()); + assertThat(thrown).hasMessageThat().contains("Failed to reindex change"); + } +}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryGroupsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryGroupsTest.java new file mode 100644 index 0000000..f449bca --- /dev/null +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryGroupsTest.java
@@ -0,0 +1,79 @@ +// Copyright (C) 2024 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.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; + +import com.google.gerrit.exceptions.StorageException; +import com.google.gerrit.extensions.api.groups.GroupApi; +import com.google.gerrit.server.query.group.AbstractQueryGroupsTest; +import com.google.gerrit.testing.ConfigSuite; +import com.google.inject.Injector; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.eclipse.jgit.lib.Config; +import org.junit.AfterClass; +import org.junit.Test; + +public abstract class ElasticAbstractQueryGroupsTest extends AbstractQueryGroupsTest { + @ConfigSuite.Default + public static Config defaultConfig() { + return ElasticTestUtils.createConfig(); + } + + @ConfigSuite.Config + public static Config searchAfterPaginationType() { + Config config = defaultConfig(); + config.setString("index", null, "paginationType", "SEARCH_AFTER"); + return config; + } + + private static ElasticContainer container; + private static CloseableHttpAsyncClient client; + + protected static void startIndexService(ElasticVersion elasticVersion) { + container = ElasticContainer.createAndStart(elasticVersion); + client = ElasticTestUtils.createHttpAsyncClient(container); + client.start(); + } + + @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); + } + + @Test + public void testErrorResponseFromGroupIndex() throws Exception { + GroupApi group = gApi.groups().create("test"); + group.index(); + + ElasticTestUtils.closeIndex(client, container, testName); + StorageException thrown = assertThrows(StorageException.class, () -> group.index()); + assertThat(thrown).hasMessageThat().contains("Failed to replace group"); + } +}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryProjectsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryProjectsTest.java new file mode 100644 index 0000000..5f4847c --- /dev/null +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticAbstractQueryProjectsTest.java
@@ -0,0 +1,79 @@ +// Copyright (C) 2024 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.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; + +import com.google.gerrit.exceptions.StorageException; +import com.google.gerrit.extensions.api.projects.ProjectApi; +import com.google.gerrit.server.query.project.AbstractQueryProjectsTest; +import com.google.gerrit.testing.ConfigSuite; +import com.google.inject.Injector; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.eclipse.jgit.lib.Config; +import org.junit.AfterClass; +import org.junit.Test; + +public abstract class ElasticAbstractQueryProjectsTest extends AbstractQueryProjectsTest { + @ConfigSuite.Default + public static Config defaultConfig() { + return ElasticTestUtils.createConfig(); + } + + @ConfigSuite.Config + public static Config searchAfterPaginationType() { + Config config = defaultConfig(); + config.setString("index", null, "paginationType", "SEARCH_AFTER"); + return config; + } + + private static ElasticContainer container; + private static CloseableHttpAsyncClient client; + + protected static void startIndexService(ElasticVersion elasticVersion) { + container = ElasticContainer.createAndStart(elasticVersion); + client = ElasticTestUtils.createHttpAsyncClient(container); + client.start(); + } + + @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); + } + + @Test + public void testErrorResponseFromProjectIndex() throws Exception { + ProjectApi project = gApi.projects().create("test"); + project.index(false); + + ElasticTestUtils.closeIndex(client, container, testName); + StorageException thrown = assertThrows(StorageException.class, () -> project.index(false)); + assertThat(thrown).hasMessageThat().contains("Failed to replace project"); + } +}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java index 86b1bac..a65e57c 100644 --- a/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticContainer.java
@@ -15,11 +15,13 @@ package com.google.gerrit.elasticsearch; import com.google.common.flogger.FluentLogger; +import java.nio.file.Path; import org.apache.http.HttpHost; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.elasticsearch.ElasticsearchContainer; +import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.DockerImageName; /* Helper class for running ES integration tests in docker container */ @@ -30,6 +32,51 @@ public static ElasticContainer createAndStart(ElasticVersion version) { ElasticContainer container = new ElasticContainer(version); try { + Path certs = Path.of("/usr/share/elasticsearch/config/certs"); + String customizedCertPath = certs.resolve("http_ca_customized.crt").toString(); + String sslKeyPath = certs.resolve("elasticsearch.key").toString(); + String sslCrtPath = certs.resolve("elasticsearch.crt").toString(); + container = + (ElasticContainer) + container + .withPassword(ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD) + .withEnv("xpack.security.enabled", "true") + .withEnv("xpack.security.http.ssl.enabled", "true") + .withEnv("xpack.security.http.ssl.key", sslKeyPath) + .withEnv("xpack.security.http.ssl.certificate", sslCrtPath) + .withEnv("xpack.security.http.ssl.certificate_authorities", customizedCertPath) + // Create our own cert so that the gerrit-ci docker hostname + // matches the certificate subject. Otherwise we get an error like: + // Host name '10.0.1.1' does not match the certificate subject provided by the + // peer (CN=4932da9bab1d) + .withCopyToContainer( + Transferable.of( + "#!/bin/bash\n" + + "mkdir -p " + + certs.toString() + + ";" + + "openssl req -x509 -newkey rsa:4096 -keyout " + + sslKeyPath + + " -out " + + sslCrtPath + + " -days 365 -nodes -subj \"/CN=" + + container.getHost() + + "\";" + + "openssl x509 -outform der -in " + + sslCrtPath + + " -out " + + customizedCertPath + + "; chown -R elasticsearch " + + certs.toString(), + 555), + "/usr/share/elasticsearch/generate-certs.sh") + // because we need to generate the certificates before Elasticsearch starts, the + // entry command has to be adjusted accordingly + .withCommand( + "sh", + "-c", + "/usr/share/elasticsearch/generate-certs.sh && /usr/local/bin/docker-entrypoint.sh") + .withCertPath(customizedCertPath); container.start(); } catch (ContainerLaunchException e) { logger.atSevere().log( @@ -39,16 +86,20 @@ return container; } - private static String getImageName(ElasticVersion version) { + private static DockerImageName getImageName(ElasticVersion version) { + DockerImageName image = DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch"); switch (version) { case V7_16: - return "docker.elastic.co/elasticsearch/elasticsearch:7.16.2"; + return image.withTag("7.16.2"); + case V8_9: + return image.withTag("8.9.2"); } throw new IllegalStateException("No tests for version: " + version.name()); } private ElasticContainer(ElasticVersion version) { - super(DockerImageName.parse(getImageName(version))); + super(getImageName(version)); + withEnv("action.destructive_requires_name", "false"); } @Override @@ -57,6 +108,7 @@ } public HttpHost getHttpHost() { - return new HttpHost(getContainerIpAddress(), getMappedPort(ELASTICSEARCH_DEFAULT_PORT)); + String protocol = caCertAsBytes().isPresent() ? "https://" : "http://"; + return HttpHost.create(protocol + getHttpHostAddress()); } }
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticContainerRestClientProvider.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticContainerRestClientProvider.java new file mode 100644 index 0000000..5b8ad40 --- /dev/null +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticContainerRestClientProvider.java
@@ -0,0 +1,37 @@ +// Copyright (C) 2024 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.inject.Inject; +import com.google.inject.Singleton; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; + +@Singleton +class ElasticContainerRestClientProvider extends ElasticRestClientProvider { + private final ElasticContainer container; + + @Inject + ElasticContainerRestClientProvider(ElasticConfiguration cfg, ElasticContainer container) { + super(cfg); + this.container = container; + } + + @Override + protected void configureHttpClientBuilder(HttpAsyncClientBuilder httpClientBuilder) { + if (container.caCertAsBytes().isPresent()) { + httpClientBuilder.setSSLContext(container.createSslContextFromCa()); + } + } +}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java index f5ba9db..a280ba5 100644 --- a/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java
@@ -14,32 +14,49 @@ package com.google.gerrit.elasticsearch; +import static com.google.common.truth.Truth.assertWithMessage; import static java.util.concurrent.TimeUnit.MINUTES; +import static org.testcontainers.elasticsearch.ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD; 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.AbstractModule; 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.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.apache.http.impl.nio.client.HttpAsyncClients; +import org.apache.http.util.EntityUtils; import org.eclipse.jgit.lib.Config; public final class ElasticTestUtils { + private static final String ELASTIC_USERNAME = "elastic"; + private static final String ELASTIC_PASSWORD = ELASTICSEARCH_DEFAULT_PASSWORD; + 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, "server", container.getHttpHost().toURI()); config.setString("elasticsearch", null, "prefix", prefix); config.setInt("index", null, "maxLimit", 10000); + if (container.caCertAsBytes().isPresent()) { + config.setString("elasticsearch", null, "username", ELASTIC_USERNAME); + config.setString("elasticsearch", null, "password", ELASTIC_PASSWORD); + } } public static void createAllIndexes(Injector injector) { @@ -76,6 +93,20 @@ "com.google.gerrit.elasticsearch.ElasticIndexModule"); } + public static class ElasticContainerTestModule extends AbstractModule { + private final ElasticContainer container; + + ElasticContainerTestModule(ElasticContainer container) { + this.container = container; + } + + @Override + protected void configure() { + bind(ElasticRestClientProvider.class).to(ElasticContainerRestClientProvider.class); + bind(ElasticContainer.class).toInstance(container); + } + } + public static Injector createInjector( Config config, GerritTestName testName, ElasticContainer container) { Config elasticsearchConfig = new Config(config); @@ -83,23 +114,42 @@ InMemoryModule.setDefaults(elasticsearchConfig); String indicesPrefix = testName.getSanitizedMethodName(); ElasticTestUtils.configure(elasticsearchConfig, container, indicesPrefix); - return Guice.createInjector(new InMemoryModule(elasticsearchConfig)); + return Guice.createInjector( + new ElasticContainerTestModule(container), new InMemoryModule(elasticsearchConfig)); + } + + public static CloseableHttpAsyncClient createHttpAsyncClient(ElasticContainer container) { + HttpAsyncClientBuilder builder = HttpAsyncClients.custom(); + if (container.caCertAsBytes().isPresent()) { + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials( + AuthScope.ANY, new UsernamePasswordCredentials(ELASTIC_USERNAME, ELASTIC_PASSWORD)); + builder + .setSSLContext(container.createSslContextFromCa()) + .setDefaultCredentialsProvider(credentialsProvider); + } + return builder.build(); } public static void closeIndex( CloseableHttpAsyncClient client, ElasticContainer container, GerritTestName testName) throws Exception { - 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); + HttpResponse response = + client + .execute( + new HttpPost( + String.format( + "%s/%s*/_close", + container.getHttpHost().toURI(), testName.getSanitizedMethodName())), + HttpClientContext.create(), + null) + .get(5, MINUTES); + int statusCode = response.getStatusLine().getStatusCode(); + assertWithMessage( + "response status code should be %s, but was %s. Full response was %s", + HttpStatus.SC_OK, statusCode, EntityUtils.toString(response.getEntity())) + .that(statusCode) + .isEqualTo(HttpStatus.SC_OK); } private ElasticTestUtils() {
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java index 7f6a585..a9c8361 100644 --- a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java
@@ -14,68 +14,11 @@ package com.google.gerrit.elasticsearch; -import static com.google.common.truth.Truth.assertThat; -import static com.google.gerrit.testing.GerritJUnit.assertThrows; - -import com.google.gerrit.exceptions.StorageException; -import com.google.gerrit.server.query.account.AbstractQueryAccountsTest; -import com.google.gerrit.testing.ConfigSuite; -import com.google.inject.Injector; -import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; -import org.apache.http.impl.nio.client.HttpAsyncClients; -import org.eclipse.jgit.lib.Config; -import org.junit.AfterClass; import org.junit.BeforeClass; -import org.junit.Test; -public class ElasticV7QueryAccountsTest extends AbstractQueryAccountsTest { - @ConfigSuite.Default - public static Config defaultConfig() { - return ElasticTestUtils.createConfig(); - } - - @ConfigSuite.Config - public static Config searchAfterPaginationType() { - Config config = defaultConfig(); - config.setString("index", null, "paginationType", "SEARCH_AFTER"); - return config; - } - - private static ElasticContainer container; - private static CloseableHttpAsyncClient client; - +public class ElasticV7QueryAccountsTest extends ElasticAbstractQueryAccountsTest { @BeforeClass public static void startIndexService() { - container = ElasticContainer.createAndStart(ElasticVersion.V7_16); - client = HttpAsyncClients.createDefault(); - client.start(); - } - - @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); - } - - @Test - public void testErrorResponseFromAccountIndex() throws Exception { - gApi.accounts().self().index(); - - ElasticTestUtils.closeIndex(client, container, testName); - StorageException thrown = - assertThrows(StorageException.class, () -> gApi.accounts().self().index()); - assertThat(thrown).hasMessageThat().contains("Failed to replace account"); + startIndexService(ElasticVersion.V7_16); } }
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java index 7151e70..9961987 100644 --- a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java
@@ -14,86 +14,11 @@ package com.google.gerrit.elasticsearch; -import static com.google.common.truth.Truth.assertThat; -import static com.google.gerrit.testing.GerritJUnit.assertThrows; - -import com.google.gerrit.entities.Change; -import com.google.gerrit.exceptions.StorageException; -import com.google.gerrit.server.query.change.AbstractQueryChangesTest; -import com.google.gerrit.testing.ConfigSuite; -import com.google.gerrit.testing.GerritTestName; -import com.google.inject.Injector; -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.eclipse.jgit.lib.Repository; -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(); - } - - @ConfigSuite.Config - public static Config searchAfterPaginationType() { - Config config = defaultConfig(); - config.setString("index", null, "paginationType", "SEARCH_AFTER"); - return config; - } - - private static ElasticContainer container; - private static CloseableHttpAsyncClient client; - +public class ElasticV7QueryChangesTest extends ElasticAbstractQueryChangesTest { @BeforeClass public static void startIndexService() { - container = ElasticContainer.createAndStart(ElasticVersion.V7_16); - 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). - ElasticTestUtils.closeIndex(client, container, testName); - } - - @Override - protected void initAfterLifecycleStart() throws Exception { - super.initAfterLifecycleStart(); - ElasticTestUtils.createAllIndexes(injector); - } - - @Override - protected Injector createInjector() { - return ElasticTestUtils.createInjector(config, testName, container); - } - - @Test - public void testErrorResponseFromChangeIndex() throws Exception { - String repository = "repo"; - TestRepository<Repository> repo = createAndOpenProject(repository); - Change c = insert(repository, newChangeWithStatus(repo, Change.Status.NEW)); - gApi.changes().id(c.getChangeId()).index(); - - ElasticTestUtils.closeIndex(client, container, testName); - StorageException thrown = - assertThrows(StorageException.class, () -> gApi.changes().id(c.getChangeId()).index()); - assertThat(thrown).hasMessageThat().contains("Failed to reindex change"); + startIndexService(ElasticVersion.V7_16); } }
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java index 271ee19..9a48181 100644 --- a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java
@@ -14,69 +14,11 @@ package com.google.gerrit.elasticsearch; -import static com.google.common.truth.Truth.assertThat; -import static com.google.gerrit.testing.GerritJUnit.assertThrows; - -import com.google.gerrit.exceptions.StorageException; -import com.google.gerrit.extensions.api.groups.GroupApi; -import com.google.gerrit.server.query.group.AbstractQueryGroupsTest; -import com.google.gerrit.testing.ConfigSuite; -import com.google.inject.Injector; -import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; -import org.apache.http.impl.nio.client.HttpAsyncClients; -import org.eclipse.jgit.lib.Config; -import org.junit.AfterClass; import org.junit.BeforeClass; -import org.junit.Test; -public class ElasticV7QueryGroupsTest extends AbstractQueryGroupsTest { - @ConfigSuite.Default - public static Config defaultConfig() { - return ElasticTestUtils.createConfig(); - } - - @ConfigSuite.Config - public static Config searchAfterPaginationType() { - Config config = defaultConfig(); - config.setString("index", null, "paginationType", "SEARCH_AFTER"); - return config; - } - - private static ElasticContainer container; - private static CloseableHttpAsyncClient client; - +public class ElasticV7QueryGroupsTest extends ElasticAbstractQueryGroupsTest { @BeforeClass public static void startIndexService() { - container = ElasticContainer.createAndStart(ElasticVersion.V7_16); - client = HttpAsyncClients.createDefault(); - client.start(); - } - - @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); - } - - @Test - public void testErrorResponseFromGroupIndex() throws Exception { - GroupApi group = gApi.groups().create("test"); - group.index(); - - ElasticTestUtils.closeIndex(client, container, testName); - StorageException thrown = assertThrows(StorageException.class, () -> group.index()); - assertThat(thrown).hasMessageThat().contains("Failed to replace group"); + startIndexService(ElasticVersion.V7_16); } }
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java index 38eef22..f37bbff 100644 --- a/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java
@@ -14,69 +14,11 @@ package com.google.gerrit.elasticsearch; -import static com.google.common.truth.Truth.assertThat; -import static com.google.gerrit.testing.GerritJUnit.assertThrows; - -import com.google.gerrit.exceptions.StorageException; -import com.google.gerrit.extensions.api.projects.ProjectApi; -import com.google.gerrit.server.query.project.AbstractQueryProjectsTest; -import com.google.gerrit.testing.ConfigSuite; -import com.google.inject.Injector; -import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; -import org.apache.http.impl.nio.client.HttpAsyncClients; -import org.eclipse.jgit.lib.Config; -import org.junit.AfterClass; import org.junit.BeforeClass; -import org.junit.Test; -public class ElasticV7QueryProjectsTest extends AbstractQueryProjectsTest { - @ConfigSuite.Default - public static Config defaultConfig() { - return ElasticTestUtils.createConfig(); - } - - @ConfigSuite.Config - public static Config searchAfterPaginationType() { - Config config = defaultConfig(); - config.setString("index", null, "paginationType", "SEARCH_AFTER"); - return config; - } - - private static ElasticContainer container; - private static CloseableHttpAsyncClient client; - +public class ElasticV7QueryProjectsTest extends ElasticAbstractQueryProjectsTest { @BeforeClass public static void startIndexService() { - container = ElasticContainer.createAndStart(ElasticVersion.V7_16); - client = HttpAsyncClients.createDefault(); - client.start(); - } - - @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); - } - - @Test - public void testErrorResponseFromProjectIndex() throws Exception { - ProjectApi project = gApi.projects().create("test"); - project.index(false); - - ElasticTestUtils.closeIndex(client, container, testName); - StorageException thrown = assertThrows(StorageException.class, () -> project.index(false)); - assertThat(thrown).hasMessageThat().contains("Failed to replace project"); + startIndexService(ElasticVersion.V7_16); } }
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryAccountsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryAccountsTest.java new file mode 100644 index 0000000..b1ef2e5 --- /dev/null +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryAccountsTest.java
@@ -0,0 +1,24 @@ +// Copyright (C) 2024 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.junit.BeforeClass; + +public class ElasticV8QueryAccountsTest extends ElasticAbstractQueryAccountsTest { + @BeforeClass + public static void startIndexService() { + startIndexService(ElasticVersion.V8_9); + } +}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryChangesTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryChangesTest.java new file mode 100644 index 0000000..a9a220d --- /dev/null +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryChangesTest.java
@@ -0,0 +1,24 @@ +// Copyright (C) 2024 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.junit.BeforeClass; + +public class ElasticV8QueryChangesTest extends ElasticAbstractQueryChangesTest { + @BeforeClass + public static void startIndexService() { + startIndexService(ElasticVersion.V8_9); + } +}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryGroupsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryGroupsTest.java new file mode 100644 index 0000000..37a204d --- /dev/null +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryGroupsTest.java
@@ -0,0 +1,24 @@ +// Copyright (C) 2024 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.junit.BeforeClass; + +public class ElasticV8QueryGroupsTest extends ElasticAbstractQueryGroupsTest { + @BeforeClass + public static void startIndexService() { + startIndexService(ElasticVersion.V8_9); + } +}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryProjectsTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryProjectsTest.java new file mode 100644 index 0000000..ace5767 --- /dev/null +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticV8QueryProjectsTest.java
@@ -0,0 +1,24 @@ +// Copyright (C) 2024 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.junit.BeforeClass; + +public class ElasticV8QueryProjectsTest extends ElasticAbstractQueryProjectsTest { + @BeforeClass + public static void startIndexService() { + startIndexService(ElasticVersion.V8_9); + } +}
diff --git a/src/test/java/com/google/gerrit/elasticsearch/ElasticVersionTest.java b/src/test/java/com/google/gerrit/elasticsearch/ElasticVersionTest.java index ea7782b..b750466 100644 --- a/src/test/java/com/google/gerrit/elasticsearch/ElasticVersionTest.java +++ b/src/test/java/com/google/gerrit/elasticsearch/ElasticVersionTest.java
@@ -24,6 +24,10 @@ public void supportedVersion() throws Exception { assertThat(ElasticVersion.forVersion("7.16.0")).isEqualTo(ElasticVersion.V7_16); assertThat(ElasticVersion.forVersion("7.16.1")).isEqualTo(ElasticVersion.V7_16); + + assertThat(ElasticVersion.forVersion("8.9.0")).isEqualTo(ElasticVersion.V8_9); + assertThat(ElasticVersion.forVersion("8.9.1")).isEqualTo(ElasticVersion.V8_9); + assertThat(ElasticVersion.forVersion("8.9.2")).isEqualTo(ElasticVersion.V8_9); } @Test