Allow unstashing values into keys (#24685)
This is almost exclusively for docs test which frequently match the entire response. This allow something like: ``` - set: {nodes.$master.http.publish_address: host} - match: $body: { "nodes": { $host: { ... stuff in here ... } } } ``` This should make it possible for the docs tests to work with unpredictable keys.
This commit is contained in:
parent
788d8c1ddc
commit
c38b3360b6
|
@ -167,6 +167,7 @@ public class RestTestsFromSnippetsTask extends SnippetsTask {
|
|||
* warning every time. */
|
||||
current.println(" - skip:")
|
||||
current.println(" features: ")
|
||||
current.println(" - stash_in_key")
|
||||
current.println(" - warnings")
|
||||
}
|
||||
if (test.skipTest) {
|
||||
|
|
|
@ -39,6 +39,7 @@ public final class Features {
|
|||
"catch_unauthorized",
|
||||
"embedded_stash_key",
|
||||
"headers",
|
||||
"stash_in_key",
|
||||
"stash_in_path",
|
||||
"warnings",
|
||||
"yaml"));
|
||||
|
|
|
@ -26,9 +26,11 @@ import org.elasticsearch.common.xcontent.ToXContent;
|
|||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -121,35 +123,46 @@ public class Stash implements ToXContent {
|
|||
* Goes recursively against each map entry and replaces any string value starting with "$" with its
|
||||
* corresponding value retrieved from the stash
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // Safe because we check that all the map keys are string in unstashObject
|
||||
public Map<String, Object> replaceStashedValues(Map<String, Object> map) throws IOException {
|
||||
Map<String, Object> copy = new HashMap<>(map);
|
||||
unstashObject(copy);
|
||||
return copy;
|
||||
return (Map<String, Object>) unstashObject(map);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void unstashObject(Object obj) throws IOException {
|
||||
private Object unstashObject(Object obj) throws IOException {
|
||||
if (obj instanceof List) {
|
||||
List list = (List) obj;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Object o = list.get(i);
|
||||
List<?> list = (List<?>) obj;
|
||||
List<Object> result = new ArrayList<>();
|
||||
for (Object o : list) {
|
||||
if (containsStashedValue(o)) {
|
||||
list.set(i, getValue(o.toString()));
|
||||
result.add(getValue(o.toString()));
|
||||
} else {
|
||||
unstashObject(o);
|
||||
result.add(unstashObject(o));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (obj instanceof Map) {
|
||||
Map<String, Object> map = (Map) obj;
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
if (containsStashedValue(entry.getValue())) {
|
||||
entry.setValue(getValue(entry.getValue().toString()));
|
||||
Map<?, ?> map = (Map<?, ?>) obj;
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
String key = (String) entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if (containsStashedValue(key)) {
|
||||
key = getValue(key).toString();
|
||||
}
|
||||
if (containsStashedValue(value)) {
|
||||
value = getValue(value.toString());
|
||||
} else {
|
||||
unstashObject(entry.getValue());
|
||||
value = unstashObject(value);
|
||||
}
|
||||
if (null != result.putIfAbsent(key, value)) {
|
||||
throw new IllegalArgumentException("Unstashing has caused a key conflict! The map is [" + result + "] and the key is ["
|
||||
+ entry.getKey() + "] which unstashes to [" + key + "]");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,27 +20,101 @@
|
|||
package org.elasticsearch.test.rest.yaml;
|
||||
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.rest.yaml.Stash;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
|
||||
public class StashTests extends ESTestCase {
|
||||
public void testReplaceStashedValuesEmbeddedStashKey() throws IOException {
|
||||
public void testReplaceStashedValuesStashKeyInMapValue() throws IOException {
|
||||
Stash stash = new Stash();
|
||||
stash.stashValue("stashed", "bar");
|
||||
|
||||
Map<String, Object> expected = new HashMap<>();
|
||||
expected.put("key", singletonMap("a", "foobar"));
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
Map<String, Object> map2 = new HashMap<>();
|
||||
if (randomBoolean()) {
|
||||
stash.stashValue("stashed", "bar");
|
||||
map2.put("a", "foo${stashed}");
|
||||
} else {
|
||||
stash.stashValue("stashed", "foobar");
|
||||
map2.put("a", "$stashed");
|
||||
}
|
||||
map.put("key", map2);
|
||||
|
||||
Map<String, Object> actual = stash.replaceStashedValues(map);
|
||||
assertEquals(expected, actual);
|
||||
assertThat(actual, not(sameInstance(map)));
|
||||
}
|
||||
|
||||
public void testReplaceStashedValuesStashKeyInMapKey() throws IOException {
|
||||
Stash stash = new Stash();
|
||||
|
||||
Map<String, Object> expected = new HashMap<>();
|
||||
expected.put("key", singletonMap("foobar", "a"));
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
Map<String, Object> map2 = new HashMap<>();
|
||||
if (randomBoolean()) {
|
||||
stash.stashValue("stashed", "bar");
|
||||
map2.put("foo${stashed}", "a");
|
||||
} else {
|
||||
stash.stashValue("stashed", "foobar");
|
||||
map2.put("$stashed", "a");
|
||||
}
|
||||
map.put("key", map2);
|
||||
|
||||
Map<String, Object> actual = stash.replaceStashedValues(map);
|
||||
assertEquals(expected, actual);
|
||||
assertThat(actual, not(sameInstance(map)));
|
||||
}
|
||||
|
||||
public void testReplaceStashedValuesStashKeyInMapKeyConflicts() throws IOException {
|
||||
Stash stash = new Stash();
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
Map<String, Object> map2 = new HashMap<>();
|
||||
String key;
|
||||
if (randomBoolean()) {
|
||||
stash.stashValue("stashed", "bar");
|
||||
key = "foo${stashed}";
|
||||
} else {
|
||||
stash.stashValue("stashed", "foobar");
|
||||
key = "$stashed";
|
||||
}
|
||||
map2.put(key, "a");
|
||||
map2.put("foobar", "whatever");
|
||||
map.put("key", map2);
|
||||
|
||||
Exception e = expectThrows(IllegalArgumentException.class, () -> stash.replaceStashedValues(map));
|
||||
assertEquals(e.getMessage(), "Unstashing has caused a key conflict! The map is [{foobar=whatever}] and the key is ["
|
||||
+ key + "] which unstashes to [foobar]");
|
||||
}
|
||||
|
||||
|
||||
public void testReplaceStashedValuesStashKeyInList() throws IOException {
|
||||
Stash stash = new Stash();
|
||||
stash.stashValue("stashed", "bar");
|
||||
|
||||
Map<String, Object> expected = new HashMap<>();
|
||||
expected.put("key", Arrays.asList("foot", "foobar", 1));
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
Object value;
|
||||
if (randomBoolean()) {
|
||||
stash.stashValue("stashed", "bar");
|
||||
value = "foo${stashed}";
|
||||
} else {
|
||||
stash.stashValue("stashed", "foobar");
|
||||
value = "$stashed";
|
||||
}
|
||||
map.put("key", Arrays.asList("foot", value, 1));
|
||||
|
||||
Map<String, Object> actual = stash.replaceStashedValues(map);
|
||||
assertEquals(expected, actual);
|
||||
assertThat(actual, not(sameInstance(map)));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue