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