diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ESRestHighLevelClientTestCase.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ESRestHighLevelClientTestCase.java index af3112ec7e1d8..efe94596b81b6 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/ESRestHighLevelClientTestCase.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ESRestHighLevelClientTestCase.java @@ -75,14 +75,22 @@ protected static RestHighLevelClient highLevelClient() { */ protected static Resp execute(Req request, SyncMethod syncMethod, AsyncMethod asyncMethod) throws IOException { + return execute(request, syncMethod, asyncMethod, RequestOptions.DEFAULT); + } + + /** + * Executes the provided request using either the sync method or its async variant, both provided as functions + */ + protected static Resp execute(Req request, SyncMethod syncMethod, + AsyncMethod asyncMethod, RequestOptions options) throws IOException { if (randomBoolean()) { - return syncMethod.execute(request, RequestOptions.DEFAULT); + return syncMethod.execute(request, options); } else { PlainActionFuture future = PlainActionFuture.newFuture(); - asyncMethod.execute(request, RequestOptions.DEFAULT, future); + asyncMethod.execute(request, options, future); return future.actionGet(); } - } + } /** * Executes the provided request using either the sync method or its async diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java index 1e8e71313e0fd..4115543a56e61 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java @@ -30,10 +30,12 @@ import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksAction; import org.elasticsearch.client.Request; import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RequestOptions.Builder; import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.WarningsHandler; import org.elasticsearch.common.CheckedRunnable; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.PathUtils; @@ -69,12 +71,14 @@ import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.function.Predicate; import static java.util.Collections.sort; @@ -177,6 +181,71 @@ public void initClient() throws IOException { assert hasXPack != null; assert nodeVersions != null; } + + /** + * Helper class to check warnings in REST responses with sensitivity to versions + * used in the target cluster. + */ + public static class VersionSensitiveWarningsHandler implements WarningsHandler { + Set requiredSameVersionClusterWarnings = new HashSet<>(); + Set allowedWarnings = new HashSet<>(); + final Set testNodeVersions; + + public VersionSensitiveWarningsHandler(Set nodeVersions) { + this.testNodeVersions = nodeVersions; + } + + /** + * Adds to the set of warnings that are all required in responses if the cluster + * is formed from nodes all running the exact same version as the client. + * @param requiredWarnings a set of required warnings + */ + public void current(String... requiredWarnings) { + requiredSameVersionClusterWarnings.addAll(Arrays.asList(requiredWarnings)); + } + + /** + * Adds to the set of warnings that are permissible (but not required) when running + * in mixed-version clusters or those that differ in version from the test client. + * @param allowedWarnings optional warnings that will be ignored if received + */ + public void compatible(String... allowedWarnings) { + this.allowedWarnings.addAll(Arrays.asList(allowedWarnings)); + } + + @Override + public boolean warningsShouldFailRequest(List warnings) { + if (isExclusivelyTargetingCurrentVersionCluster()) { + // absolute equality required in expected and actual. + Set actual = new HashSet<>(warnings); + return false == requiredSameVersionClusterWarnings.equals(actual); + } else { + // Some known warnings can safely be ignored + for (String actualWarning : warnings) { + if (false == allowedWarnings.contains(actualWarning) && + false == requiredSameVersionClusterWarnings.contains(actualWarning)) { + return true; + } + } + return false; + } + } + + private boolean isExclusivelyTargetingCurrentVersionCluster() { + assertFalse("Node versions running in the cluster are missing", testNodeVersions.isEmpty()); + return testNodeVersions.size() == 1 && + testNodeVersions.iterator().next().equals(Version.CURRENT); + } + + } + + public static RequestOptions expectVersionSpecificWarnings(Consumer expectationsSetter) { + Builder builder = RequestOptions.DEFAULT.toBuilder(); + VersionSensitiveWarningsHandler warningsHandler = new VersionSensitiveWarningsHandler(nodeVersions); + expectationsSetter.accept(warningsHandler); + builder.setWarningsHandler(warningsHandler); + return builder.build(); + } /** * Construct an HttpHost from the given host and port diff --git a/test/framework/src/test/java/org/elasticsearch/test/rest/VersionSensitiveWarningsHandlerTests.java b/test/framework/src/test/java/org/elasticsearch/test/rest/VersionSensitiveWarningsHandlerTests.java new file mode 100644 index 0000000000000..38fb9ece1133c --- /dev/null +++ b/test/framework/src/test/java/org/elasticsearch/test/rest/VersionSensitiveWarningsHandlerTests.java @@ -0,0 +1,70 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.test.rest; + +import org.elasticsearch.Version; +import org.elasticsearch.client.WarningsHandler; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.rest.ESRestTestCase.VersionSensitiveWarningsHandler; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; + +public class VersionSensitiveWarningsHandlerTests extends ESTestCase { + + public void testSameVersionCluster() throws IOException { + Set nodeVersions= new HashSet<>(); + nodeVersions.add(Version.CURRENT); + WarningsHandler handler = expectVersionSpecificWarnings(nodeVersions, (v)->{ + v.current("expectedCurrent1"); + }); + assertFalse(handler.warningsShouldFailRequest(Arrays.asList("expectedCurrent1"))); + assertTrue(handler.warningsShouldFailRequest(Arrays.asList("expectedCurrent1", "unexpected"))); + assertTrue(handler.warningsShouldFailRequest(Collections.emptyList())); + + } + public void testMixedVersionCluster() throws IOException { + Set nodeVersions= new HashSet<>(); + nodeVersions.add(Version.CURRENT); + nodeVersions.add(Version.CURRENT.minimumIndexCompatibilityVersion()); + WarningsHandler handler = expectVersionSpecificWarnings(nodeVersions, (v)->{ + v.current("expectedCurrent1"); + v.compatible("Expected legacy warning"); + }); + assertFalse(handler.warningsShouldFailRequest(Arrays.asList("expectedCurrent1"))); + assertFalse(handler.warningsShouldFailRequest(Arrays.asList("Expected legacy warning"))); + assertFalse(handler.warningsShouldFailRequest(Arrays.asList("expectedCurrent1", "Expected legacy warning"))); + assertTrue(handler.warningsShouldFailRequest(Arrays.asList("expectedCurrent1", "Unexpected legacy warning"))); + assertTrue(handler.warningsShouldFailRequest(Arrays.asList("Unexpected legacy warning"))); + assertFalse(handler.warningsShouldFailRequest(Collections.emptyList())); + } + + private static WarningsHandler expectVersionSpecificWarnings(Set nodeVersions, + Consumer expectationsSetter) { + //Based on EsRestTestCase.expectVersionSpecificWarnings helper method but without ESRestTestCase dependency + VersionSensitiveWarningsHandler warningsHandler = new VersionSensitiveWarningsHandler(nodeVersions); + expectationsSetter.accept(warningsHandler); + return warningsHandler; + } +}