Search in sources :

Example 1 with ClientYamlSuiteRestApi

use of org.opensearch.test.rest.yaml.restspec.ClientYamlSuiteRestApi in project OpenSearch by opensearch-project.

the class RestHighLevelClientTests method testApiNamingConventions.

public void testApiNamingConventions() throws Exception {
    // this list should be empty once the high-level client is feature complete
    String[] notYetSupportedApi = new String[] { "create", "get_script_context", "get_script_languages", "indices.exists_type", "indices.get_upgrade", "indices.put_alias", "render_search_template", "scripts_painless_execute", "indices.simulate_template", "indices.resolve_index", "indices.add_block" };
    // These API are not required for high-level client feature completeness
    String[] notRequiredApi = new String[] { "cluster.allocation_explain", "cluster.pending_tasks", "cluster.reroute", "cluster.state", "cluster.stats", "cluster.post_voting_config_exclusions", "cluster.delete_voting_config_exclusions", "dangling_indices.delete_dangling_index", "dangling_indices.import_dangling_index", "dangling_indices.list_dangling_indices", "indices.shard_stores", "indices.upgrade", "indices.recovery", "indices.segments", "indices.stats", "ingest.processor_grok", "nodes.info", "nodes.stats", "nodes.hot_threads", "nodes.usage", "nodes.reload_secure_settings", "search_shards" };
    List<String> booleanReturnMethods = Arrays.asList("security.enable_user", "security.disable_user", "security.change_password");
    Set<String> deprecatedMethods = new HashSet<>();
    deprecatedMethods.add("indices.force_merge");
    deprecatedMethods.add("multi_get");
    deprecatedMethods.add("multi_search");
    deprecatedMethods.add("search_scroll");
    ClientYamlSuiteRestSpec restSpec = ClientYamlSuiteRestSpec.load("/rest-api-spec/api");
    Set<String> apiSpec = restSpec.getApis().stream().map(ClientYamlSuiteRestApi::getName).collect(Collectors.toSet());
    Set<String> apiUnsupported = new HashSet<>(apiSpec);
    Set<String> apiNotFound = new HashSet<>();
    Set<String> topLevelMethodsExclusions = new HashSet<>();
    topLevelMethodsExclusions.add("getLowLevelClient");
    topLevelMethodsExclusions.add("close");
    Map<String, Set<Method>> methods = Arrays.stream(RestHighLevelClient.class.getMethods()).filter(method -> method.getDeclaringClass().equals(RestHighLevelClient.class) && topLevelMethodsExclusions.contains(method.getName()) == false).map(method -> Tuple.tuple(toSnakeCase(method.getName()), method)).flatMap(tuple -> tuple.v2().getReturnType().getName().endsWith("Client") ? getSubClientMethods(tuple.v1(), tuple.v2().getReturnType()) : Stream.of(tuple)).filter(tuple -> tuple.v2().getAnnotation(Deprecated.class) == null).collect(Collectors.groupingBy(Tuple::v1, Collectors.mapping(Tuple::v2, Collectors.toSet())));
    // TODO remove in 8.0 - we will undeprecate indices.get_template because the current getIndexTemplate
    // impl will replace the existing getTemplate method.
    // The above general-purpose code ignores all deprecated methods which in this case leaves `getTemplate`
    // looking like it doesn't have a valid implementatation when it does.
    apiUnsupported.remove("indices.get_template");
    // Synced flush is deprecated
    apiUnsupported.remove("indices.flush_synced");
    for (Map.Entry<String, Set<Method>> entry : methods.entrySet()) {
        String apiName = entry.getKey();
        for (Method method : entry.getValue()) {
            assertTrue("method [" + apiName + "] is not final", Modifier.isFinal(method.getClass().getModifiers()) || Modifier.isFinal(method.getModifiers()));
            assertTrue("method [" + method + "] should be public", Modifier.isPublic(method.getModifiers()));
            // we convert all the method names to snake case, hence we need to look for the '_async' suffix rather than 'Async'
            if (apiName.endsWith("_async")) {
                assertAsyncMethod(methods, method, apiName);
            } else if (isSubmitTaskMethod(apiName)) {
                assertSubmitTaskMethod(methods, method, apiName, restSpec);
            } else {
                assertSyncMethod(method, apiName, booleanReturnMethods);
                apiUnsupported.remove(apiName);
                if (apiSpec.contains(apiName) == false) {
                    if (deprecatedMethods.contains(apiName)) {
                        assertTrue("method [" + method.getName() + "], api [" + apiName + "] should be deprecated", method.isAnnotationPresent(Deprecated.class));
                    } else {
                        if (// can get rid of 7.0's deprecated "getTemplate"
                        apiName.equals("indices.get_index_template") == false) {
                            apiNotFound.add(apiName);
                        }
                    }
                }
            }
        }
    }
    assertThat("Some client method doesn't match a corresponding API defined in the REST spec: " + apiNotFound, apiNotFound.size(), equalTo(0));
    // we decided not to support cat API in the high-level REST client, they are supposed to be used from a low-level client
    apiUnsupported.removeIf(api -> api.startsWith("cat."));
    Stream.concat(Arrays.stream(notYetSupportedApi), Arrays.stream(notRequiredApi)).forEach(api -> assertTrue(api + " API is either not defined in the spec or already supported by the high-level client", apiUnsupported.remove(api)));
    assertThat("Some API are not supported but they should be: " + apiUnsupported, apiUnsupported.size(), equalTo(0));
}
Also used : InternalAggregationTestCase(org.opensearch.test.InternalAggregationTestCase) Arrays(java.util.Arrays) Aggregation(org.opensearch.search.aggregations.Aggregation) MainResponse(org.opensearch.client.core.MainResponse) ToXContentFragment(org.opensearch.common.xcontent.ToXContentFragment) CheckedFunction(org.opensearch.common.CheckedFunction) ToXContent(org.opensearch.common.xcontent.ToXContent) CoreMatchers.endsWith(org.hamcrest.CoreMatchers.endsWith) ChildrenAggregationBuilder(org.opensearch.join.aggregations.ChildrenAggregationBuilder) ActionRequest(org.opensearch.action.ActionRequest) OpenSearchException(org.opensearch.OpenSearchException) StatusLine(org.apache.http.StatusLine) NByteArrayEntity(org.apache.http.nio.entity.NByteArrayEntity) XContentParser(org.opensearch.common.xcontent.XContentParser) CoreMatchers.instanceOf(org.hamcrest.CoreMatchers.instanceOf) EvaluationMetric(org.opensearch.index.rankeval.EvaluationMetric) RequestLine(org.apache.http.RequestLine) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) InternalAggregations(org.opensearch.search.aggregations.InternalAggregations) Map(java.util.Map) NStringEntity(org.apache.http.nio.entity.NStringEntity) ActionListener(org.opensearch.action.ActionListener) JsonParseException(com.fasterxml.jackson.core.JsonParseException) Method(java.lang.reflect.Method) PrecisionAtK(org.opensearch.index.rankeval.PrecisionAtK) ClientYamlSuiteRestSpec(org.opensearch.test.rest.yaml.restspec.ClientYamlSuiteRestSpec) MetricDetail(org.opensearch.index.rankeval.MetricDetail) OpenSearchTestCase(org.opensearch.test.OpenSearchTestCase) HttpEntity(org.apache.http.HttpEntity) ContentType(org.apache.http.entity.ContentType) Set(java.util.Set) RestStatus(org.opensearch.rest.RestStatus) Collectors(java.util.stream.Collectors) Tuple(org.opensearch.common.collect.Tuple) RecallAtK(org.opensearch.index.rankeval.RecallAtK) List(java.util.List) Stream(java.util.stream.Stream) HttpGet(org.apache.http.client.methods.HttpGet) Modifier(java.lang.reflect.Modifier) Optional(java.util.Optional) MeanReciprocalRank(org.opensearch.index.rankeval.MeanReciprocalRank) Mockito.any(org.mockito.Mockito.any) SmileXContent(org.opensearch.common.xcontent.smile.SmileXContent) Mockito.mock(org.mockito.Mockito.mock) BytesReference(org.opensearch.common.bytes.BytesReference) BasicStatusLine(org.apache.http.message.BasicStatusLine) CoreMatchers.equalTo(org.hamcrest.CoreMatchers.equalTo) CborXContent(org.opensearch.common.xcontent.cbor.CborXContent) ExpectedReciprocalRank(org.opensearch.index.rankeval.ExpectedReciprocalRank) HashMap(java.util.HashMap) SearchHits(org.opensearch.search.SearchHits) AtomicReference(java.util.concurrent.atomic.AtomicReference) ActionRequestValidationException(org.opensearch.action.ActionRequestValidationException) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) BasicHttpResponse(org.apache.http.message.BasicHttpResponse) XContentHelper.toXContent(org.opensearch.common.xcontent.XContentHelper.toXContent) SearchScrollRequest(org.opensearch.action.search.SearchScrollRequest) SocketTimeoutException(java.net.SocketTimeoutException) ClearScrollResponse(org.opensearch.action.search.ClearScrollResponse) SearchResponse(org.opensearch.action.search.SearchResponse) ClientYamlSuiteRestApi(org.opensearch.test.rest.yaml.restspec.ClientYamlSuiteRestApi) MainRequest(org.opensearch.client.core.MainRequest) Before(org.junit.Before) MatrixStatsAggregationBuilder(org.opensearch.search.aggregations.matrix.stats.MatrixStatsAggregationBuilder) BasicRequestLine(org.apache.http.message.BasicRequestLine) Matchers(org.hamcrest.Matchers) IOException(java.io.IOException) Mockito.times(org.mockito.Mockito.times) Mockito.when(org.mockito.Mockito.when) Mockito.verify(org.mockito.Mockito.verify) XContentBuilder(org.opensearch.common.xcontent.XContentBuilder) DiscountedCumulativeGain(org.opensearch.index.rankeval.DiscountedCumulativeGain) ProtocolVersion(org.apache.http.ProtocolVersion) Sets(org.opensearch.common.util.set.Sets) SearchResponseSections(org.opensearch.action.search.SearchResponseSections) Suggest(org.opensearch.search.suggest.Suggest) ClearScrollRequest(org.opensearch.action.search.ClearScrollRequest) ShardSearchFailure(org.opensearch.action.search.ShardSearchFailure) NamedXContentRegistry(org.opensearch.common.xcontent.NamedXContentRegistry) HttpResponse(org.apache.http.HttpResponse) HttpHost(org.apache.http.HttpHost) Collections(java.util.Collections) Set(java.util.Set) HashSet(java.util.HashSet) Method(java.lang.reflect.Method) ClientYamlSuiteRestSpec(org.opensearch.test.rest.yaml.restspec.ClientYamlSuiteRestSpec) Map(java.util.Map) HashMap(java.util.HashMap) Tuple(org.opensearch.common.collect.Tuple) HashSet(java.util.HashSet)

Example 2 with ClientYamlSuiteRestApi

use of org.opensearch.test.rest.yaml.restspec.ClientYamlSuiteRestApi in project OpenSearch by opensearch-project.

the class ClientYamlTestClient method callApi.

/**
 * Calls an api with the provided parameters and body
 */
public ClientYamlTestResponse callApi(String apiName, Map<String, String> params, HttpEntity entity, Map<String, String> headers, NodeSelector nodeSelector) throws IOException {
    ClientYamlSuiteRestApi restApi = restApi(apiName);
    Set<String> apiRequiredParameters = restApi.getParams().entrySet().stream().filter(Entry::getValue).map(Entry::getKey).collect(Collectors.toSet());
    List<ClientYamlSuiteRestApi.Path> bestPaths = restApi.getBestMatchingPaths(params.keySet());
    // the rest path to use is randomized out of the matching ones (if more than one)
    ClientYamlSuiteRestApi.Path path = RandomizedTest.randomFrom(bestPaths);
    // divide params between ones that go within query string and ones that go within path
    Map<String, String> pathParts = new HashMap<>();
    Map<String, String> queryStringParams = new HashMap<>();
    for (Map.Entry<String, String> entry : params.entrySet()) {
        if (path.getParts().contains(entry.getKey())) {
            pathParts.put(entry.getKey(), entry.getValue());
        } else if (restApi.getParams().containsKey(entry.getKey()) || restSpec.isGlobalParameter(entry.getKey()) || restSpec.isClientParameter(entry.getKey())) {
            queryStringParams.put(entry.getKey(), entry.getValue());
            apiRequiredParameters.remove(entry.getKey());
        } else {
            throw new IllegalArgumentException("path/param [" + entry.getKey() + "] not supported by [" + restApi.getName() + "] " + "api");
        }
    }
    if (false == apiRequiredParameters.isEmpty()) {
        throw new IllegalArgumentException("missing required parameter: " + apiRequiredParameters + " by [" + restApi.getName() + "] api");
    }
    Set<String> partNames = pathParts.keySet();
    if (path.getParts().size() != partNames.size() || path.getParts().containsAll(partNames) == false) {
        throw new IllegalStateException("provided path parts don't match the best matching path: " + path.getParts() + " - " + partNames);
    }
    String finalPath = path.getPath();
    for (Entry<String, String> pathPart : pathParts.entrySet()) {
        try {
            // Encode rules for path and query string parameters are different. We use URI to encode the path. We need to encode each
            // path part separately, as each one might contain slashes that need to be escaped, which needs to be done manually.
            // We prepend "/" to the path part to handle parts that start with - or other invalid characters.
            URI uri = new URI(null, null, null, -1, "/" + pathPart.getValue(), null, null);
            // manually escape any slash that each part may contain
            String encodedPathPart = uri.getRawPath().substring(1).replaceAll("/", "%2F");
            finalPath = finalPath.replace("{" + pathPart.getKey() + "}", encodedPathPart);
        } catch (URISyntaxException e) {
            throw new RuntimeException("unable to build uri", e);
        }
    }
    List<String> supportedMethods = Arrays.asList(path.getMethods());
    String requestMethod;
    if (entity != null) {
        if (false == restApi.isBodySupported()) {
            throw new IllegalArgumentException("body is not supported by [" + restApi.getName() + "] api");
        }
        String contentType = entity.getContentType().getValue();
        // randomly test the GET with source param instead of GET/POST with body
        if (sendBodyAsSourceParam(supportedMethods, contentType, entity.getContentLength())) {
            logger.debug("sending the request body as source param with GET method");
            queryStringParams.put("source", EntityUtils.toString(entity));
            queryStringParams.put("source_content_type", contentType);
            requestMethod = HttpGet.METHOD_NAME;
            entity = null;
        } else {
            requestMethod = RandomizedTest.randomFrom(supportedMethods);
        }
    } else {
        if (restApi.isBodyRequired()) {
            throw new IllegalArgumentException("body is required by [" + restApi.getName() + "] api");
        }
        requestMethod = RandomizedTest.randomFrom(supportedMethods);
    }
    logger.debug("calling api [{}]", apiName);
    Request request = new Request(requestMethod, finalPath);
    for (Map.Entry<String, String> param : queryStringParams.entrySet()) {
        request.addParameter(param.getKey(), param.getValue());
    }
    request.setEntity(entity);
    setOptions(request, headers);
    try {
        Response response = getRestClient(nodeSelector).performRequest(request);
        return new ClientYamlTestResponse(response);
    } catch (ResponseException e) {
        throw new ClientYamlTestResponseException(e);
    }
}
Also used : HashMap(java.util.HashMap) ResponseException(org.opensearch.client.ResponseException) Request(org.opensearch.client.Request) URISyntaxException(java.net.URISyntaxException) URI(java.net.URI) Response(org.opensearch.client.Response) ClientYamlSuiteRestApi(org.opensearch.test.rest.yaml.restspec.ClientYamlSuiteRestApi) Entry(java.util.Map.Entry) HashMap(java.util.HashMap) Map(java.util.Map)

Aggregations

HashMap (java.util.HashMap)2 Map (java.util.Map)2 ClientYamlSuiteRestApi (org.opensearch.test.rest.yaml.restspec.ClientYamlSuiteRestApi)2 JsonParseException (com.fasterxml.jackson.core.JsonParseException)1 IOException (java.io.IOException)1 Method (java.lang.reflect.Method)1 Modifier (java.lang.reflect.Modifier)1 SocketTimeoutException (java.net.SocketTimeoutException)1 URI (java.net.URI)1 URISyntaxException (java.net.URISyntaxException)1 ArrayList (java.util.ArrayList)1 Arrays (java.util.Arrays)1 Collections (java.util.Collections)1 HashSet (java.util.HashSet)1 List (java.util.List)1 Entry (java.util.Map.Entry)1 Optional (java.util.Optional)1 Set (java.util.Set)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1