• 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.MutableViewData.ZERO_TIMESTAMP;
21 
22 import com.google.common.collect.Iterables;
23 import com.google.common.collect.Lists;
24 import io.opencensus.common.Function;
25 import io.opencensus.common.Functions;
26 import io.opencensus.common.Timestamp;
27 import io.opencensus.stats.Aggregation;
28 import io.opencensus.stats.AggregationData;
29 import io.opencensus.stats.AggregationData.CountData;
30 import io.opencensus.stats.AggregationData.DistributionData;
31 import io.opencensus.stats.AggregationData.LastValueDataDouble;
32 import io.opencensus.stats.AggregationData.LastValueDataLong;
33 import io.opencensus.stats.AggregationData.MeanData;
34 import io.opencensus.stats.AggregationData.SumDataDouble;
35 import io.opencensus.stats.AggregationData.SumDataLong;
36 import io.opencensus.stats.Measure;
37 import io.opencensus.stats.View;
38 import io.opencensus.stats.ViewData;
39 import io.opencensus.stats.ViewData.AggregationWindowData;
40 import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData;
41 import io.opencensus.stats.ViewData.AggregationWindowData.IntervalData;
42 import io.opencensus.tags.Tag;
43 import io.opencensus.tags.TagContext;
44 import io.opencensus.tags.TagValue;
45 import java.util.ArrayList;
46 import java.util.Collections;
47 import java.util.Iterator;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.Map.Entry;
51 import javax.annotation.Nullable;
52 
53 /** Stats test utilities. */
54 final class StatsTestUtil {
55 
56   private static final Timestamp EMPTY = Timestamp.create(0, 0);
57 
StatsTestUtil()58   private StatsTestUtil() {}
59 
60   /**
61    * Creates an {@link AggregationData} by adding the given sequence of values, based on the
62    * definition of the given {@link Aggregation}.
63    *
64    * @param aggregation the {@code Aggregation} to apply the values to.
65    * @param values the values to add to the {@code MutableAggregation}s.
66    * @return an {@code AggregationData}.
67    */
createAggregationData( Aggregation aggregation, Measure measure, double... values)68   static AggregationData createAggregationData(
69       Aggregation aggregation, Measure measure, double... values) {
70     MutableAggregation mutableAggregation =
71         RecordUtils.createMutableAggregation(aggregation, measure);
72     for (double value : values) {
73       mutableAggregation.add(value, Collections.<String, String>emptyMap(), EMPTY);
74     }
75     return mutableAggregation.toAggregationData();
76   }
77 
78   /**
79    * Compare the actual and expected AggregationMap within the given tolerance.
80    *
81    * @param expected the expected map.
82    * @param actual the actual mapping from {@code List<TagValue>} to {@code AggregationData}.
83    * @param tolerance the tolerance used for {@code double} comparison.
84    */
assertAggregationMapEquals( Map<? extends List<? extends TagValue>, ? extends AggregationData> actual, Map<? extends List<? extends TagValue>, ? extends AggregationData> expected, double tolerance)85   static void assertAggregationMapEquals(
86       Map<? extends List<? extends TagValue>, ? extends AggregationData> actual,
87       Map<? extends List<? extends TagValue>, ? extends AggregationData> expected,
88       double tolerance) {
89     assertThat(actual.keySet()).containsExactlyElementsIn(expected.keySet());
90     for (Entry<? extends List<? extends TagValue>, ? extends AggregationData> entry :
91         actual.entrySet()) {
92       assertAggregationDataEquals(expected.get(entry.getKey()), entry.getValue(), tolerance);
93     }
94   }
95 
96   /**
97    * Compare the expected and actual {@code AggregationData} within the given tolerance.
98    *
99    * @param expected the expected {@code AggregationData}.
100    * @param actual the actual {@code AggregationData}.
101    * @param tolerance the tolerance used for {@code double} comparison.
102    */
assertAggregationDataEquals( AggregationData expected, final AggregationData actual, final double tolerance)103   static void assertAggregationDataEquals(
104       AggregationData expected, final AggregationData actual, final double tolerance) {
105     expected.match(
106         new Function<SumDataDouble, Void>() {
107           @Override
108           public Void apply(SumDataDouble arg) {
109             assertThat(actual).isInstanceOf(SumDataDouble.class);
110             assertThat(((SumDataDouble) actual).getSum()).isWithin(tolerance).of(arg.getSum());
111             return null;
112           }
113         },
114         new Function<SumDataLong, Void>() {
115           @Override
116           public Void apply(SumDataLong arg) {
117             assertThat(actual).isInstanceOf(SumDataLong.class);
118             assertThat(((SumDataLong) actual).getSum()).isEqualTo(arg.getSum());
119             return null;
120           }
121         },
122         new Function<CountData, Void>() {
123           @Override
124           public Void apply(CountData arg) {
125             assertThat(actual).isInstanceOf(CountData.class);
126             assertThat(((CountData) actual).getCount()).isEqualTo(arg.getCount());
127             return null;
128           }
129         },
130         new Function<DistributionData, Void>() {
131           @Override
132           public Void apply(DistributionData arg) {
133             assertThat(actual).isInstanceOf(DistributionData.class);
134             assertDistributionDataEquals(arg, (DistributionData) actual, tolerance);
135             return null;
136           }
137         },
138         new Function<LastValueDataDouble, Void>() {
139           @Override
140           public Void apply(LastValueDataDouble arg) {
141             assertThat(actual).isInstanceOf(LastValueDataDouble.class);
142             assertThat(((LastValueDataDouble) actual).getLastValue())
143                 .isWithin(tolerance)
144                 .of(arg.getLastValue());
145             return null;
146           }
147         },
148         new Function<LastValueDataLong, Void>() {
149           @Override
150           public Void apply(LastValueDataLong arg) {
151             assertThat(actual).isInstanceOf(LastValueDataLong.class);
152             assertThat(((LastValueDataLong) actual).getLastValue()).isEqualTo(arg.getLastValue());
153             return null;
154           }
155         },
156         new Function<AggregationData, Void>() {
157           @Override
158           public Void apply(AggregationData arg) {
159             if (arg instanceof MeanData) {
160               assertThat(actual).isInstanceOf(MeanData.class);
161               assertThat(((MeanData) actual).getMean())
162                   .isWithin(tolerance)
163                   .of(((MeanData) arg).getMean());
164               return null;
165             }
166             throw new IllegalArgumentException("Unknown Aggregation.");
167           }
168         });
169   }
170 
171   // Create an empty ViewData with the given View.
createEmptyViewData(View view)172   static ViewData createEmptyViewData(View view) {
173     return ViewData.create(
174         view,
175         Collections.<List<TagValue>, AggregationData>emptyMap(),
176         view.getWindow()
177             .match(
178                 Functions.<AggregationWindowData>returnConstant(
179                     CumulativeData.create(ZERO_TIMESTAMP, ZERO_TIMESTAMP)),
180                 Functions.<AggregationWindowData>returnConstant(
181                     IntervalData.create(ZERO_TIMESTAMP)),
182                 Functions.<AggregationWindowData>throwAssertionError()));
183   }
184 
185   // Compare the expected and actual DistributionData within the given tolerance.
assertDistributionDataEquals( DistributionData expected, DistributionData actual, double tolerance)186   private static void assertDistributionDataEquals(
187       DistributionData expected, DistributionData actual, double tolerance) {
188     assertThat(actual.getMean()).isWithin(tolerance).of(expected.getMean());
189     assertThat(actual.getCount()).isEqualTo(expected.getCount());
190     assertThat(actual.getMean()).isWithin(tolerance).of(expected.getMean());
191     assertThat(actual.getSumOfSquaredDeviations())
192         .isWithin(tolerance)
193         .of(expected.getSumOfSquaredDeviations());
194 
195     if (expected.getMax() == Double.NEGATIVE_INFINITY
196         && expected.getMin() == Double.POSITIVE_INFINITY) {
197       assertThat(actual.getMax()).isNegativeInfinity();
198       assertThat(actual.getMin()).isPositiveInfinity();
199     } else {
200       assertThat(actual.getMax()).isWithin(tolerance).of(expected.getMax());
201       assertThat(actual.getMin()).isWithin(tolerance).of(expected.getMin());
202     }
203 
204     assertThat(removeTrailingZeros((actual).getBucketCounts()))
205         .isEqualTo(removeTrailingZeros(expected.getBucketCounts()));
206   }
207 
208   @Nullable
removeTrailingZeros(List<Long> longs)209   private static List<Long> removeTrailingZeros(List<Long> longs) {
210     if (longs == null) {
211       return null;
212     }
213     List<Long> truncated = new ArrayList<Long>(longs);
214     while (!truncated.isEmpty() && Iterables.getLast(truncated) == 0) {
215       truncated.remove(truncated.size() - 1);
216     }
217     return truncated;
218   }
219 
220   static final class SimpleTagContext extends TagContext {
221     private final List<Tag> tags;
222 
SimpleTagContext(Tag... tags)223     SimpleTagContext(Tag... tags) {
224       this.tags = Collections.unmodifiableList(Lists.newArrayList(tags));
225     }
226 
227     @Override
getIterator()228     protected Iterator<Tag> getIterator() {
229       return tags.iterator();
230     }
231   }
232 }
233