Skip to content

Commit ff42d7c

Browse files
committed
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.
1 parent 01d7020 commit ff42d7c

File tree

6 files changed

+68
-11
lines changed

6 files changed

+68
-11
lines changed

test/framework/src/main/java/org/elasticsearch/test/rest/ObjectPath.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public Object evaluate(String path, Stash stash) throws IOException {
7070

7171
@SuppressWarnings("unchecked")
7272
private Object evaluate(String key, Object object, Stash stash) throws IOException {
73-
if (stash.isStashedValue(key)) {
73+
if (stash.containsStashedValue(key)) {
7474
key = stash.getValue(key).toString();
7575
}
7676

test/framework/src/main/java/org/elasticsearch/test/rest/RestTestExecutionContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public RestTestResponse callApi(String apiName, Map<String, String> params, List
6666
//makes a copy of the parameters before modifying them for this specific request
6767
HashMap<String, String> requestParams = new HashMap<>(params);
6868
for (Map.Entry<String, String> entry : requestParams.entrySet()) {
69-
if (stash.isStashedValue(entry.getValue())) {
69+
if (stash.containsStashedValue(entry.getValue())) {
7070
entry.setValue(stash.getValue(entry.getValue()).toString());
7171
}
7272
}

test/framework/src/main/java/org/elasticsearch/test/rest/Stash.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@
2929
import java.util.HashMap;
3030
import java.util.List;
3131
import java.util.Map;
32+
import java.util.regex.Matcher;
33+
import java.util.regex.Pattern;
3234

3335
/**
3436
* Allows to cache the last obtained test response and or part of it within variables
3537
* that can be used as input values in following requests and assertions.
3638
*/
3739
public class Stash implements ToXContent {
40+
private static final Pattern EXTENDED_KEY = Pattern.compile("\\$\\{([^}]+)\\}");
3841

3942
private static final ESLogger logger = Loggers.getLogger(Stash.class);
4043

@@ -67,12 +70,18 @@ public void clear() {
6770
* The stash contains fields eventually extracted from previous responses that can be reused
6871
* as arguments for following requests (e.g. scroll_id)
6972
*/
70-
public boolean isStashedValue(Object key) {
73+
public boolean containsStashedValue(Object key) {
7174
if (key == null) {
7275
return false;
7376
}
7477
String stashKey = key.toString();
75-
return Strings.hasLength(stashKey) && stashKey.startsWith("$");
78+
if (false == Strings.hasLength(stashKey)) {
79+
return false;
80+
}
81+
if (stashKey.startsWith("$")) {
82+
return true;
83+
}
84+
return EXTENDED_KEY.matcher(stashKey).find();
7685
}
7786

7887
/**
@@ -81,7 +90,27 @@ public boolean isStashedValue(Object key) {
8190
* as arguments for following requests (e.g. scroll_id)
8291
*/
8392
public Object getValue(String key) throws IOException {
84-
Object stashedValue = stashObjectPath.evaluate(key.substring(1));
93+
if (key.charAt(0) == '$' && key.charAt(1) != '{') {
94+
return unstash(key.substring(1));
95+
}
96+
Matcher matcher = EXTENDED_KEY.matcher(key);
97+
/*
98+
* String*Buffer* because that is what the Matcher API takes. In modern versions of java the uncontended synchronization is very,
99+
* very cheap so that should be a problem.
100+
*/
101+
StringBuffer result = new StringBuffer(key.length());
102+
if (false == matcher.find()) {
103+
throw new IllegalArgumentException("Doesn't contain any stash keys [" + key + "]");
104+
}
105+
do {
106+
matcher.appendReplacement(result, Matcher.quoteReplacement(unstash(matcher.group(1)).toString()));
107+
} while (matcher.find());
108+
matcher.appendTail(result);
109+
return result.toString();
110+
}
111+
112+
private Object unstash(String key) throws IOException {
113+
Object stashedValue = stashObjectPath.evaluate(key);
85114
if (stashedValue == null) {
86115
throw new IllegalArgumentException("stashed value not found for key [" + key + "]");
87116
}
@@ -104,7 +133,7 @@ private void unstashObject(Object obj) throws IOException {
104133
List list = (List) obj;
105134
for (int i = 0; i < list.size(); i++) {
106135
Object o = list.get(i);
107-
if (isStashedValue(o)) {
136+
if (containsStashedValue(o)) {
108137
list.set(i, getValue(o.toString()));
109138
} else {
110139
unstashObject(o);
@@ -114,7 +143,7 @@ private void unstashObject(Object obj) throws IOException {
114143
if (obj instanceof Map) {
115144
Map<String, Object> map = (Map) obj;
116145
for (Map.Entry<String, Object> entry : map.entrySet()) {
117-
if (isStashedValue(entry.getValue())) {
146+
if (containsStashedValue(entry.getValue())) {
118147
entry.setValue(getValue(entry.getValue().toString()));
119148
} else {
120149
unstashObject(entry.getValue());

test/framework/src/main/java/org/elasticsearch/test/rest/section/Assertion.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ protected final Object resolveExpectedValue(RestTestExecutionContext executionCo
5151
return executionContext.stash().replaceStashedValues(map);
5252
}
5353

54-
if (executionContext.stash().isStashedValue(expectedValue)) {
54+
if (executionContext.stash().containsStashedValue(expectedValue)) {
5555
return executionContext.stash().getValue(expectedValue.toString());
5656
}
5757
return expectedValue;
5858
}
5959

6060
protected final Object getActualValue(RestTestExecutionContext executionContext) throws IOException {
61-
if (executionContext.stash().isStashedValue(field)) {
61+
if (executionContext.stash().containsStashedValue(field)) {
6262
return executionContext.stash().getValue(field);
6363
}
6464
return executionContext.response(field);

test/framework/src/main/java/org/elasticsearch/test/rest/support/Features.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
*/
3535
public final class Features {
3636

37-
private static final List<String> SUPPORTED = Arrays.asList("stash_in_path", "groovy_scripting", "headers");
37+
private static final List<String> SUPPORTED = Arrays.asList("stash_in_path", "groovy_scripting", "headers", "embedded_stash_key");
3838

3939
private Features() {
4040

test/framework/src/test/java/org/elasticsearch/test/rest/test/ObjectPathTests.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,21 +190,49 @@ public void testEvaluateStashInPropertyName() throws Exception {
190190
objectPath.evaluate("field1.$placeholder.element1");
191191
fail("evaluate should have failed due to unresolved placeholder");
192192
} catch(IllegalArgumentException e) {
193-
assertThat(e.getMessage(), containsString("stashed value not found for key [$placeholder]"));
193+
assertThat(e.getMessage(), containsString("stashed value not found for key [placeholder]"));
194194
}
195195

196+
// Stashed value is whole property name
196197
Stash stash = new Stash();
197198
stash.stashValue("placeholder", "elements");
198199
Object object = objectPath.evaluate("field1.$placeholder.element1", stash);
199200
assertThat(object, notNullValue());
200201
assertThat(object.toString(), equalTo("value1"));
201202

203+
// Stash key has dots
202204
Map<String, Object> stashedObject = new HashMap<>();
203205
stashedObject.put("subobject", "elements");
204206
stash.stashValue("object", stashedObject);
205207
object = objectPath.evaluate("field1.$object\\.subobject.element1", stash);
206208
assertThat(object, notNullValue());
207209
assertThat(object.toString(), equalTo("value1"));
210+
211+
// Stashed value is part of property name
212+
stash.stashValue("placeholder", "ele");
213+
object = objectPath.evaluate("field1.${placeholder}ments.element1", stash);
214+
assertThat(object, notNullValue());
215+
assertThat(object.toString(), equalTo("value1"));
216+
217+
// Stashed value is inside of property name
218+
stash.stashValue("placeholder", "le");
219+
object = objectPath.evaluate("field1.e${placeholder}ments.element1", stash);
220+
assertThat(object, notNullValue());
221+
assertThat(object.toString(), equalTo("value1"));
222+
223+
// Multiple stashed values in property name
224+
stash.stashValue("placeholder", "le");
225+
stash.stashValue("placeholder2", "nts");
226+
object = objectPath.evaluate("field1.e${placeholder}me${placeholder2}.element1", stash);
227+
assertThat(object, notNullValue());
228+
assertThat(object.toString(), equalTo("value1"));
229+
230+
// Stashed value is part of property name and has dots
231+
stashedObject.put("subobject", "ele");
232+
stash.stashValue("object", stashedObject);
233+
object = objectPath.evaluate("field1.${object\\.subobject}ments.element1", stash);
234+
assertThat(object, notNullValue());
235+
assertThat(object.toString(), equalTo("value1"));
208236
}
209237

210238
@SuppressWarnings("unchecked")

0 commit comments

Comments
 (0)