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));
}
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);
}
}
Aggregations