[TEST] Add test for Aggregations#fromXContent (#24524)

AggregationsTests#testFromXContent verifies that parsing of aggregations works by combining multiple aggs at the same level, and also adding sub-aggregations to multi bucket and single bucket aggs, up to a maximum depth of 5.
This commit is contained in:
Luca Cavanna 2017-05-09 21:08:10 +02:00 committed by GitHub
parent 1959fd6a1a
commit c5bdbecc64
10 changed files with 218 additions and 44 deletions

View File

@ -128,7 +128,6 @@ public class Aggregations implements Iterable<Aggregation>, ToXContent {
return builder;
}
//TODO add tests for this method
public static Aggregations fromXContent(XContentParser parser) throws IOException {
final List<Aggregation> aggregations = new ArrayList<>();
XContentParser.Token token;

View File

@ -0,0 +1,156 @@
/*
* 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.search.aggregations;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.action.search.RestSearchAction;
import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.bucket.histogram.InternalDateHistogramTests;
import org.elasticsearch.search.aggregations.bucket.histogram.InternalHistogramTests;
import org.elasticsearch.search.aggregations.metrics.InternalExtendedStatsTests;
import org.elasticsearch.search.aggregations.metrics.InternalMaxTests;
import org.elasticsearch.search.aggregations.metrics.InternalStatsBucketTests;
import org.elasticsearch.search.aggregations.metrics.InternalStatsTests;
import org.elasticsearch.search.aggregations.metrics.avg.InternalAvgTests;
import org.elasticsearch.search.aggregations.metrics.cardinality.InternalCardinalityTests;
import org.elasticsearch.search.aggregations.metrics.geobounds.InternalGeoBoundsTests;
import org.elasticsearch.search.aggregations.metrics.geocentroid.InternalGeoCentroidTests;
import org.elasticsearch.search.aggregations.metrics.min.InternalMinTests;
import org.elasticsearch.search.aggregations.metrics.percentiles.hdr.InternalHDRPercentilesRanksTests;
import org.elasticsearch.search.aggregations.metrics.percentiles.hdr.InternalHDRPercentilesTests;
import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.InternalTDigestPercentilesRanksTests;
import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.InternalTDigestPercentilesTests;
import org.elasticsearch.search.aggregations.metrics.sum.InternalSumTests;
import org.elasticsearch.search.aggregations.metrics.valuecount.InternalValueCountTests;
import org.elasticsearch.search.aggregations.pipeline.InternalSimpleValueTests;
import org.elasticsearch.search.aggregations.pipeline.bucketmetrics.InternalBucketMetricValueTests;
import org.elasticsearch.search.aggregations.pipeline.bucketmetrics.percentile.InternalPercentilesBucketTests;
import org.elasticsearch.search.aggregations.pipeline.bucketmetrics.stats.extended.InternalExtendedStatsBucketTests;
import org.elasticsearch.search.aggregations.pipeline.derivative.InternalDerivativeTests;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static java.util.Collections.singletonMap;
/**
* This class tests that aggregations parsing works properly. It checks that we can parse
* different aggregations and adds sub-aggregations where applicable.
*
*/
public class AggregationsTests extends ESTestCase {
private static final List<InternalAggregationTestCase> aggsTests = getAggsTests();
private static List<InternalAggregationTestCase> getAggsTests() {
List<InternalAggregationTestCase> aggsTests = new ArrayList<>();
aggsTests.add(new InternalCardinalityTests());
aggsTests.add(new InternalTDigestPercentilesTests());
aggsTests.add(new InternalTDigestPercentilesRanksTests());
aggsTests.add(new InternalHDRPercentilesTests());
aggsTests.add(new InternalHDRPercentilesRanksTests());
aggsTests.add(new InternalPercentilesBucketTests());
aggsTests.add(new InternalMinTests());
aggsTests.add(new InternalMaxTests());
aggsTests.add(new InternalAvgTests());
aggsTests.add(new InternalSumTests());
aggsTests.add(new InternalValueCountTests());
aggsTests.add(new InternalSimpleValueTests());
aggsTests.add(new InternalDerivativeTests());
aggsTests.add(new InternalBucketMetricValueTests());
aggsTests.add(new InternalStatsTests());
aggsTests.add(new InternalStatsBucketTests());
aggsTests.add(new InternalExtendedStatsTests());
aggsTests.add(new InternalExtendedStatsBucketTests());
aggsTests.add(new InternalGeoBoundsTests());
aggsTests.add(new InternalGeoCentroidTests());
aggsTests.add(new InternalHistogramTests());
aggsTests.add(new InternalDateHistogramTests());
return Collections.unmodifiableList(aggsTests);
}
@Override
protected NamedXContentRegistry xContentRegistry() {
return new NamedXContentRegistry(InternalAggregationTestCase.getNamedXContents());
}
@Before
public void init() throws Exception {
for (InternalAggregationTestCase aggsTest : aggsTests) {
aggsTest.setUp();
}
}
@After
public void cleanUp() throws Exception {
for (InternalAggregationTestCase aggsTest : aggsTests) {
aggsTest.tearDown();
}
}
public void testFromXContent() throws IOException {
XContentType xContentType = randomFrom(XContentType.values());
final ToXContent.Params params = new ToXContent.MapParams(singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true"));
Aggregations aggregations = createTestInstance();
BytesReference originalBytes = toShuffledXContent(aggregations, xContentType, params, randomBoolean());
try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals(Aggregations.AGGREGATIONS_FIELD, parser.currentName());
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
Aggregations parsedAggregations = Aggregations.fromXContent(parser);
BytesReference parsedBytes = XContentHelper.toXContent(parsedAggregations, xContentType, randomBoolean());
ElasticsearchAssertions.assertToXContentEquivalent(originalBytes, parsedBytes, xContentType);
}
}
private static InternalAggregations createTestInstance() {
return createTestInstance(0, 5);
}
private static InternalAggregations createTestInstance(final int currentDepth, final int maxDepth) {
int numAggs = randomIntBetween(1, 5);
List<InternalAggregation> aggs = new ArrayList<>(numAggs);
for (int i = 0; i < numAggs; i++) {
InternalAggregationTestCase testCase = randomFrom(aggsTests);
if (testCase instanceof InternalMultiBucketAggregationTestCase && currentDepth < maxDepth) {
InternalMultiBucketAggregationTestCase multiBucketAggTestCase = (InternalMultiBucketAggregationTestCase) testCase;
multiBucketAggTestCase.subAggregationsSupplier = () -> createTestInstance(currentDepth + 1, maxDepth);
}
if (testCase instanceof InternalSingleBucketAggregationTestCase && currentDepth < maxDepth) {
InternalSingleBucketAggregationTestCase singleBucketAggTestCase = (InternalSingleBucketAggregationTestCase) testCase;
singleBucketAggTestCase.subAggregationsSupplier = () -> createTestInstance(currentDepth + 1, maxDepth);
}
aggs.add(testCase.createTestInstance());
}
return new InternalAggregations(aggs);
}
}

View File

@ -21,36 +21,42 @@ package org.elasticsearch.search.aggregations;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
public abstract class InternalMultiBucketAggregationTestCase<T extends InternalAggregation & MultiBucketsAggregation>
extends InternalAggregationTestCase<T> {
private boolean hasSubAggregations;
Supplier<InternalAggregations> subAggregationsSupplier;
@Before
public void initHasSubAggregations() {
hasSubAggregations = randomBoolean();
@Override
public void setUp() throws Exception {
super.setUp();
if (randomBoolean()) {
subAggregationsSupplier = () -> InternalAggregations.EMPTY;
} else {
subAggregationsSupplier = () -> {
final int numAggregations = randomIntBetween(1, 3);
List<InternalAggregation> aggs = new ArrayList<>();
for (int i = 0; i < numAggregations; i++) {
aggs.add(createTestInstance(randomAlphaOfLength(5), emptyList(), emptyMap(), InternalAggregations.EMPTY));
}
return new InternalAggregations(aggs);
};
}
}
@Override
protected final T createTestInstance(String name, List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) {
List<InternalAggregation> internal = new ArrayList<>();
if (hasSubAggregations) {
final int numAggregations = randomIntBetween(1, 3);
for (int i = 0; i <numAggregations; i++) {
internal.add(createTestInstance(randomAlphaOfLength(5), pipelineAggregators, emptyMap(), InternalAggregations.EMPTY));
}
}
return createTestInstance(name, pipelineAggregators, metaData, new InternalAggregations(internal));
return createTestInstance(name, pipelineAggregators, metaData, subAggregationsSupplier.get());
}
protected abstract T createTestInstance(String name, List<PipelineAggregator> pipelineAggregators,

View File

@ -29,31 +29,43 @@ import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
public abstract class InternalSingleBucketAggregationTestCase<T extends InternalSingleBucketAggregation>
extends InternalAggregationTestCase<T> {
private final boolean hasInternalMax = randomBoolean();
private final boolean hasInternalMin = randomBoolean();
public Supplier<InternalAggregations> subAggregationsSupplier;
@Override
public void setUp() throws Exception {
super.setUp();
subAggregationsSupplier = () -> {
List<InternalAggregation> aggs = new ArrayList<>();
if (hasInternalMax) {
aggs.add(new InternalMax("max", randomDouble(), randomNumericDocValueFormat(), emptyList(), emptyMap()));
}
if (hasInternalMin) {
aggs.add(new InternalMin("min", randomDouble(), randomNumericDocValueFormat(), emptyList(), emptyMap()));
}
return new InternalAggregations(aggs);
};
}
protected abstract T createTestInstance(String name, long docCount, InternalAggregations aggregations,
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData);
protected abstract void extraAssertReduced(T reduced, List<T> inputs);
@Override
protected final T createTestInstance(String name, List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) {
List<InternalAggregation> internal = new ArrayList<>();
if (hasInternalMax) {
internal.add(new InternalMax("max", randomDouble(), randomNumericDocValueFormat(), emptyList(), emptyMap()));
}
if (hasInternalMin) {
internal.add(new InternalMin("min", randomDouble(), randomNumericDocValueFormat(), emptyList(), emptyMap()));
}
// we shouldn't use the full long range here since we sum doc count on reduce, and don't want to overflow the long range there
long docCount = between(0, Integer.MAX_VALUE);
return createTestInstance(name, docCount, new InternalAggregations(internal), pipelineAggregators, metaData);
return createTestInstance(name, docCount, subAggregationsSupplier.get(), pipelineAggregators, metaData);
}
@Override

View File

@ -26,7 +26,6 @@ import org.elasticsearch.search.aggregations.InternalMultiBucketAggregationTestC
import org.elasticsearch.search.aggregations.ParsedMultiBucketAggregation;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import org.joda.time.DateTime;
import org.junit.Before;
import java.util.ArrayList;
import java.util.List;
@ -42,8 +41,9 @@ public class InternalDateHistogramTests extends InternalMultiBucketAggregationTe
private boolean keyed;
private DocValueFormat format;
@Before
public void init() {
@Override
public void setUp() throws Exception {
super.setUp();
keyed = randomBoolean();
format = randomNumericDocValueFormat();
}

View File

@ -22,12 +22,10 @@ package org.elasticsearch.search.aggregations.bucket.histogram;
import org.apache.lucene.util.TestUtil;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.InternalAggregationTestCase;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.aggregations.InternalMultiBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.ParsedMultiBucketAggregation;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import org.junit.Before;
import java.util.ArrayList;
import java.util.List;
@ -39,8 +37,9 @@ public class InternalHistogramTests extends InternalMultiBucketAggregationTestCa
private boolean keyed;
private DocValueFormat format;
@Before
public void init() {
@Override
public void setUp() throws Exception{
super.setUp();
keyed = randomBoolean();
format = randomNumericDocValueFormat();
}

View File

@ -34,7 +34,7 @@ public class InternalMaxTests extends InternalAggregationTestCase<InternalMax> {
@Override
protected InternalMax createTestInstance(String name, List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) {
double value = frequently() ? randomDouble() : randomFrom(new Double[] { Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY });
double value = frequently() ? randomDouble() : randomFrom(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
DocValueFormat formatter = randomNumericDocValueFormat();
return new InternalMax(name, value, formatter, pipelineAggregators, metaData);
}

View File

@ -28,7 +28,6 @@ import org.elasticsearch.search.aggregations.InternalAggregationTestCase;
import org.elasticsearch.search.aggregations.ParsedAggregation;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import org.junit.After;
import org.junit.Before;
import java.util.ArrayList;
import java.util.List;
@ -38,12 +37,22 @@ public class InternalCardinalityTests extends InternalAggregationTestCase<Intern
private static List<HyperLogLogPlusPlus> algos;
private static int p;
@Before
public void setup() {
@Override
public void setUp() throws Exception {
super.setUp();
algos = new ArrayList<>();
p = randomIntBetween(HyperLogLogPlusPlus.MIN_PRECISION, HyperLogLogPlusPlus.MAX_PRECISION);
}
@After //we force @After to have it run before ESTestCase#after otherwise it fails
@Override
public void tearDown() throws Exception {
super.tearDown();
Releasables.close(algos);
algos.clear();
algos = null;
}
@Override
protected InternalCardinality createTestInstance(String name,
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) {
@ -82,11 +91,4 @@ public class InternalCardinalityTests extends InternalAggregationTestCase<Intern
assertEquals(aggregation.getValue(), parsed.getValue(), Double.MIN_VALUE);
assertEquals(aggregation.getValueAsString(), parsed.getValueAsString());
}
@After
public void cleanup() {
Releasables.close(algos);
algos.clear();
algos = null;
}
}

View File

@ -47,7 +47,7 @@ public class InternalGeoCentroidTests extends InternalAggregationTestCase<Intern
if (count == 0) {
centroid = null;
}
return new InternalGeoCentroid("_name", centroid, count, Collections.emptyList(), Collections.emptyMap());
return new InternalGeoCentroid(name, centroid, count, Collections.emptyList(), Collections.emptyMap());
}
@Override

View File

@ -23,7 +23,6 @@ import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.InternalAggregationTestCase;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import org.junit.Before;
import java.io.IOException;
import java.util.Arrays;
@ -38,8 +37,9 @@ public abstract class AbstractPercentilesTestCase<T extends InternalAggregation
private boolean keyed;
private DocValueFormat docValueFormat;
@Before
public void init() {
@Override
public void setUp() throws Exception {
super.setUp();
percents = randomPercents(false);
keyed = randomBoolean();
docValueFormat = randomNumericDocValueFormat();