Skip to content

Commit 487b540

Browse files
tvernumalpar-t
andauthored
Rest Tests - Support for matching objects in lists (#34693)
Makes it possible to have a key that points to a list and assert that a certain object is present in the list. All keys have to be present and values have to match. The objects in the source list may have additional fields. example: ``` contains: { 'nodes.$master.plugins': { name: ingest-attachment } } ``` Backported from #30874 (e8b8d11) Co-authored-by: Alpar Torok <[email protected]>
1 parent 69449a0 commit 487b540

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.elasticsearch.test.rest.yaml.section;
20+
21+
import org.apache.logging.log4j.Logger;
22+
import org.elasticsearch.common.collect.Tuple;
23+
import org.elasticsearch.common.logging.Loggers;
24+
import org.elasticsearch.common.xcontent.XContentLocation;
25+
import org.elasticsearch.common.xcontent.XContentParser;
26+
27+
import java.io.IOException;
28+
import java.util.List;
29+
import java.util.Map;
30+
import java.util.stream.Collectors;
31+
32+
import static org.hamcrest.Matchers.empty;
33+
import static org.hamcrest.Matchers.is;
34+
import static org.hamcrest.Matchers.not;
35+
import static org.junit.Assert.assertThat;
36+
import static org.junit.Assert.assertTrue;
37+
import static org.junit.Assert.fail;
38+
39+
public class ContainsAssertion extends Assertion {
40+
public static ContainsAssertion parse(XContentParser parser) throws IOException {
41+
XContentLocation location = parser.getTokenLocation();
42+
Tuple<String, Object> stringObjectTuple = ParserUtils.parseTuple(parser);
43+
return new ContainsAssertion(location, stringObjectTuple.v1(), stringObjectTuple.v2());
44+
}
45+
46+
private static final Logger logger = Loggers.getLogger(ContainsAssertion.class);
47+
48+
public ContainsAssertion(XContentLocation location, String field, Object expectedValue) {
49+
super(location, field, expectedValue);
50+
}
51+
52+
@Override
53+
protected void doAssert(Object actualValue, Object expectedValue) {
54+
// add support for matching objects ({a:b}) against list of objects ([ {a:b, c:d} ])
55+
if (expectedValue instanceof Map && actualValue instanceof List) {
56+
logger.trace("assert that [{}] contains [{}]", actualValue, expectedValue);
57+
Map<String, Object> expectedMap = (Map<String, Object>) expectedValue;
58+
List<Object> actualList = (List<Object>) actualValue;
59+
List<Map<String, Object>> actualValues = actualList.stream()
60+
.filter(each -> each instanceof Map)
61+
.map((each -> (Map<String, Object>) each))
62+
.filter(each -> each.keySet().containsAll(expectedMap.keySet()))
63+
.collect(Collectors.toList());
64+
assertThat(
65+
getField() + " expected to be a list with at least one object that has keys: " +
66+
expectedMap.keySet() + " but it was " + actualList,
67+
actualValues,
68+
is(not(empty()))
69+
);
70+
assertTrue(
71+
getField() + " expected to be a list with at least on object that matches " + expectedMap +
72+
" but was " + actualValues,
73+
actualValues.stream()
74+
.anyMatch(each -> each.entrySet().containsAll(expectedMap.entrySet()))
75+
);
76+
} else {
77+
fail("'contains' only supports checking an object against a list of objects");
78+
}
79+
}
80+
}

test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/ExecutableSection.java

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public interface ExecutableSection {
4747
new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("gte"), GreaterThanEqualToAssertion::parse),
4848
new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("lt"), LessThanAssertion::parse),
4949
new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("lte"), LessThanOrEqualToAssertion::parse),
50+
new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("contains"), ContainsAssertion::parse),
5051
new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("length"), LengthAssertion::parse)));
5152

5253
/**

test/framework/src/test/java/org/elasticsearch/test/rest/yaml/section/AssertionTests.java

+16
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,22 @@ public void testParseMatchArray() throws Exception {
134134
assertThat(strings.get(1).toString(), equalTo("test_percolator_2"));
135135
}
136136

137+
@SuppressWarnings("unchecked")
138+
public void testParseContains() throws Exception {
139+
parser = createParser(YamlXContent.yamlXContent,
140+
"{testKey: { someKey: someValue } }"
141+
);
142+
143+
ContainsAssertion containsAssertion = ContainsAssertion.parse(parser);
144+
assertThat(containsAssertion, notNullValue());
145+
assertThat(containsAssertion.getField(), equalTo("testKey"));
146+
assertThat(containsAssertion.getExpectedValue(), instanceOf(Map.class));
147+
assertThat(
148+
((Map<String, String>) containsAssertion.getExpectedValue()).get("someKey"),
149+
equalTo("someValue")
150+
);
151+
}
152+
137153
@SuppressWarnings("unchecked")
138154
public void testParseMatchSourceValues() throws Exception {
139155
parser = createParser(YamlXContent.yamlXContent,

0 commit comments

Comments
 (0)