Add embedded stash key support to rest tests

This allowes embedding stash keys in string like `t${key}est`. This
allows simple string concatenation like acitons.

The test for this is in `ObjectPathTests` because `Stash` doesn't seem
to have a test on its own and it is simple enough to test embedded
stashes this way. And this is a way I expect them to be used eventually.
This commit is contained in:
Nik Everett 2016-07-01 12:18:47 -04:00
parent 01d7020ee3
commit ff42d7cfc6
6 changed files with 68 additions and 11 deletions

View File

@ -70,7 +70,7 @@ public class ObjectPath {
@SuppressWarnings("unchecked")
private Object evaluate(String key, Object object, Stash stash) throws IOException {
if (stash.isStashedValue(key)) {
if (stash.containsStashedValue(key)) {
key = stash.getValue(key).toString();
}

View File

@ -66,7 +66,7 @@ public class RestTestExecutionContext implements Closeable {
//makes a copy of the parameters before modifying them for this specific request
HashMap<String, String> requestParams = new HashMap<>(params);
for (Map.Entry<String, String> entry : requestParams.entrySet()) {
if (stash.isStashedValue(entry.getValue())) {
if (stash.containsStashedValue(entry.getValue())) {
entry.setValue(stash.getValue(entry.getValue()).toString());
}
}

View File

@ -29,12 +29,15 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Allows to cache the last obtained test response and or part of it within variables
* that can be used as input values in following requests and assertions.
*/
public class Stash implements ToXContent {
private static final Pattern EXTENDED_KEY = Pattern.compile("\\$\\{([^}]+)\\}");
private static final ESLogger logger = Loggers.getLogger(Stash.class);
@ -67,12 +70,18 @@ public class Stash implements ToXContent {
* The stash contains fields eventually extracted from previous responses that can be reused
* as arguments for following requests (e.g. scroll_id)
*/
public boolean isStashedValue(Object key) {
public boolean containsStashedValue(Object key) {
if (key == null) {
return false;
}
String stashKey = key.toString();
return Strings.hasLength(stashKey) && stashKey.startsWith("$");
if (false == Strings.hasLength(stashKey)) {
return false;
}
if (stashKey.startsWith("$")) {
return true;
}
return EXTENDED_KEY.matcher(stashKey).find();
}
/**
@ -81,7 +90,27 @@ public class Stash implements ToXContent {
* as arguments for following requests (e.g. scroll_id)
*/
public Object getValue(String key) throws IOException {
Object stashedValue = stashObjectPath.evaluate(key.substring(1));
if (key.charAt(0) == '$' && key.charAt(1) != '{') {
return unstash(key.substring(1));
}
Matcher matcher = EXTENDED_KEY.matcher(key);
/*
* String*Buffer* because that is what the Matcher API takes. In modern versions of java the uncontended synchronization is very,
* very cheap so that should be a problem.
*/
StringBuffer result = new StringBuffer(key.length());
if (false == matcher.find()) {
throw new IllegalArgumentException("Doesn't contain any stash keys [" + key + "]");
}
do {
matcher.appendReplacement(result, Matcher.quoteReplacement(unstash(matcher.group(1)).toString()));
} while (matcher.find());
matcher.appendTail(result);
return result.toString();
}
private Object unstash(String key) throws IOException {
Object stashedValue = stashObjectPath.evaluate(key);
if (stashedValue == null) {
throw new IllegalArgumentException("stashed value not found for key [" + key + "]");
}
@ -104,7 +133,7 @@ public class Stash implements ToXContent {
List list = (List) obj;
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
if (isStashedValue(o)) {
if (containsStashedValue(o)) {
list.set(i, getValue(o.toString()));
} else {
unstashObject(o);
@ -114,7 +143,7 @@ public class Stash implements ToXContent {
if (obj instanceof Map) {
Map<String, Object> map = (Map) obj;
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (isStashedValue(entry.getValue())) {
if (containsStashedValue(entry.getValue())) {
entry.setValue(getValue(entry.getValue().toString()));
} else {
unstashObject(entry.getValue());

View File

@ -51,14 +51,14 @@ public abstract class Assertion implements ExecutableSection {
return executionContext.stash().replaceStashedValues(map);
}
if (executionContext.stash().isStashedValue(expectedValue)) {
if (executionContext.stash().containsStashedValue(expectedValue)) {
return executionContext.stash().getValue(expectedValue.toString());
}
return expectedValue;
}
protected final Object getActualValue(RestTestExecutionContext executionContext) throws IOException {
if (executionContext.stash().isStashedValue(field)) {
if (executionContext.stash().containsStashedValue(field)) {
return executionContext.stash().getValue(field);
}
return executionContext.response(field);

View File

@ -34,7 +34,7 @@ import java.util.List;
*/
public final class Features {
private static final List<String> SUPPORTED = Arrays.asList("stash_in_path", "groovy_scripting", "headers");
private static final List<String> SUPPORTED = Arrays.asList("stash_in_path", "groovy_scripting", "headers", "embedded_stash_key");
private Features() {

View File

@ -190,21 +190,49 @@ public class ObjectPathTests extends ESTestCase {
objectPath.evaluate("field1.$placeholder.element1");
fail("evaluate should have failed due to unresolved placeholder");
} catch(IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("stashed value not found for key [$placeholder]"));
assertThat(e.getMessage(), containsString("stashed value not found for key [placeholder]"));
}
// Stashed value is whole property name
Stash stash = new Stash();
stash.stashValue("placeholder", "elements");
Object object = objectPath.evaluate("field1.$placeholder.element1", stash);
assertThat(object, notNullValue());
assertThat(object.toString(), equalTo("value1"));
// Stash key has dots
Map<String, Object> stashedObject = new HashMap<>();
stashedObject.put("subobject", "elements");
stash.stashValue("object", stashedObject);
object = objectPath.evaluate("field1.$object\\.subobject.element1", stash);
assertThat(object, notNullValue());
assertThat(object.toString(), equalTo("value1"));
// Stashed value is part of property name
stash.stashValue("placeholder", "ele");
object = objectPath.evaluate("field1.${placeholder}ments.element1", stash);
assertThat(object, notNullValue());
assertThat(object.toString(), equalTo("value1"));
// Stashed value is inside of property name
stash.stashValue("placeholder", "le");
object = objectPath.evaluate("field1.e${placeholder}ments.element1", stash);
assertThat(object, notNullValue());
assertThat(object.toString(), equalTo("value1"));
// Multiple stashed values in property name
stash.stashValue("placeholder", "le");
stash.stashValue("placeholder2", "nts");
object = objectPath.evaluate("field1.e${placeholder}me${placeholder2}.element1", stash);
assertThat(object, notNullValue());
assertThat(object.toString(), equalTo("value1"));
// Stashed value is part of property name and has dots
stashedObject.put("subobject", "ele");
stash.stashValue("object", stashedObject);
object = objectPath.evaluate("field1.${object\\.subobject}ments.element1", stash);
assertThat(object, notNullValue());
assertThat(object.toString(), equalTo("value1"));
}
@SuppressWarnings("unchecked")