|  | @@ -119,19 +119,19 @@ import org.elasticsearch.search.aggregations.metrics.StatsAggregationBuilder;
 | 
	
		
			
				|  |  |  import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
 | 
	
		
			
				|  |  |  import org.elasticsearch.search.aggregations.metrics.TopHitsAggregationBuilder;
 | 
	
		
			
				|  |  |  import org.elasticsearch.search.aggregations.metrics.ValueCountAggregationBuilder;
 | 
	
		
			
				|  |  | -import org.elasticsearch.search.aggregations.pipeline.InternalSimpleValue;
 | 
	
		
			
				|  |  | -import org.elasticsearch.search.aggregations.pipeline.ParsedSimpleValue;
 | 
	
		
			
				|  |  | -import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
 | 
	
		
			
				|  |  | +import org.elasticsearch.search.aggregations.pipeline.DerivativePipelineAggregationBuilder;
 | 
	
		
			
				|  |  | +import org.elasticsearch.search.aggregations.pipeline.ExtendedStatsBucketPipelineAggregationBuilder;
 | 
	
		
			
				|  |  |  import org.elasticsearch.search.aggregations.pipeline.InternalBucketMetricValue;
 | 
	
		
			
				|  |  | +import org.elasticsearch.search.aggregations.pipeline.InternalSimpleValue;
 | 
	
		
			
				|  |  |  import org.elasticsearch.search.aggregations.pipeline.ParsedBucketMetricValue;
 | 
	
		
			
				|  |  | +import org.elasticsearch.search.aggregations.pipeline.ParsedDerivative;
 | 
	
		
			
				|  |  | +import org.elasticsearch.search.aggregations.pipeline.ParsedExtendedStatsBucket;
 | 
	
		
			
				|  |  |  import org.elasticsearch.search.aggregations.pipeline.ParsedPercentilesBucket;
 | 
	
		
			
				|  |  | -import org.elasticsearch.search.aggregations.pipeline.PercentilesBucketPipelineAggregationBuilder;
 | 
	
		
			
				|  |  | +import org.elasticsearch.search.aggregations.pipeline.ParsedSimpleValue;
 | 
	
		
			
				|  |  |  import org.elasticsearch.search.aggregations.pipeline.ParsedStatsBucket;
 | 
	
		
			
				|  |  | +import org.elasticsearch.search.aggregations.pipeline.PercentilesBucketPipelineAggregationBuilder;
 | 
	
		
			
				|  |  | +import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
 | 
	
		
			
				|  |  |  import org.elasticsearch.search.aggregations.pipeline.StatsBucketPipelineAggregationBuilder;
 | 
	
		
			
				|  |  | -import org.elasticsearch.search.aggregations.pipeline.ExtendedStatsBucketPipelineAggregationBuilder;
 | 
	
		
			
				|  |  | -import org.elasticsearch.search.aggregations.pipeline.ParsedExtendedStatsBucket;
 | 
	
		
			
				|  |  | -import org.elasticsearch.search.aggregations.pipeline.DerivativePipelineAggregationBuilder;
 | 
	
		
			
				|  |  | -import org.elasticsearch.search.aggregations.pipeline.ParsedDerivative;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import java.io.IOException;
 | 
	
		
			
				|  |  |  import java.util.ArrayList;
 | 
	
	
		
			
				|  | @@ -151,6 +151,7 @@ import static org.elasticsearch.search.aggregations.InternalMultiBucketAggregati
 | 
	
		
			
				|  |  |  import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
 | 
	
		
			
				|  |  |  import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.equalTo;
 | 
	
		
			
				|  |  | +import static org.hamcrest.Matchers.lessThanOrEqualTo;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  public abstract class InternalAggregationTestCase<T extends InternalAggregation> extends AbstractWireSerializingTestCase<T> {
 | 
	
		
			
				|  |  |      public static final int DEFAULT_MAX_BUCKETS = 100000;
 | 
	
	
		
			
				|  | @@ -267,7 +268,14 @@ public abstract class InternalAggregationTestCase<T extends InternalAggregation>
 | 
	
		
			
				|  |  |                  new InternalAggregation.ReduceContext(bigArrays, mockScriptService, bucketConsumer,false);
 | 
	
		
			
				|  |  |              @SuppressWarnings("unchecked")
 | 
	
		
			
				|  |  |              T reduced = (T) inputs.get(0).reduce(internalAggregations, context);
 | 
	
		
			
				|  |  | -            assertMultiBucketConsumer(reduced, bucketConsumer);
 | 
	
		
			
				|  |  | +            int initialBucketCount = 0;
 | 
	
		
			
				|  |  | +            for (InternalAggregation internalAggregation : internalAggregations) {
 | 
	
		
			
				|  |  | +                initialBucketCount += countInnerBucket(internalAggregation);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            int reducedBucketCount = countInnerBucket(reduced);
 | 
	
		
			
				|  |  | +            //check that non final reduction never adds buckets
 | 
	
		
			
				|  |  | +            assertThat(reducedBucketCount, lessThanOrEqualTo(initialBucketCount));
 | 
	
		
			
				|  |  | +            assertMultiBucketConsumer(reducedBucketCount, bucketConsumer);
 | 
	
		
			
				|  |  |              toReduce = new ArrayList<>(toReduce.subList(r, toReduceSize));
 | 
	
		
			
				|  |  |              toReduce.add(reduced);
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -332,14 +340,14 @@ public abstract class InternalAggregationTestCase<T extends InternalAggregation>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public final void testFromXContent() throws IOException {
 | 
	
		
			
				|  |  |          final T aggregation = createTestInstance();
 | 
	
		
			
				|  |  | -        final Aggregation parsedAggregation = parseAndAssert(aggregation, randomBoolean(), false);
 | 
	
		
			
				|  |  | -        assertFromXContent(aggregation, (ParsedAggregation) parsedAggregation);
 | 
	
		
			
				|  |  | +        final ParsedAggregation parsedAggregation = parseAndAssert(aggregation, randomBoolean(), false);
 | 
	
		
			
				|  |  | +        assertFromXContent(aggregation, parsedAggregation);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public final void testFromXContentWithRandomFields() throws IOException {
 | 
	
		
			
				|  |  |          final T aggregation = createTestInstance();
 | 
	
		
			
				|  |  | -        final Aggregation parsedAggregation = parseAndAssert(aggregation, randomBoolean(), true);
 | 
	
		
			
				|  |  | -        assertFromXContent(aggregation, (ParsedAggregation) parsedAggregation);
 | 
	
		
			
				|  |  | +        final ParsedAggregation parsedAggregation = parseAndAssert(aggregation, randomBoolean(), true);
 | 
	
		
			
				|  |  | +        assertFromXContent(aggregation, parsedAggregation);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      protected abstract void assertFromXContent(T aggregation, ParsedAggregation parsedAggregation) throws IOException;
 | 
	
	
		
			
				|  | @@ -423,6 +431,10 @@ public abstract class InternalAggregationTestCase<T extends InternalAggregation>
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public static void assertMultiBucketConsumer(Aggregation agg, MultiBucketConsumer bucketConsumer) {
 | 
	
		
			
				|  |  | -        assertThat(bucketConsumer.getCount(), equalTo(countInnerBucket(agg)));
 | 
	
		
			
				|  |  | +        assertMultiBucketConsumer(countInnerBucket(agg), bucketConsumer);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private static void assertMultiBucketConsumer(int innerBucketCount, MultiBucketConsumer bucketConsumer) {
 | 
	
		
			
				|  |  | +        assertThat(bucketConsumer.getCount(), equalTo(innerBucketCount));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |