Skip to content

Commit

Permalink
[REST tests] Randomized REST path chosen if more than one is availabl…
Browse files Browse the repository at this point in the history
…e with current parameters

Previously we would always take the same path if more than one was available
  • Loading branch information
javanna authored and brusic committed Jan 19, 2014
1 parent 9a10b13 commit 1802c4b
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ private HttpRequestBuilder callApiBuilder(String apiName, Map<String, String> pa

//the http method is randomized (out of the available ones with the chosen api)
return httpRequestBuilder.method(RandomizedTest.randomFrom(restApi.getSupportedMethods(pathParts.keySet())))
.path(restApi.getFinalPath(pathParts));
.path(RandomizedTest.randomFrom(restApi.getFinalPaths(pathParts)));
}

private RestApi restApi(String apiName) {
Expand Down
65 changes: 27 additions & 38 deletions src/test/java/org/elasticsearch/test/rest/spec/RestApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import com.google.common.collect.Maps;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.lucene.util.PriorityQueue;

import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -117,60 +116,50 @@ void addPathPart(String pathPart) {
* Finds the best matching rest path given the current parameters and replaces
* placeholders with their corresponding values received as arguments
*/
public String getFinalPath(Map<String, String> pathParams) {
RestPath matchingRestPath = findMatchingRestPath(pathParams.keySet());
String path = matchingRestPath.path;
for (Map.Entry<String, String> paramEntry : matchingRestPath.params.entrySet()) {
// replace path placeholders with actual values
String value = pathParams.get(paramEntry.getValue());
if (value == null) {
// if a value is missing, we got the wrong path or the test was
// specified incorrectly
// TODO: What if more than one path exists? for example: PUT
// index/type/_mapping vs. PUT index/_maping/type? Should we
// randomize?
throw new IllegalArgumentException("parameter [" + paramEntry.getValue() + "] missing");
} else {
public String[] getFinalPaths(Map<String, String> pathParams) {

List<RestPath> matchingRestPaths = findMatchingRestPaths(pathParams.keySet());
if (matchingRestPaths == null || matchingRestPaths.isEmpty()) {
throw new IllegalArgumentException("unable to find matching rest path for api [" + name + "] and params " + pathParams);
}

String[] paths = new String[matchingRestPaths.size()];
for (int i = 0; i < matchingRestPaths.size(); i++) {
RestPath restPath = matchingRestPaths.get(i);
String path = restPath.path;
for (Map.Entry<String, String> paramEntry : restPath.params.entrySet()) {
// replace path placeholders with actual values
String value = pathParams.get(paramEntry.getValue());
if (value == null) {
throw new IllegalArgumentException("parameter [" + paramEntry.getValue() + "] missing");
}
path = path.replace(paramEntry.getKey(), value);
}
paths[i] = path;
}
return path;
return paths;
}

/**
* Finds the best matching rest path out of the available ones with the current api (based on REST spec).
* Finds the matching rest paths out of the available ones with the current api (based on REST spec).
*
* The best path is the one that has exactly the same number of placeholders to replace
* (e.g. /{index}/{type}/{id} when the params are exactly index, type and id).
* Otherwise there might be additional placeholders, thus we use the path with the least additional placeholders.
* (e.g. get with only index and id as parameters, the closest (and only) path contains {type} too, which becomes _all)
*/
private RestPath findMatchingRestPath(Set<String> restParams) {
private List<RestPath> findMatchingRestPaths(Set<String> restParams) {

List<RestPath> matchingRestPaths = Lists.newArrayList();
RestPath[] restPaths = buildRestPaths();

//We need to find the path that has exactly the placeholders corresponding to our params
//If there's no exact match we fallback to the closest one (with as less additional placeholders as possible)
//The fallback is needed for:
//1) get, get_source and exists with only index and id => /{index}/_all/{id} (
//2) search with only type => /_all/{type/_search
PriorityQueue<RestPath> restPathQueue = new PriorityQueue<RestPath>(1) {
@Override
protected boolean lessThan(RestPath a, RestPath b) {
return a.params.size() >= b.params.size();
}
};
for (RestPath restPath : restPaths) {
if (restPath.params.values().containsAll(restParams)) {
restPathQueue.insertWithOverflow(restPath);
if (restPath.params.size() == restParams.size()) {
if (restPath.params.values().containsAll(restParams)) {
matchingRestPaths.add(restPath);
}
}
}

if (restPathQueue.size() > 0) {
return restPathQueue.top();
}

throw new IllegalArgumentException("unable to find best path for api [" + name + "] and params " + restParams);
return matchingRestPaths;
}

private RestPath[] buildRestPaths() {
Expand Down

0 comments on commit 1802c4b

Please sign in to comment.