Merge branch 'master' into log4j2

* master:
  Increase visibility of deprecation logger
  Skip transport client plugin installed on JDK 9
  Explicitly disable Netty key set replacement
  percolator: Fail indexing percolator queries containing either a has_child or has_parent query.
  Make it possible for Ingest Processors to access AnalysisRegistry
  Allow RestClient to send array-based headers
  Silence rest util tests until the bogusness can be simplified
  Remove unknown HttpContext-based test as it fails unpredictably on different JVMs
  Tests: Improve rest suite names and generated test names for docs tests
  Add support for a RestClient base path
This commit is contained in:
Jason Tedor 2016-08-31 10:59:27 -04:00
commit e166459bbe
22 changed files with 386 additions and 147 deletions

View File

@ -117,7 +117,7 @@ public class RestTestsFromSnippetsTask extends SnippetsTask {
if (false == test.continued) {
current.println('---')
current.println("\"$test.start\":")
current.println("\"line_$test.start\":")
}
if (test.skipTest) {
current.println(" - skip:")

View File

@ -89,17 +89,19 @@ public class RestClient implements Closeable {
//we don't rely on default headers supported by HttpAsyncClient as those cannot be replaced
private final Header[] defaultHeaders;
private final long maxRetryTimeoutMillis;
private final String pathPrefix;
private final AtomicInteger lastHostIndex = new AtomicInteger(0);
private volatile Set<HttpHost> hosts;
private final ConcurrentMap<HttpHost, DeadHostState> blacklist = new ConcurrentHashMap<>();
private final FailureListener failureListener;
RestClient(CloseableHttpAsyncClient client, long maxRetryTimeoutMillis, Header[] defaultHeaders,
HttpHost[] hosts, FailureListener failureListener) {
HttpHost[] hosts, String pathPrefix, FailureListener failureListener) {
this.client = client;
this.maxRetryTimeoutMillis = maxRetryTimeoutMillis;
this.defaultHeaders = defaultHeaders;
this.failureListener = failureListener;
this.pathPrefix = pathPrefix;
setHosts(hosts);
}
@ -280,7 +282,7 @@ public class RestClient implements Closeable {
public void performRequestAsync(String method, String endpoint, Map<String, String> params,
HttpEntity entity, HttpAsyncResponseConsumer<HttpResponse> responseConsumer,
ResponseListener responseListener, Header... headers) {
URI uri = buildUri(endpoint, params);
URI uri = buildUri(pathPrefix, endpoint, params);
HttpRequestBase request = createHttpRequest(method, uri, entity);
setHeaders(request, headers);
FailureTrackingResponseListener failureTrackingResponseListener = new FailureTrackingResponseListener(responseListener);
@ -360,12 +362,17 @@ public class RestClient implements Closeable {
private void setHeaders(HttpRequest httpRequest, Header[] requestHeaders) {
Objects.requireNonNull(requestHeaders, "request headers must not be null");
for (Header defaultHeader : defaultHeaders) {
httpRequest.setHeader(defaultHeader);
}
// request headers override default headers, so we don't add default headers if they exist as request headers
final Set<String> requestNames = new HashSet<>(requestHeaders.length);
for (Header requestHeader : requestHeaders) {
Objects.requireNonNull(requestHeader, "request header must not be null");
httpRequest.setHeader(requestHeader);
httpRequest.addHeader(requestHeader);
requestNames.add(requestHeader.getName());
}
for (Header defaultHeader : defaultHeaders) {
if (requestNames.contains(defaultHeader.getName()) == false) {
httpRequest.addHeader(defaultHeader);
}
}
}
@ -501,10 +508,21 @@ public class RestClient implements Closeable {
return httpRequest;
}
private static URI buildUri(String path, Map<String, String> params) {
private static URI buildUri(String pathPrefix, String path, Map<String, String> params) {
Objects.requireNonNull(params, "params must not be null");
try {
URIBuilder uriBuilder = new URIBuilder(path);
String fullPath;
if (pathPrefix != null) {
if (path.startsWith("/")) {
fullPath = pathPrefix + path;
} else {
fullPath = pathPrefix + "/" + path;
}
} else {
fullPath = path;
}
URIBuilder uriBuilder = new URIBuilder(fullPath);
for (Map.Entry<String, String> param : params.entrySet()) {
uriBuilder.addParameter(param.getKey(), param.getValue());
}

View File

@ -51,12 +51,17 @@ public final class RestClientBuilder {
private RestClient.FailureListener failureListener;
private HttpClientConfigCallback httpClientConfigCallback;
private RequestConfigCallback requestConfigCallback;
private String pathPrefix;
/**
* Creates a new builder instance and sets the hosts that the client will send requests to.
*
* @throws NullPointerException if {@code hosts} or any host is {@code null}.
* @throws IllegalArgumentException if {@code hosts} is empty.
*/
RestClientBuilder(HttpHost... hosts) {
if (hosts == null || hosts.length == 0) {
Objects.requireNonNull(hosts, "hosts must not be null");
if (hosts.length == 0) {
throw new IllegalArgumentException("no hosts provided");
}
for (HttpHost host : hosts) {
@ -66,7 +71,11 @@ public final class RestClientBuilder {
}
/**
* Sets the default request headers, which will be sent along with each request
* Sets the default request headers, which will be sent along with each request.
* <p>
* Request-time headers will always overwrite any default headers.
*
* @throws NullPointerException if {@code defaultHeaders} or any header is {@code null}.
*/
public RestClientBuilder setDefaultHeaders(Header[] defaultHeaders) {
Objects.requireNonNull(defaultHeaders, "defaultHeaders must not be null");
@ -79,6 +88,8 @@ public final class RestClientBuilder {
/**
* Sets the {@link RestClient.FailureListener} to be notified for each request failure
*
* @throws NullPointerException if {@code failureListener} is {@code null}.
*/
public RestClientBuilder setFailureListener(RestClient.FailureListener failureListener) {
Objects.requireNonNull(failureListener, "failureListener must not be null");
@ -90,7 +101,7 @@ public final class RestClientBuilder {
* Sets the maximum timeout (in milliseconds) to honour in case of multiple retries of the same request.
* {@link #DEFAULT_MAX_RETRY_TIMEOUT_MILLIS} if not specified.
*
* @throws IllegalArgumentException if maxRetryTimeoutMillis is not greater than 0
* @throws IllegalArgumentException if {@code maxRetryTimeoutMillis} is not greater than 0
*/
public RestClientBuilder setMaxRetryTimeoutMillis(int maxRetryTimeoutMillis) {
if (maxRetryTimeoutMillis <= 0) {
@ -102,6 +113,8 @@ public final class RestClientBuilder {
/**
* Sets the {@link HttpClientConfigCallback} to be used to customize http client configuration
*
* @throws NullPointerException if {@code httpClientConfigCallback} is {@code null}.
*/
public RestClientBuilder setHttpClientConfigCallback(HttpClientConfigCallback httpClientConfigCallback) {
Objects.requireNonNull(httpClientConfigCallback, "httpClientConfigCallback must not be null");
@ -111,6 +124,8 @@ public final class RestClientBuilder {
/**
* Sets the {@link RequestConfigCallback} to be used to customize http client configuration
*
* @throws NullPointerException if {@code requestConfigCallback} is {@code null}.
*/
public RestClientBuilder setRequestConfigCallback(RequestConfigCallback requestConfigCallback) {
Objects.requireNonNull(requestConfigCallback, "requestConfigCallback must not be null");
@ -118,6 +133,43 @@ public final class RestClientBuilder {
return this;
}
/**
* Sets the path's prefix for every request used by the http client.
* <p>
* For example, if this is set to "/my/path", then any client request will become <code>"/my/path/" + endpoint</code>.
* <p>
* In essence, every request's {@code endpoint} is prefixed by this {@code pathPrefix}. The path prefix is useful for when
* Elasticsearch is behind a proxy that provides a base path; it is not intended for other purposes and it should not be supplied in
* other scenarios.
*
* @throws NullPointerException if {@code pathPrefix} is {@code null}.
* @throws IllegalArgumentException if {@code pathPrefix} is empty, only '/', or ends with more than one '/'.
*/
public RestClientBuilder setPathPrefix(String pathPrefix) {
Objects.requireNonNull(pathPrefix, "pathPrefix must not be null");
String cleanPathPrefix = pathPrefix;
if (cleanPathPrefix.startsWith("/") == false) {
cleanPathPrefix = "/" + cleanPathPrefix;
}
// best effort to ensure that it looks like "/base/path" rather than "/base/path/"
if (cleanPathPrefix.endsWith("/")) {
cleanPathPrefix = cleanPathPrefix.substring(0, cleanPathPrefix.length() - 1);
if (cleanPathPrefix.endsWith("/")) {
throw new IllegalArgumentException("pathPrefix is malformed. too many trailing slashes: [" + pathPrefix + "]");
}
}
if (cleanPathPrefix.isEmpty() || "/".equals(cleanPathPrefix)) {
throw new IllegalArgumentException("pathPrefix must not be empty or '/': [" + pathPrefix + "]");
}
this.pathPrefix = cleanPathPrefix;
return this;
}
/**
* Creates a new {@link RestClient} based on the provided configuration.
*/
@ -126,7 +178,7 @@ public final class RestClientBuilder {
failureListener = new RestClient.FailureListener();
}
CloseableHttpAsyncClient httpClient = createHttpClient();
RestClient restClient = new RestClient(httpClient, maxRetryTimeout, defaultHeaders, hosts, failureListener);
RestClient restClient = new RestClient(httpClient, maxRetryTimeout, defaultHeaders, hosts, pathPrefix, failureListener);
httpClient.start();
return restClient;
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.client;
import com.carrotsearch.randomizedtesting.generators.RandomInts;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
@ -28,8 +27,10 @@ import org.apache.http.message.BasicHeader;
import java.io.IOException;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
public class RestClientBuilderTests extends RestClientTestCase {
@ -38,8 +39,8 @@ public class RestClientBuilderTests extends RestClientTestCase {
try {
RestClient.builder((HttpHost[])null);
fail("should have failed");
} catch(IllegalArgumentException e) {
assertEquals("no hosts provided", e.getMessage());
} catch(NullPointerException e) {
assertEquals("hosts must not be null", e.getMessage());
}
try {
@ -62,7 +63,7 @@ public class RestClientBuilderTests extends RestClientTestCase {
try {
RestClient.builder(new HttpHost("localhost", 9200))
.setMaxRetryTimeoutMillis(RandomInts.randomIntBetween(getRandom(), Integer.MIN_VALUE, 0));
.setMaxRetryTimeoutMillis(randomIntBetween(Integer.MIN_VALUE, 0));
fail("should have failed");
} catch(IllegalArgumentException e) {
assertEquals("maxRetryTimeoutMillis must be greater than 0", e.getMessage());
@ -103,13 +104,13 @@ public class RestClientBuilderTests extends RestClientTestCase {
assertEquals("requestConfigCallback must not be null", e.getMessage());
}
int numNodes = RandomInts.randomIntBetween(getRandom(), 1, 5);
int numNodes = randomIntBetween(1, 5);
HttpHost[] hosts = new HttpHost[numNodes];
for (int i = 0; i < numNodes; i++) {
hosts[i] = new HttpHost("localhost", 9200 + i);
}
RestClientBuilder builder = RestClient.builder(hosts);
if (getRandom().nextBoolean()) {
if (randomBoolean()) {
builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
@ -117,7 +118,7 @@ public class RestClientBuilderTests extends RestClientTestCase {
}
});
}
if (getRandom().nextBoolean()) {
if (randomBoolean()) {
builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
@Override
public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
@ -125,19 +126,55 @@ public class RestClientBuilderTests extends RestClientTestCase {
}
});
}
if (getRandom().nextBoolean()) {
int numHeaders = RandomInts.randomIntBetween(getRandom(), 1, 5);
if (randomBoolean()) {
int numHeaders = randomIntBetween(1, 5);
Header[] headers = new Header[numHeaders];
for (int i = 0; i < numHeaders; i++) {
headers[i] = new BasicHeader("header" + i, "value");
}
builder.setDefaultHeaders(headers);
}
if (getRandom().nextBoolean()) {
builder.setMaxRetryTimeoutMillis(RandomInts.randomIntBetween(getRandom(), 1, Integer.MAX_VALUE));
if (randomBoolean()) {
builder.setMaxRetryTimeoutMillis(randomIntBetween(1, Integer.MAX_VALUE));
}
if (randomBoolean()) {
String pathPrefix = (randomBoolean() ? "/" : "") + randomAsciiOfLengthBetween(2, 5);
while (pathPrefix.length() < 20 && randomBoolean()) {
pathPrefix += "/" + randomAsciiOfLengthBetween(3, 6);
}
builder.setPathPrefix(pathPrefix + (randomBoolean() ? "/" : ""));
}
try (RestClient restClient = builder.build()) {
assertNotNull(restClient);
}
}
public void testSetPathPrefixNull() {
try {
RestClient.builder(new HttpHost("localhost", 9200)).setPathPrefix(null);
fail("pathPrefix set to null should fail!");
} catch (final NullPointerException e) {
assertEquals("pathPrefix must not be null", e.getMessage());
}
}
public void testSetPathPrefixEmpty() {
assertSetPathPrefixThrows("/");
assertSetPathPrefixThrows("");
}
public void testSetPathPrefixMalformed() {
assertSetPathPrefixThrows("//");
assertSetPathPrefixThrows("base/path//");
}
private static void assertSetPathPrefixThrows(final String pathPrefix) {
try {
RestClient.builder(new HttpHost("localhost", 9200)).setPathPrefix(pathPrefix);
fail("path prefix [" + pathPrefix + "] should have failed");
} catch (final IllegalArgumentException e) {
assertThat(e.getMessage(), containsString(pathPrefix));
}
}
}

View File

@ -19,18 +19,15 @@
package org.elasticsearch.client;
import com.carrotsearch.randomizedtesting.generators.RandomInts;
import com.carrotsearch.randomizedtesting.generators.RandomStrings;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
import org.junit.AfterClass;
@ -60,6 +57,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Integration test to check interaction between {@link RestClient} and {@link org.apache.http.client.HttpClient}.
@ -81,13 +79,8 @@ public class RestClientIntegTests extends RestClientTestCase {
for (int statusCode : getAllStatusCodes()) {
createStatusCodeContext(httpServer, statusCode);
}
int numHeaders = RandomInts.randomIntBetween(getRandom(), 0, 3);
defaultHeaders = new Header[numHeaders];
for (int i = 0; i < numHeaders; i++) {
String headerName = "Header-default" + (getRandom().nextBoolean() ? i : "");
String headerValue = RandomStrings.randomAsciiOfLengthBetween(getRandom(), 3, 10);
defaultHeaders[i] = new BasicHeader(headerName, headerValue);
}
int numHeaders = randomIntBetween(0, 5);
defaultHeaders = generateHeaders("Header-default", "Header-array", numHeaders);
restClient = RestClient.builder(new HttpHost(httpServer.getAddress().getHostString(), httpServer.getAddress().getPort()))
.setDefaultHeaders(defaultHeaders).build();
}
@ -146,44 +139,43 @@ public class RestClientIntegTests extends RestClientTestCase {
*/
public void testHeaders() throws IOException {
for (String method : getHttpMethods()) {
Set<String> standardHeaders = new HashSet<>(
Arrays.asList("Connection", "Host", "User-agent", "Date"));
final Set<String> standardHeaders = new HashSet<>(Arrays.asList("Connection", "Host", "User-agent", "Date"));
if (method.equals("HEAD") == false) {
standardHeaders.add("Content-length");
}
int numHeaders = RandomInts.randomIntBetween(getRandom(), 1, 5);
Map<String, String> expectedHeaders = new HashMap<>();
for (Header defaultHeader : defaultHeaders) {
expectedHeaders.put(defaultHeader.getName(), defaultHeader.getValue());
}
Header[] headers = new Header[numHeaders];
for (int i = 0; i < numHeaders; i++) {
String headerName = "Header" + (getRandom().nextBoolean() ? i : "");
String headerValue = RandomStrings.randomAsciiOfLengthBetween(getRandom(), 3, 10);
headers[i] = new BasicHeader(headerName, headerValue);
expectedHeaders.put(headerName, headerValue);
}
int statusCode = randomStatusCode(getRandom());
final int numHeaders = randomIntBetween(1, 5);
final Header[] headers = generateHeaders("Header", "Header-array", numHeaders);
final Map<String, List<String>> expectedHeaders = new HashMap<>();
addHeaders(expectedHeaders, defaultHeaders, headers);
final int statusCode = randomStatusCode(getRandom());
Response esResponse;
try {
esResponse = restClient.performRequest(method, "/" + statusCode, Collections.<String, String>emptyMap(),
(HttpEntity)null, headers);
esResponse = restClient.performRequest(method, "/" + statusCode, Collections.<String, String>emptyMap(), headers);
} catch(ResponseException e) {
esResponse = e.getResponse();
}
assertThat(esResponse.getStatusLine().getStatusCode(), equalTo(statusCode));
for (Header responseHeader : esResponse.getHeaders()) {
if (responseHeader.getName().startsWith("Header")) {
String headerValue = expectedHeaders.remove(responseHeader.getName());
assertNotNull("found response header [" + responseHeader.getName() + "] that wasn't originally sent", headerValue);
for (final Header responseHeader : esResponse.getHeaders()) {
final String name = responseHeader.getName();
final String value = responseHeader.getValue();
if (name.startsWith("Header")) {
final List<String> values = expectedHeaders.get(name);
assertNotNull("found response header [" + name + "] that wasn't originally sent: " + value, values);
assertTrue("found incorrect response header [" + name + "]: " + value, values.remove(value));
// we've collected them all
if (values.isEmpty()) {
expectedHeaders.remove(name);
}
} else {
assertTrue("unknown header was returned " + responseHeader.getName(),
standardHeaders.remove(responseHeader.getName()));
assertTrue("unknown header was returned " + name, standardHeaders.remove(name));
}
}
assertEquals("some headers that were sent weren't returned: " + expectedHeaders, 0, expectedHeaders.size());
assertEquals("some expected standard headers weren't returned: " + standardHeaders, 0, standardHeaders.size());
assertTrue("some headers that were sent weren't returned: " + expectedHeaders, expectedHeaders.isEmpty());
assertTrue("some expected standard headers weren't returned: " + standardHeaders, standardHeaders.isEmpty());
}
}
@ -205,6 +197,38 @@ public class RestClientIntegTests extends RestClientTestCase {
bodyTest("GET");
}
/**
* Ensure that pathPrefix works as expected.
*/
public void testPathPrefix() throws IOException {
// guarantee no other test setup collides with this one and lets it sneak through
final String uniqueContextSuffix = "/testPathPrefix";
final String pathPrefix = "base/" + randomAsciiOfLengthBetween(1, 5) + "/";
final int statusCode = randomStatusCode(getRandom());
final HttpContext context =
httpServer.createContext("/" + pathPrefix + statusCode + uniqueContextSuffix, new ResponseHandler(statusCode));
try (final RestClient client =
RestClient.builder(new HttpHost(httpServer.getAddress().getHostString(), httpServer.getAddress().getPort()))
.setPathPrefix((randomBoolean() ? "/" : "") + pathPrefix).build()) {
for (final String method : getHttpMethods()) {
Response esResponse;
try {
esResponse = client.performRequest(method, "/" + statusCode + uniqueContextSuffix);
} catch(ResponseException e) {
esResponse = e.getResponse();
}
assertThat(esResponse.getRequestLine().getUri(), equalTo("/" + pathPrefix + statusCode + uniqueContextSuffix));
assertThat(esResponse.getStatusLine().getStatusCode(), equalTo(statusCode));
}
} finally {
httpServer.removeContext(context);
}
}
private void bodyTest(String method) throws IOException {
String requestBody = "{ \"field\": \"value\" }";
StringEntity entity = new StringEntity(requestBody);

View File

@ -101,7 +101,7 @@ public class RestClientMultipleHostsTests extends RestClientTestCase {
httpHosts[i] = new HttpHost("localhost", 9200 + i);
}
failureListener = new HostsTrackingFailureListener();
restClient = new RestClient(httpClient, 10000, new Header[0], httpHosts, failureListener);
restClient = new RestClient(httpClient, 10000, new Header[0], httpHosts, null, failureListener);
}
public void testRoundRobinOkStatusCodes() throws IOException {

View File

@ -19,8 +19,6 @@
package org.elasticsearch.client;
import com.carrotsearch.randomizedtesting.generators.RandomInts;
import com.carrotsearch.randomizedtesting.generators.RandomStrings;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
@ -41,7 +39,6 @@ import org.apache.http.concurrent.FutureCallback;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
@ -58,7 +55,10 @@ import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import static org.elasticsearch.client.RestClientTestUtil.getAllErrorStatusCodes;
@ -132,16 +132,11 @@ public class RestClientSingleHostTests extends RestClientTestCase {
});
int numHeaders = RandomInts.randomIntBetween(getRandom(), 0, 3);
defaultHeaders = new Header[numHeaders];
for (int i = 0; i < numHeaders; i++) {
String headerName = "Header-default" + (getRandom().nextBoolean() ? i : "");
String headerValue = RandomStrings.randomAsciiOfLengthBetween(getRandom(), 3, 10);
defaultHeaders[i] = new BasicHeader(headerName, headerValue);
}
int numHeaders = randomIntBetween(0, 3);
defaultHeaders = generateHeaders("Header-default", "Header-array", numHeaders);
httpHost = new HttpHost("localhost", 9200);
failureListener = new HostsTrackingFailureListener();
restClient = new RestClient(httpClient, 10000, defaultHeaders, new HttpHost[]{httpHost}, failureListener);
restClient = new RestClient(httpClient, 10000, defaultHeaders, new HttpHost[]{httpHost}, null, failureListener);
}
/**
@ -333,20 +328,13 @@ public class RestClientSingleHostTests extends RestClientTestCase {
*/
public void testHeaders() throws IOException {
for (String method : getHttpMethods()) {
Map<String, String> expectedHeaders = new HashMap<>();
for (Header defaultHeader : defaultHeaders) {
expectedHeaders.put(defaultHeader.getName(), defaultHeader.getValue());
}
int numHeaders = RandomInts.randomIntBetween(getRandom(), 1, 5);
Header[] headers = new Header[numHeaders];
for (int i = 0; i < numHeaders; i++) {
String headerName = "Header" + (getRandom().nextBoolean() ? i : "");
String headerValue = RandomStrings.randomAsciiOfLengthBetween(getRandom(), 3, 10);
headers[i] = new BasicHeader(headerName, headerValue);
expectedHeaders.put(headerName, headerValue);
}
final int numHeaders = randomIntBetween(1, 5);
final Header[] headers = generateHeaders("Header", null, numHeaders);
final Map<String, List<String>> expectedHeaders = new HashMap<>();
int statusCode = randomStatusCode(getRandom());
addHeaders(expectedHeaders, defaultHeaders, headers);
final int statusCode = randomStatusCode(getRandom());
Response esResponse;
try {
esResponse = restClient.performRequest(method, "/" + statusCode, headers);
@ -355,10 +343,18 @@ public class RestClientSingleHostTests extends RestClientTestCase {
}
assertThat(esResponse.getStatusLine().getStatusCode(), equalTo(statusCode));
for (Header responseHeader : esResponse.getHeaders()) {
String headerValue = expectedHeaders.remove(responseHeader.getName());
assertNotNull("found response header [" + responseHeader.getName() + "] that wasn't originally sent", headerValue);
final String name = responseHeader.getName();
final String value = responseHeader.getValue();
final List<String> values = expectedHeaders.get(name);
assertNotNull("found response header [" + name + "] that wasn't originally sent: " + value, values);
assertTrue("found incorrect response header [" + name + "]: " + value, values.remove(value));
// we've collected them all
if (values.isEmpty()) {
expectedHeaders.remove(name);
}
}
assertEquals("some headers that were sent weren't returned " + expectedHeaders, 0, expectedHeaders.size());
assertTrue("some headers that were sent weren't returned " + expectedHeaders, expectedHeaders.isEmpty());
}
}
@ -368,11 +364,11 @@ public class RestClientSingleHostTests extends RestClientTestCase {
Map<String, String> params = Collections.emptyMap();
boolean hasParams = randomBoolean();
if (hasParams) {
int numParams = RandomInts.randomIntBetween(getRandom(), 1, 3);
int numParams = randomIntBetween(1, 3);
params = new HashMap<>(numParams);
for (int i = 0; i < numParams; i++) {
String paramKey = "param-" + i;
String paramValue = RandomStrings.randomAsciiOfLengthBetween(getRandom(), 3, 10);
String paramValue = randomAsciiOfLengthBetween(3, 10);
params.put(paramKey, paramValue);
uriBuilder.addParameter(paramKey, paramValue);
}
@ -412,24 +408,24 @@ public class RestClientSingleHostTests extends RestClientTestCase {
HttpEntity entity = null;
boolean hasBody = request instanceof HttpEntityEnclosingRequest && getRandom().nextBoolean();
if (hasBody) {
entity = new StringEntity(RandomStrings.randomAsciiOfLengthBetween(getRandom(), 10, 100));
entity = new StringEntity(randomAsciiOfLengthBetween(10, 100));
((HttpEntityEnclosingRequest) request).setEntity(entity);
}
Header[] headers = new Header[0];
for (Header defaultHeader : defaultHeaders) {
//default headers are expected but not sent for each request
request.setHeader(defaultHeader);
final int numHeaders = randomIntBetween(1, 5);
final Set<String> uniqueNames = new HashSet<>(numHeaders);
if (randomBoolean()) {
headers = generateHeaders("Header", "Header-array", numHeaders);
for (Header header : headers) {
request.addHeader(header);
uniqueNames.add(header.getName());
}
}
if (getRandom().nextBoolean()) {
int numHeaders = RandomInts.randomIntBetween(getRandom(), 1, 5);
headers = new Header[numHeaders];
for (int i = 0; i < numHeaders; i++) {
String headerName = "Header" + (getRandom().nextBoolean() ? i : "");
String headerValue = RandomStrings.randomAsciiOfLengthBetween(getRandom(), 3, 10);
BasicHeader basicHeader = new BasicHeader(headerName, headerValue);
headers[i] = basicHeader;
request.setHeader(basicHeader);
for (Header defaultHeader : defaultHeaders) {
// request level headers override default headers
if (uniqueNames.contains(defaultHeader.getName()) == false) {
request.addHeader(defaultHeader);
}
}
@ -459,4 +455,5 @@ public class RestClientSingleHostTests extends RestClientTestCase {
throw new UnsupportedOperationException();
}
}
}

View File

@ -30,6 +30,7 @@ install.enabled = false
uploadArchives.enabled = false
dependencies {
compile "org.apache.httpcomponents:httpcore:${versions.httpcore}"
compile "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${versions.randomizedrunner}"
compile "junit:junit:${versions.junit}"
compile "org.hamcrest:hamcrest-all:${versions.hamcrest}"

View File

@ -31,6 +31,15 @@ import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakZombies;
import com.carrotsearch.randomizedtesting.annotations.TimeoutSuite;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@TestMethodProviders({
JUnit3MethodProvider.class
})
@ -43,4 +52,71 @@ import com.carrotsearch.randomizedtesting.annotations.TimeoutSuite;
@TimeoutSuite(millis = 2 * 60 * 60 * 1000)
public abstract class RestClientTestCase extends RandomizedTest {
/**
* Create the specified number of {@link Header}s.
* <p>
* Generated header names will be the {@code baseName} plus its index or, rarely, the {@code arrayName} if it's supplied.
*
* @param baseName The base name to use for all headers.
* @param arrayName The optional ({@code null}able) array name to use randomly.
* @param headers The number of headers to create.
* @return Never {@code null}.
*/
protected static Header[] generateHeaders(final String baseName, final String arrayName, final int headers) {
final Header[] generated = new Header[headers];
for (int i = 0; i < headers; i++) {
String headerName = baseName + i;
if (arrayName != null && rarely()) {
headerName = arrayName;
}
generated[i] = new BasicHeader(headerName, randomAsciiOfLengthBetween(3, 10));
}
return generated;
}
/**
* Create a new {@link List} within the {@code map} if none exists for {@code name} or append to the existing list.
*
* @param map The map to manipulate.
* @param name The name to create/append the list for.
* @param value The value to add.
*/
private static void createOrAppendList(final Map<String, List<String>> map, final String name, final String value) {
List<String> values = map.get(name);
if (values == null) {
values = new ArrayList<>();
map.put(name, values);
}
values.add(value);
}
/**
* Add the {@code headers} to the {@code map} so that related tests can more easily assert that they exist.
* <p>
* If both the {@code defaultHeaders} and {@code headers} contain the same {@link Header}, based on its
* {@linkplain Header#getName() name}, then this will only use the {@code Header}(s) from {@code headers}.
*
* @param map The map to build with name/value(s) pairs.
* @param defaultHeaders The headers to add to the map representing default headers.
* @param headers The headers to add to the map representing request-level headers.
* @see #createOrAppendList(Map, String, String)
*/
protected static void addHeaders(final Map<String, List<String>> map, final Header[] defaultHeaders, final Header[] headers) {
final Set<String> uniqueHeaders = new HashSet<>();
for (final Header header : headers) {
final String name = header.getName();
createOrAppendList(map, name, header.getValue());
uniqueHeaders.add(name);
}
for (final Header defaultHeader : defaultHeaders) {
final String name = defaultHeader.getName();
if (uniqueHeaders.contains(name) == false) {
createOrAppendList(map, name, defaultHeader.getValue());
}
}
}
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.transport.client;
import com.carrotsearch.randomizedtesting.RandomizedTest;
import org.apache.lucene.util.Constants;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
@ -40,6 +41,8 @@ public class PreBuiltTransportClientTests extends RandomizedTest {
@Test
public void testPluginInstalled() {
// TODO: remove when Netty 4.1.5 is upgraded to Netty 4.1.6 including https://github.com/netty/netty/pull/5778
assumeFalse(Constants.JRE_IS_MINIMUM_JAVA9);
try (TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)) {
Settings settings = client.settings();
assertEquals(Netty4Plugin.NETTY_TRANSPORT_NAME, NetworkModule.HTTP_DEFAULT_TYPE_SETTING.get(settings));
@ -49,9 +52,7 @@ public class PreBuiltTransportClientTests extends RandomizedTest {
@Test
public void testInstallPluginTwice() {
for (Class<? extends Plugin> plugin : Arrays.asList(ReindexPlugin.class, PercolatorPlugin.class,
MustachePlugin.class)) {
for (Class<? extends Plugin> plugin : Arrays.asList(ReindexPlugin.class, PercolatorPlugin.class, MustachePlugin.class)) {
try {
new PreBuiltTransportClient(Settings.EMPTY, plugin);
fail("exception expected");

View File

@ -133,12 +133,10 @@ public class DeprecationLogger {
// ignored; it should be removed shortly
}
}
logger.warn(formattedMessage);
} else {
logger.warn(message, params);
}
}
}

View File

@ -27,6 +27,7 @@ import java.util.Map;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.analysis.AnalysisRegistry;
import org.elasticsearch.plugins.IngestPlugin;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.threadpool.ThreadPool;
@ -40,10 +41,12 @@ public class IngestService {
private final PipelineExecutionService pipelineExecutionService;
public IngestService(Settings settings, ThreadPool threadPool,
Environment env, ScriptService scriptService, List<IngestPlugin> ingestPlugins) {
Environment env, ScriptService scriptService, AnalysisRegistry analysisRegistry,
List<IngestPlugin> ingestPlugins) {
final TemplateService templateService = new InternalTemplateService(scriptService);
Processor.Parameters parameters = new Processor.Parameters(env, scriptService, templateService,
threadPool.getThreadContext());
analysisRegistry, threadPool.getThreadContext());
Map<String, Processor.Factory> processorFactories = new HashMap<>();
for (IngestPlugin ingestPlugin : ingestPlugins) {
Map<String, Processor.Factory> newProcessors = ingestPlugin.getProcessors(parameters);

View File

@ -21,6 +21,7 @@ package org.elasticsearch.ingest;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.analysis.AnalysisRegistry;
import org.elasticsearch.script.ScriptService;
import java.util.Map;
@ -86,6 +87,11 @@ public interface Processor {
*/
public final TemplateService templateService;
/**
* Provide analyzer support
*/
public final AnalysisRegistry analysisRegistry;
/**
* Allows processors to read headers set by {@link org.elasticsearch.action.support.ActionFilter}
* instances that have run prior to in ingest.
@ -93,11 +99,12 @@ public interface Processor {
public final ThreadContext threadContext;
public Parameters(Environment env, ScriptService scriptService, TemplateService templateService,
ThreadContext threadContext) {
AnalysisRegistry analysisRegistry, ThreadContext threadContext) {
this.env = env;
this.scriptService = scriptService;
this.templateService = templateService;
this.threadContext = threadContext;
this.analysisRegistry = analysisRegistry;
}
}

View File

@ -317,7 +317,7 @@ public class Node implements Closeable {
final TribeService tribeService = new TribeService(settings, clusterService, nodeEnvironment.nodeId());
resourcesToClose.add(tribeService);
final IngestService ingestService = new IngestService(settings, threadPool, this.environment,
scriptModule.getScriptService(), pluginsService.filterPlugins(IngestPlugin.class));
scriptModule.getScriptService(), analysisModule.getAnalysisRegistry(), pluginsService.filterPlugins(IngestPlugin.class));
ModulesBuilder modules = new ModulesBuilder();
// plugin modules must be added here, before others or we can get crazy injection errors...

View File

@ -39,7 +39,7 @@ public class IngestServiceTests extends ESTestCase {
public void testIngestPlugin() {
ThreadPool tp = Mockito.mock(ThreadPool.class);
IngestService ingestService = new IngestService(Settings.EMPTY, tp, null, null, Collections.singletonList(DUMMY_PLUGIN));
IngestService ingestService = new IngestService(Settings.EMPTY, tp, null, null, null, Collections.singletonList(DUMMY_PLUGIN));
Map<String, Processor.Factory> factories = ingestService.getPipelineStore().getProcessorFactories();
assertTrue(factories.containsKey("foo"));
assertEquals(1, factories.size());
@ -48,7 +48,7 @@ public class IngestServiceTests extends ESTestCase {
public void testIngestPluginDuplicate() {
ThreadPool tp = Mockito.mock(ThreadPool.class);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new IngestService(Settings.EMPTY, tp, null, null, Arrays.asList(DUMMY_PLUGIN, DUMMY_PLUGIN))
new IngestService(Settings.EMPTY, tp, null, null, null, Arrays.asList(DUMMY_PLUGIN, DUMMY_PLUGIN))
);
assertTrue(e.getMessage(), e.getMessage().contains("already registered"));
}

View File

@ -59,8 +59,9 @@
# use our provided JNA always versus the system one
-Djna.nosys=true
# flag to explicitly tell Netty to not use unsafe
# flags to keep Netty from being unsafe
-Dio.netty.noUnsafe=true
-Dio.netty.noKeySetOptimization=true
# log4j 2
-Dlog4j.shutdownHookEnabled=false

View File

@ -130,20 +130,23 @@ http://logging.apache.org/log4j/extras/[log4j-extras] are also available,
out of the box.
[float]
[[deprecation-logging]]
[[deprecation-logging]]e
=== Deprecation logging
In addition to regular logging, Elasticsearch allows you to enable logging
of deprecated actions. For example this allows you to determine early, if
you need to migrate certain functionality in the future. By default,
deprecation logging is disabled. You can enable it in the `config/logging.yml`
file by setting the deprecation log level to `DEBUG`.
deprecation logging is enabled at the WARN level, the level at which all
deprecation log messages will be emitted.
[source,yaml]
--------------------------------------------------
deprecation: DEBUG, deprecation_log_file
deprecation: WARN, deprecation_log_file
--------------------------------------------------
This will create a daily rolling deprecation log file in your log directory.
Check this file regularly, especially when you intend to upgrade to a new
major version.
You can disable it in the `config/logging.yml` file by setting the deprecation
log level to `INFO`.

View File

@ -53,6 +53,8 @@ import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.BoostingQueryBuilder;
import org.elasticsearch.index.query.ConstantScoreQueryBuilder;
import org.elasticsearch.index.query.HasChildQueryBuilder;
import org.elasticsearch.index.query.HasParentQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryShardContext;
@ -269,7 +271,7 @@ public class PercolatorFieldMapper extends FieldMapper {
XContentParser parser = context.parser();
QueryBuilder queryBuilder = parseQueryBuilder(queryShardContext.newParseContext(parser), parser.getTokenLocation());
verifyRangeQueries(queryBuilder);
verifyQuery(queryBuilder);
// Fetching of terms, shapes and indexed scripts happen during this rewrite:
queryBuilder = queryBuilder.rewrite(queryShardContext);
@ -356,19 +358,26 @@ public class PercolatorFieldMapper extends FieldMapper {
}
/**
* Fails if a range query with a date range is found based on current time
* Fails if a percolator contains an unsupported query. The following queries are not supported:
* 1) a range query with a date range based on current time
* 2) a has_child query
* 3) a has_parent query
*/
static void verifyRangeQueries(QueryBuilder queryBuilder) {
static void verifyQuery(QueryBuilder queryBuilder) {
if (queryBuilder instanceof RangeQueryBuilder) {
RangeQueryBuilder rangeQueryBuilder = (RangeQueryBuilder) queryBuilder;
if (rangeQueryBuilder.from() instanceof String) {
String from = (String) rangeQueryBuilder.from();
String to = (String) rangeQueryBuilder.to();
if (from.contains("now") || to.contains("now")) {
throw new IllegalArgumentException("Percolator queries containing time range queries based on the " +
"current time are forbidden");
throw new IllegalArgumentException("percolator queries containing time range queries based on the " +
"current time is unsupported");
}
}
} else if (queryBuilder instanceof HasChildQueryBuilder) {
throw new IllegalArgumentException("the [has_child] query is unsupported inside a percolator query");
} else if (queryBuilder instanceof HasParentQueryBuilder) {
throw new IllegalArgumentException("the [has_parent] query is unsupported inside a percolator query");
} else if (queryBuilder instanceof BoolQueryBuilder) {
BoolQueryBuilder boolQueryBuilder = (BoolQueryBuilder) queryBuilder;
List<QueryBuilder> clauses = new ArrayList<>();
@ -377,15 +386,15 @@ public class PercolatorFieldMapper extends FieldMapper {
clauses.addAll(boolQueryBuilder.mustNot());
clauses.addAll(boolQueryBuilder.should());
for (QueryBuilder clause : clauses) {
verifyRangeQueries(clause);
verifyQuery(clause);
}
} else if (queryBuilder instanceof ConstantScoreQueryBuilder) {
verifyRangeQueries(((ConstantScoreQueryBuilder) queryBuilder).innerQuery());
verifyQuery(((ConstantScoreQueryBuilder) queryBuilder).innerQuery());
} else if (queryBuilder instanceof FunctionScoreQueryBuilder) {
verifyRangeQueries(((FunctionScoreQueryBuilder) queryBuilder).query());
verifyQuery(((FunctionScoreQueryBuilder) queryBuilder).query());
} else if (queryBuilder instanceof BoostingQueryBuilder) {
verifyRangeQueries(((BoostingQueryBuilder) queryBuilder).negativeQuery());
verifyRangeQueries(((BoostingQueryBuilder) queryBuilder).positiveQuery());
verifyQuery(((BoostingQueryBuilder) queryBuilder).negativeQuery());
verifyQuery(((BoostingQueryBuilder) queryBuilder).positiveQuery());
}
}

View File

@ -32,6 +32,7 @@ import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.join.ScoreMode;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetaData;
@ -49,6 +50,8 @@ import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.BoostingQueryBuilder;
import org.elasticsearch.index.query.ConstantScoreQueryBuilder;
import org.elasticsearch.index.query.HasChildQueryBuilder;
import org.elasticsearch.index.query.HasParentQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
@ -435,23 +438,31 @@ public class PercolatorFieldMapperTests extends ESSingleNodeTestCase {
assertThat(e.getCause(), instanceOf(IllegalArgumentException.class));
}
public void testVerifyRangeQueries() {
public void testUnsupportedQueries() {
RangeQueryBuilder rangeQuery1 = new RangeQueryBuilder("field").from("2016-01-01||/D").to("2017-01-01||/D");
RangeQueryBuilder rangeQuery2 = new RangeQueryBuilder("field").from("2016-01-01||/D").to("now");
PercolatorFieldMapper.verifyRangeQueries(rangeQuery1);
expectThrows(IllegalArgumentException.class, () -> PercolatorFieldMapper.verifyRangeQueries(rangeQuery2));
PercolatorFieldMapper.verifyRangeQueries(new BoolQueryBuilder().must(rangeQuery1));
PercolatorFieldMapper.verifyQuery(rangeQuery1);
expectThrows(IllegalArgumentException.class, () -> PercolatorFieldMapper.verifyQuery(rangeQuery2));
PercolatorFieldMapper.verifyQuery(new BoolQueryBuilder().must(rangeQuery1));
expectThrows(IllegalArgumentException.class, () ->
PercolatorFieldMapper.verifyRangeQueries(new BoolQueryBuilder().must(rangeQuery2)));
PercolatorFieldMapper.verifyRangeQueries(new ConstantScoreQueryBuilder((rangeQuery1)));
PercolatorFieldMapper.verifyQuery(new BoolQueryBuilder().must(rangeQuery2)));
PercolatorFieldMapper.verifyQuery(new ConstantScoreQueryBuilder((rangeQuery1)));
expectThrows(IllegalArgumentException.class, () ->
PercolatorFieldMapper.verifyRangeQueries(new ConstantScoreQueryBuilder(rangeQuery2)));
PercolatorFieldMapper.verifyRangeQueries(new BoostingQueryBuilder(rangeQuery1, new MatchAllQueryBuilder()));
PercolatorFieldMapper.verifyQuery(new ConstantScoreQueryBuilder(rangeQuery2)));
PercolatorFieldMapper.verifyQuery(new BoostingQueryBuilder(rangeQuery1, new MatchAllQueryBuilder()));
expectThrows(IllegalArgumentException.class, () ->
PercolatorFieldMapper.verifyRangeQueries(new BoostingQueryBuilder(rangeQuery2, new MatchAllQueryBuilder())));
PercolatorFieldMapper.verifyRangeQueries(new FunctionScoreQueryBuilder(rangeQuery1, new RandomScoreFunctionBuilder()));
PercolatorFieldMapper.verifyQuery(new BoostingQueryBuilder(rangeQuery2, new MatchAllQueryBuilder())));
PercolatorFieldMapper.verifyQuery(new FunctionScoreQueryBuilder(rangeQuery1, new RandomScoreFunctionBuilder()));
expectThrows(IllegalArgumentException.class, () ->
PercolatorFieldMapper.verifyRangeQueries(new FunctionScoreQueryBuilder(rangeQuery2, new RandomScoreFunctionBuilder())));
PercolatorFieldMapper.verifyQuery(new FunctionScoreQueryBuilder(rangeQuery2, new RandomScoreFunctionBuilder())));
HasChildQueryBuilder hasChildQuery = new HasChildQueryBuilder("_type", new MatchAllQueryBuilder(), ScoreMode.None);
expectThrows(IllegalArgumentException.class, () -> PercolatorFieldMapper.verifyQuery(hasChildQuery));
expectThrows(IllegalArgumentException.class, () -> PercolatorFieldMapper.verifyQuery(new BoolQueryBuilder().must(hasChildQuery)));
HasParentQueryBuilder hasParentQuery = new HasParentQueryBuilder("_type", new MatchAllQueryBuilder(), false);
expectThrows(IllegalArgumentException.class, () -> PercolatorFieldMapper.verifyQuery(hasParentQuery));
expectThrows(IllegalArgumentException.class, () -> PercolatorFieldMapper.verifyQuery(new BoolQueryBuilder().must(hasParentQuery)));
}
private void assertQueryBuilder(BytesRef actual, QueryBuilder expected) throws IOException {

View File

@ -1777,16 +1777,15 @@ public class PercolatorIT extends ESIntegTestCase {
assertThat(response1.getMatches()[0].getId().string(), equalTo("1"));
}
public void testParentChild() throws Exception {
// We don't fail p/c queries, but those queries are unusable because only a single document can be provided in
// the percolate api
public void testFailParentChild() throws Exception {
assertAcked(prepareCreate(INDEX_NAME)
.addMapping(TYPE_NAME, "query", "type=percolator")
.addMapping("child", "_parent", "type=parent").addMapping("parent"));
client().prepareIndex(INDEX_NAME, TYPE_NAME, "1")
Exception e = expectThrows(MapperParsingException.class, () -> client().prepareIndex(INDEX_NAME, TYPE_NAME, "1")
.setSource(jsonBuilder().startObject().field("query", hasChildQuery("child", matchAllQuery(), ScoreMode.None)).endObject())
.execute().actionGet();
.get());
assertThat(e.getCause(), instanceOf(IllegalArgumentException.class));
assertThat(e.getCause().getMessage(), equalTo("the [has_child] query is unsupported inside a percolator query"));
}
public void testPercolateDocumentWithParentField() throws Exception {

View File

@ -155,7 +155,7 @@ public final class FileUtils {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (file.toString().endsWith(fileSuffix)) {
String groupName = file.toAbsolutePath().getParent().getFileName().toString();
String groupName = dir.relativize(file.getParent()).toString();
Set<Path> filesSet = files.get(groupName);
if (filesSet == null) {
filesSet = new HashSet<>();

View File

@ -31,6 +31,7 @@ import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.greaterThan;
public class FileUtilsTests extends ESTestCase {
@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/20240")
public void testLoadSingleYamlSuite() throws Exception {
Map<String,Set<Path>> yamlSuites = FileUtils.findYamlSuites(null, "/rest-api-spec/test", "/rest-api-spec/test/suite1/10_basic");
assertSingleFile(yamlSuites, "suite1", "10_basic.yaml");
@ -44,6 +45,7 @@ public class FileUtilsTests extends ESTestCase {
assertSingleFile(yamlSuites, "suite1", "10_basic.yaml");
}
@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/20240")
public void testLoadMultipleYamlSuites() throws Exception {
//single directory
Map<String,Set<Path>> yamlSuites = FileUtils.findYamlSuites(null, "/rest-api-spec/test", "suite1");