• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017, OpenCensus Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.opencensus.implcore.stats;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static io.opencensus.implcore.stats.StatsTestUtil.assertAggregationDataEquals;
21 
22 import com.google.common.collect.ImmutableList;
23 import io.opencensus.common.Timestamp;
24 import io.opencensus.implcore.stats.MutableAggregation.MutableCount;
25 import io.opencensus.implcore.stats.MutableAggregation.MutableDistribution;
26 import io.opencensus.implcore.stats.MutableAggregation.MutableLastValueDouble;
27 import io.opencensus.implcore.stats.MutableAggregation.MutableLastValueLong;
28 import io.opencensus.implcore.stats.MutableAggregation.MutableMean;
29 import io.opencensus.implcore.stats.MutableAggregation.MutableSumDouble;
30 import io.opencensus.implcore.stats.MutableAggregation.MutableSumLong;
31 import io.opencensus.metrics.data.AttachmentValue;
32 import io.opencensus.metrics.data.AttachmentValue.AttachmentValueString;
33 import io.opencensus.metrics.data.Exemplar;
34 import io.opencensus.metrics.export.Distribution;
35 import io.opencensus.metrics.export.Distribution.Bucket;
36 import io.opencensus.metrics.export.Distribution.BucketOptions;
37 import io.opencensus.metrics.export.Point;
38 import io.opencensus.metrics.export.Value;
39 import io.opencensus.stats.AggregationData;
40 import io.opencensus.stats.AggregationData.CountData;
41 import io.opencensus.stats.AggregationData.DistributionData;
42 import io.opencensus.stats.AggregationData.LastValueDataDouble;
43 import io.opencensus.stats.AggregationData.LastValueDataLong;
44 import io.opencensus.stats.AggregationData.MeanData;
45 import io.opencensus.stats.AggregationData.SumDataDouble;
46 import io.opencensus.stats.AggregationData.SumDataLong;
47 import io.opencensus.stats.BucketBoundaries;
48 import java.util.Arrays;
49 import java.util.Collections;
50 import java.util.List;
51 import java.util.Map;
52 import org.junit.Rule;
53 import org.junit.Test;
54 import org.junit.rules.ExpectedException;
55 import org.junit.runner.RunWith;
56 import org.junit.runners.JUnit4;
57 
58 /** Unit tests for {@link io.opencensus.implcore.stats.MutableAggregation}. */
59 @RunWith(JUnit4.class)
60 public class MutableAggregationTest {
61 
62   @Rule public ExpectedException thrown = ExpectedException.none();
63 
64   private static final double TOLERANCE = 1e-6;
65   private static final BucketBoundaries BUCKET_BOUNDARIES =
66       BucketBoundaries.create(Arrays.asList(-10.0, 0.0, 10.0));
67   private static final BucketBoundaries BUCKET_BOUNDARIES_EMPTY =
68       BucketBoundaries.create(Collections.<Double>emptyList());
69   private static final Timestamp TIMESTAMP = Timestamp.create(60, 0);
70   private static final AttachmentValue ATTACHMENT_VALUE_1 = AttachmentValueString.create("v1");
71   private static final AttachmentValue ATTACHMENT_VALUE_2 = AttachmentValueString.create("v2");
72   private static final AttachmentValue ATTACHMENT_VALUE_3 = AttachmentValueString.create("v3");
73   private static final AttachmentValue ATTACHMENT_VALUE_4 = AttachmentValueString.create("v4");
74   private static final AttachmentValue ATTACHMENT_VALUE_5 = AttachmentValueString.create("v5");
75 
76   @Test
testCreateEmpty()77   public void testCreateEmpty() {
78     assertThat(MutableSumDouble.create().getSum()).isWithin(TOLERANCE).of(0);
79     assertThat(MutableSumLong.create().getSum()).isWithin(TOLERANCE).of(0);
80     assertThat(MutableCount.create().getCount()).isEqualTo(0);
81     assertThat(MutableMean.create().getMean()).isWithin(TOLERANCE).of(0);
82     assertThat(MutableLastValueDouble.create().getLastValue()).isNaN();
83     assertThat(MutableLastValueLong.create().getLastValue()).isNaN();
84 
85     BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(0.1, 2.2, 33.3));
86     MutableDistribution mutableDistribution = MutableDistribution.create(bucketBoundaries);
87     assertThat(mutableDistribution.getMean()).isWithin(TOLERANCE).of(0);
88     assertThat(mutableDistribution.getCount()).isEqualTo(0);
89     assertThat(mutableDistribution.getSumOfSquaredDeviations()).isWithin(TOLERANCE).of(0);
90     assertThat(mutableDistribution.getBucketCounts()).isEqualTo(new long[4]);
91     assertThat(mutableDistribution.getExemplars()).isEqualTo(new Exemplar[4]);
92 
93     MutableDistribution mutableDistributionNoHistogram =
94         MutableDistribution.create(BUCKET_BOUNDARIES_EMPTY);
95     assertThat(mutableDistributionNoHistogram.getExemplars()).isNull();
96   }
97 
98   @Test
testNullBucketBoundaries()99   public void testNullBucketBoundaries() {
100     thrown.expect(NullPointerException.class);
101     thrown.expectMessage("bucketBoundaries should not be null.");
102     MutableDistribution.create(null);
103   }
104 
105   @Test
testNoBoundaries()106   public void testNoBoundaries() {
107     MutableDistribution noBoundaries =
108         MutableDistribution.create(BucketBoundaries.create(Collections.<Double>emptyList()));
109     assertThat(noBoundaries.getBucketCounts().length).isEqualTo(1);
110     assertThat(noBoundaries.getBucketCounts()[0]).isEqualTo(0);
111   }
112 
113   @Test
testAdd()114   public void testAdd() {
115     List<MutableAggregation> aggregations =
116         Arrays.asList(
117             MutableSumDouble.create(),
118             MutableSumLong.create(),
119             MutableCount.create(),
120             MutableMean.create(),
121             MutableDistribution.create(BUCKET_BOUNDARIES),
122             MutableLastValueDouble.create(),
123             MutableLastValueLong.create());
124 
125     List<Double> values = Arrays.asList(-1.0, 1.0, -5.0, 20.0, 5.0);
126 
127     for (double value : values) {
128       for (MutableAggregation aggregation : aggregations) {
129         aggregation.add(value, Collections.<String, AttachmentValue>emptyMap(), TIMESTAMP);
130       }
131     }
132 
133     assertAggregationDataEquals(
134         aggregations.get(0).toAggregationData(),
135         AggregationData.SumDataDouble.create(20.0),
136         TOLERANCE);
137     assertAggregationDataEquals(
138         aggregations.get(1).toAggregationData(), AggregationData.SumDataLong.create(20), TOLERANCE);
139     assertAggregationDataEquals(
140         aggregations.get(2).toAggregationData(), AggregationData.CountData.create(5), TOLERANCE);
141     assertAggregationDataEquals(
142         aggregations.get(3).toAggregationData(),
143         AggregationData.MeanData.create(4.0, 5),
144         TOLERANCE);
145     assertAggregationDataEquals(
146         aggregations.get(4).toAggregationData(),
147         AggregationData.DistributionData.create(4.0, 5, 372, Arrays.asList(4L, 1L)),
148         TOLERANCE);
149     assertAggregationDataEquals(
150         aggregations.get(5).toAggregationData(),
151         AggregationData.LastValueDataDouble.create(5.0),
152         TOLERANCE);
153     assertAggregationDataEquals(
154         aggregations.get(6).toAggregationData(),
155         AggregationData.LastValueDataLong.create(5),
156         TOLERANCE);
157   }
158 
159   @Test
testAdd_DistributionWithExemplarAttachments()160   public void testAdd_DistributionWithExemplarAttachments() {
161     MutableDistribution mutableDistribution = MutableDistribution.create(BUCKET_BOUNDARIES);
162     MutableDistribution mutableDistributionNoHistogram =
163         MutableDistribution.create(BUCKET_BOUNDARIES_EMPTY);
164     List<Double> values = Arrays.asList(-1.0, 1.0, -5.0, 20.0, 5.0);
165     List<Map<String, AttachmentValue>> attachmentsList =
166         ImmutableList.<Map<String, AttachmentValue>>of(
167             Collections.<String, AttachmentValue>singletonMap("k1", ATTACHMENT_VALUE_1),
168             Collections.<String, AttachmentValue>singletonMap("k2", ATTACHMENT_VALUE_2),
169             Collections.<String, AttachmentValue>singletonMap("k3", ATTACHMENT_VALUE_3),
170             Collections.<String, AttachmentValue>singletonMap("k4", ATTACHMENT_VALUE_4),
171             Collections.<String, AttachmentValue>singletonMap("k5", ATTACHMENT_VALUE_5));
172     List<Timestamp> timestamps =
173         Arrays.asList(
174             Timestamp.fromMillis(500),
175             Timestamp.fromMillis(1000),
176             Timestamp.fromMillis(2000),
177             Timestamp.fromMillis(3000),
178             Timestamp.fromMillis(4000));
179     for (int i = 0; i < values.size(); i++) {
180       mutableDistribution.add(values.get(i), attachmentsList.get(i), timestamps.get(i));
181       mutableDistributionNoHistogram.add(values.get(i), attachmentsList.get(i), timestamps.get(i));
182     }
183 
184     // Each bucket can only have up to one exemplar. If there are more than one exemplars in a
185     // bucket, only the last one will be kept.
186     List<Exemplar> expected =
187         Arrays.<Exemplar>asList(
188             Exemplar.create(values.get(4), timestamps.get(4), attachmentsList.get(4)),
189             Exemplar.create(values.get(3), timestamps.get(3), attachmentsList.get(3)));
190     assertThat(mutableDistribution.getExemplars())
191         .asList()
192         .containsExactlyElementsIn(expected)
193         .inOrder();
194     assertThat(mutableDistributionNoHistogram.getExemplars()).isNull();
195   }
196 
197   @Test
testCombine_SumCountMean()198   public void testCombine_SumCountMean() {
199     // combine() for Mutable Sum, Count and Mean will pick up fractional stats
200     List<MutableAggregation> aggregations1 =
201         Arrays.asList(
202             MutableSumDouble.create(),
203             MutableSumLong.create(),
204             MutableCount.create(),
205             MutableMean.create());
206     List<MutableAggregation> aggregations2 =
207         Arrays.asList(
208             MutableSumDouble.create(),
209             MutableSumLong.create(),
210             MutableCount.create(),
211             MutableMean.create());
212 
213     for (double val : Arrays.asList(-1.0, -5.0)) {
214       for (MutableAggregation aggregation : aggregations1) {
215         aggregation.add(val, Collections.<String, AttachmentValue>emptyMap(), TIMESTAMP);
216       }
217     }
218     for (double val : Arrays.asList(10.0, 50.0)) {
219       for (MutableAggregation aggregation : aggregations2) {
220         aggregation.add(val, Collections.<String, AttachmentValue>emptyMap(), TIMESTAMP);
221       }
222     }
223 
224     List<MutableAggregation> combined =
225         Arrays.asList(
226             MutableSumDouble.create(),
227             MutableSumLong.create(),
228             MutableCount.create(),
229             MutableMean.create());
230     double fraction1 = 1.0;
231     double fraction2 = 0.6;
232     for (int i = 0; i < combined.size(); i++) {
233       combined.get(i).combine(aggregations1.get(i), fraction1);
234       combined.get(i).combine(aggregations2.get(i), fraction2);
235     }
236 
237     assertThat(((MutableSumDouble) combined.get(0)).getSum()).isWithin(TOLERANCE).of(30);
238     assertThat(((MutableSumLong) combined.get(1)).getSum()).isWithin(TOLERANCE).of(30);
239     assertThat(((MutableCount) combined.get(2)).getCount()).isEqualTo(3);
240     assertThat(((MutableMean) combined.get(3)).getMean()).isWithin(TOLERANCE).of(10);
241   }
242 
243   @Test
testCombine_Distribution()244   public void testCombine_Distribution() {
245     // combine() for Mutable Distribution will ignore fractional stats
246     MutableDistribution distribution1 = MutableDistribution.create(BUCKET_BOUNDARIES);
247     MutableDistribution distribution2 = MutableDistribution.create(BUCKET_BOUNDARIES);
248     MutableDistribution distribution3 = MutableDistribution.create(BUCKET_BOUNDARIES);
249 
250     for (double val : Arrays.asList(5.0, -5.0)) {
251       distribution1.add(val, Collections.<String, AttachmentValue>emptyMap(), TIMESTAMP);
252     }
253     for (double val : Arrays.asList(10.0, 20.0)) {
254       distribution2.add(val, Collections.<String, AttachmentValue>emptyMap(), TIMESTAMP);
255     }
256     for (double val : Arrays.asList(-10.0, 15.0, -15.0, -20.0)) {
257       distribution3.add(val, Collections.<String, AttachmentValue>emptyMap(), TIMESTAMP);
258     }
259 
260     MutableDistribution combined = MutableDistribution.create(BUCKET_BOUNDARIES);
261     combined.combine(distribution1, 1.0); // distribution1 will be combined
262     combined.combine(distribution2, 0.6); // distribution2 will be ignored
263     verifyMutableDistribution(combined, 0, 2, 50.0, new long[] {2, 0});
264 
265     combined.combine(distribution2, 1.0); // distribution2 will be combined
266     verifyMutableDistribution(combined, 7.5, 4, 325.0, new long[] {2, 2});
267     combined.combine(distribution3, 1.0); // distribution3 will be combined
268     verifyMutableDistribution(combined, 0, 8, 1500.0, new long[] {5, 3});
269   }
270 
271   @Test
mutableAggregation_ToAggregationData()272   public void mutableAggregation_ToAggregationData() {
273     assertThat(MutableSumDouble.create().toAggregationData()).isEqualTo(SumDataDouble.create(0));
274     assertThat(MutableSumLong.create().toAggregationData()).isEqualTo(SumDataLong.create(0));
275     assertThat(MutableCount.create().toAggregationData()).isEqualTo(CountData.create(0));
276     assertThat(MutableMean.create().toAggregationData()).isEqualTo(MeanData.create(0, 0));
277     assertThat(MutableDistribution.create(BUCKET_BOUNDARIES).toAggregationData())
278         .isEqualTo(DistributionData.create(0, 0, 0, Arrays.asList(0L, 0L)));
279     assertThat(MutableLastValueDouble.create().toAggregationData())
280         .isEqualTo(LastValueDataDouble.create(Double.NaN));
281     assertThat(MutableLastValueLong.create().toAggregationData())
282         .isEqualTo(LastValueDataLong.create(0));
283   }
284 
285   @Test
mutableAggregation_ToPoint()286   public void mutableAggregation_ToPoint() {
287     assertThat(MutableSumDouble.create().toPoint(TIMESTAMP))
288         .isEqualTo(Point.create(Value.doubleValue(0), TIMESTAMP));
289     assertThat(MutableSumLong.create().toPoint(TIMESTAMP))
290         .isEqualTo(Point.create(Value.longValue(0), TIMESTAMP));
291     assertThat(MutableCount.create().toPoint(TIMESTAMP))
292         .isEqualTo(Point.create(Value.longValue(0), TIMESTAMP));
293     assertThat(MutableMean.create().toPoint(TIMESTAMP))
294         .isEqualTo(Point.create(Value.doubleValue(0), TIMESTAMP));
295 
296     assertThat(MutableDistribution.create(BUCKET_BOUNDARIES).toPoint(TIMESTAMP))
297         .isEqualTo(
298             Point.create(
299                 Value.distributionValue(
300                     Distribution.create(
301                         0,
302                         0,
303                         0,
304                         BucketOptions.explicitOptions(BUCKET_BOUNDARIES.getBoundaries()),
305                         Arrays.asList(Bucket.create(0), Bucket.create(0)))),
306                 TIMESTAMP));
307   }
308 
verifyMutableDistribution( MutableDistribution mutableDistribution, double mean, long count, double sumOfSquaredDeviations, long[] bucketCounts)309   private static void verifyMutableDistribution(
310       MutableDistribution mutableDistribution,
311       double mean,
312       long count,
313       double sumOfSquaredDeviations,
314       long[] bucketCounts) {
315     assertThat(mutableDistribution.getMean()).isWithin(MutableAggregationTest.TOLERANCE).of(mean);
316     assertThat(mutableDistribution.getCount()).isEqualTo(count);
317     assertThat(mutableDistribution.getSumOfSquaredDeviations())
318         .isWithin(MutableAggregationTest.TOLERANCE)
319         .of(sumOfSquaredDeviations);
320     assertThat(mutableDistribution.getBucketCounts()).isEqualTo(bucketCounts);
321   }
322 }
323