Skip to content

Commit

Permalink
Rest Tests - Support for matching objects in lists (#34693)
Browse files Browse the repository at this point in the history
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 <torokalpar@gmail.com>
  • Loading branch information
tvernum and alpar-t committed Nov 1, 2018
1 parent 69449a0 commit 487b540
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.test.rest.yaml.section;

import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.xcontent.XContentLocation;
import org.elasticsearch.common.xcontent.XContentParser;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

public class ContainsAssertion extends Assertion {
public static ContainsAssertion parse(XContentParser parser) throws IOException {
XContentLocation location = parser.getTokenLocation();
Tuple<String, Object> stringObjectTuple = ParserUtils.parseTuple(parser);
return new ContainsAssertion(location, stringObjectTuple.v1(), stringObjectTuple.v2());
}

private static final Logger logger = Loggers.getLogger(ContainsAssertion.class);

public ContainsAssertion(XContentLocation location, String field, Object expectedValue) {
super(location, field, expectedValue);
}

@Override
protected void doAssert(Object actualValue, Object expectedValue) {
// add support for matching objects ({a:b}) against list of objects ([ {a:b, c:d} ])
if (expectedValue instanceof Map && actualValue instanceof List) {
logger.trace("assert that [{}] contains [{}]", actualValue, expectedValue);
Map<String, Object> expectedMap = (Map<String, Object>) expectedValue;
List<Object> actualList = (List<Object>) actualValue;
List<Map<String, Object>> actualValues = actualList.stream()
.filter(each -> each instanceof Map)
.map((each -> (Map<String, Object>) each))
.filter(each -> each.keySet().containsAll(expectedMap.keySet()))
.collect(Collectors.toList());
assertThat(
getField() + " expected to be a list with at least one object that has keys: " +
expectedMap.keySet() + " but it was " + actualList,
actualValues,
is(not(empty()))
);
assertTrue(
getField() + " expected to be a list with at least on object that matches " + expectedMap +
" but was " + actualValues,
actualValues.stream()
.anyMatch(each -> each.entrySet().containsAll(expectedMap.entrySet()))
);
} else {
fail("'contains' only supports checking an object against a list of objects");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public interface ExecutableSection {
new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("gte"), GreaterThanEqualToAssertion::parse),
new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("lt"), LessThanAssertion::parse),
new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("lte"), LessThanOrEqualToAssertion::parse),
new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("contains"), ContainsAssertion::parse),
new NamedXContentRegistry.Entry(ExecutableSection.class, new ParseField("length"), LengthAssertion::parse)));

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,22 @@ public void testParseMatchArray() throws Exception {
assertThat(strings.get(1).toString(), equalTo("test_percolator_2"));
}

@SuppressWarnings("unchecked")
public void testParseContains() throws Exception {
parser = createParser(YamlXContent.yamlXContent,
"{testKey: { someKey: someValue } }"
);

ContainsAssertion containsAssertion = ContainsAssertion.parse(parser);
assertThat(containsAssertion, notNullValue());
assertThat(containsAssertion.getField(), equalTo("testKey"));
assertThat(containsAssertion.getExpectedValue(), instanceOf(Map.class));
assertThat(
((Map<String, String>) containsAssertion.getExpectedValue()).get("someKey"),
equalTo("someValue")
);
}

@SuppressWarnings("unchecked")
public void testParseMatchSourceValues() throws Exception {
parser = createParser(YamlXContent.yamlXContent,
Expand Down

0 comments on commit 487b540

Please sign in to comment.