aboutsummaryrefslogtreecommitdiff
path: root/impl_core/src/test/java/io/opencensus/implcore/stats
diff options
context:
space:
mode:
Diffstat (limited to 'impl_core/src/test/java/io/opencensus/implcore/stats')
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java65
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java120
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java147
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java69
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java249
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java147
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java73
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java207
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java183
-rw-r--r--impl_core/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java924
10 files changed, 2184 insertions, 0 deletions
diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java
new file mode 100644
index 00000000..2fd1ddc7
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed 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 io.opencensus.implcore.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.stats.StatsCollectionState;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link CurrentStatsState}. */
+@RunWith(JUnit4.class)
+public final class CurrentStatsStateTest {
+
+ @Rule public final ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void defaultState() {
+ assertThat(new CurrentStatsState().get()).isEqualTo(StatsCollectionState.ENABLED);
+ }
+
+ @Test
+ public void setState() {
+ CurrentStatsState state = new CurrentStatsState();
+ assertThat(state.set(StatsCollectionState.DISABLED)).isTrue();
+ assertThat(state.getInternal()).isEqualTo(StatsCollectionState.DISABLED);
+ assertThat(state.set(StatsCollectionState.ENABLED)).isTrue();
+ assertThat(state.getInternal()).isEqualTo(StatsCollectionState.ENABLED);
+ assertThat(state.set(StatsCollectionState.ENABLED)).isFalse();
+ }
+
+ @Test
+ public void preventNull() {
+ CurrentStatsState state = new CurrentStatsState();
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("state");
+ state.set(null);
+ }
+
+ @Test
+ public void preventSettingStateAfterReadingState() {
+ CurrentStatsState state = new CurrentStatsState();
+ state.get();
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("State was already read, cannot set state.");
+ state.set(StatsCollectionState.DISABLED);
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java
new file mode 100644
index 00000000..10bce262
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed 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 io.opencensus.implcore.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.common.Duration;
+import io.opencensus.common.Timestamp;
+import io.opencensus.implcore.stats.MutableAggregation.MutableMean;
+import io.opencensus.stats.Aggregation.Mean;
+import io.opencensus.tags.TagValue;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link IntervalBucket}. */
+@RunWith(JUnit4.class)
+public class IntervalBucketTest {
+
+ @Rule public final ExpectedException thrown = ExpectedException.none();
+
+ private static final double TOLERANCE = 1e-6;
+ private static final Duration MINUTE = Duration.create(60, 0);
+ private static final Duration NEGATIVE_TEN_SEC = Duration.create(-10, 0);
+ private static final Timestamp START = Timestamp.create(60, 0);
+ private static final Mean MEAN = Mean.create();
+
+ @Test
+ public void preventNullStartTime() {
+ thrown.expect(NullPointerException.class);
+ new IntervalBucket(null, MINUTE, MEAN);
+ }
+
+ @Test
+ public void preventNullDuration() {
+ thrown.expect(NullPointerException.class);
+ new IntervalBucket(START, null, MEAN);
+ }
+
+ @Test
+ public void preventNegativeDuration() {
+ thrown.expect(IllegalArgumentException.class);
+ new IntervalBucket(START, NEGATIVE_TEN_SEC, MEAN);
+ }
+
+ @Test
+ public void preventNullAggregationList() {
+ thrown.expect(NullPointerException.class);
+ new IntervalBucket(START, MINUTE, null);
+ }
+
+ @Test
+ public void testGetTagValueAggregationMap_empty() {
+ assertThat(new IntervalBucket(START, MINUTE, MEAN).getTagValueAggregationMap()).isEmpty();
+ }
+
+ @Test
+ public void testGetStart() {
+ assertThat(new IntervalBucket(START, MINUTE, MEAN).getStart()).isEqualTo(START);
+ }
+
+ @Test
+ public void testRecord() {
+ IntervalBucket bucket = new IntervalBucket(START, MINUTE, MEAN);
+ List<TagValue> tagValues1 = Arrays.<TagValue>asList(TagValue.create("VALUE1"));
+ List<TagValue> tagValues2 = Arrays.<TagValue>asList(TagValue.create("VALUE2"));
+ bucket.record(tagValues1, 5.0);
+ bucket.record(tagValues1, 15.0);
+ bucket.record(tagValues2, 10.0);
+ assertThat(bucket.getTagValueAggregationMap().keySet()).containsExactly(tagValues1, tagValues2);
+ MutableMean mutableMean1 = (MutableMean) bucket.getTagValueAggregationMap().get(tagValues1);
+ MutableMean mutableMean2 = (MutableMean) bucket.getTagValueAggregationMap().get(tagValues2);
+ assertThat(mutableMean1.getSum()).isWithin(TOLERANCE).of(20);
+ assertThat(mutableMean2.getSum()).isWithin(TOLERANCE).of(10);
+ assertThat(mutableMean1.getCount()).isEqualTo(2);
+ assertThat(mutableMean2.getCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void testGetFraction() {
+ Timestamp thirtySecondsAfterStart = Timestamp.create(90, 0);
+ assertThat(new IntervalBucket(START, MINUTE, MEAN).getFraction(thirtySecondsAfterStart))
+ .isWithin(TOLERANCE)
+ .of(0.5);
+ }
+
+ @Test
+ public void preventCallingGetFractionOnPastBuckets() {
+ IntervalBucket bucket = new IntervalBucket(START, MINUTE, MEAN);
+ Timestamp twoMinutesAfterStart = Timestamp.create(180, 0);
+ thrown.expect(IllegalArgumentException.class);
+ bucket.getFraction(twoMinutesAfterStart);
+ }
+
+ @Test
+ public void preventCallingGetFractionOnFutureBuckets() {
+ IntervalBucket bucket = new IntervalBucket(START, MINUTE, MEAN);
+ Timestamp thirtySecondsBeforeStart = Timestamp.create(30, 0);
+ thrown.expect(IllegalArgumentException.class);
+ bucket.getFraction(thirtySecondsBeforeStart);
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java
new file mode 100644
index 00000000..c57baa0b
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016-17, OpenCensus Authors
+ *
+ * Licensed 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 io.opencensus.implcore.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.Lists;
+import io.opencensus.stats.Measure;
+import io.opencensus.stats.Measure.MeasureDouble;
+import io.opencensus.stats.Measure.MeasureLong;
+import io.opencensus.stats.Measurement;
+import io.opencensus.stats.Measurement.MeasurementDouble;
+import io.opencensus.stats.Measurement.MeasurementLong;
+import java.util.ArrayList;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link MeasureMapInternal}. */
+@RunWith(JUnit4.class)
+public class MeasureMapInternalTest {
+
+ @Test
+ public void testPutDouble() {
+ MeasureMapInternal metrics = MeasureMapInternal.builder().put(M1, 44.4).build();
+ assertContains(metrics, MeasurementDouble.create(M1, 44.4));
+ }
+
+ @Test
+ public void testPutLong() {
+ MeasureMapInternal metrics = MeasureMapInternal.builder().put(M3, 9999L).put(M4, 8888L).build();
+ assertContains(metrics, MeasurementLong.create(M3, 9999L), MeasurementLong.create(M4, 8888L));
+ }
+
+ @Test
+ public void testCombination() {
+ MeasureMapInternal metrics =
+ MeasureMapInternal.builder()
+ .put(M1, 44.4)
+ .put(M2, 66.6)
+ .put(M3, 9999L)
+ .put(M4, 8888L)
+ .build();
+ assertContains(
+ metrics,
+ MeasurementDouble.create(M1, 44.4),
+ MeasurementDouble.create(M2, 66.6),
+ MeasurementLong.create(M3, 9999L),
+ MeasurementLong.create(M4, 8888L));
+ }
+
+ @Test
+ public void testBuilderEmpty() {
+ MeasureMapInternal metrics = MeasureMapInternal.builder().build();
+ assertContains(metrics);
+ }
+
+ @Test
+ public void testBuilder() {
+ ArrayList<Measurement> expected = new ArrayList<Measurement>(10);
+ MeasureMapInternal.Builder builder = MeasureMapInternal.builder();
+ for (int i = 1; i <= 10; i++) {
+ expected.add(MeasurementDouble.create(makeSimpleMeasureDouble("m" + i), i * 11.1));
+ builder.put(makeSimpleMeasureDouble("m" + i), i * 11.1);
+ assertContains(builder.build(), expected.toArray(new Measurement[i]));
+ }
+ }
+
+ @Test
+ public void testDuplicateMeasureDoubles() {
+ assertContains(
+ MeasureMapInternal.builder().put(M1, 1.0).put(M1, 2.0).build(),
+ MeasurementDouble.create(M1, 2.0));
+ assertContains(
+ MeasureMapInternal.builder().put(M1, 1.0).put(M1, 2.0).put(M1, 3.0).build(),
+ MeasurementDouble.create(M1, 3.0));
+ assertContains(
+ MeasureMapInternal.builder().put(M1, 1.0).put(M2, 2.0).put(M1, 3.0).build(),
+ MeasurementDouble.create(M1, 3.0),
+ MeasurementDouble.create(M2, 2.0));
+ assertContains(
+ MeasureMapInternal.builder().put(M1, 1.0).put(M1, 2.0).put(M2, 2.0).build(),
+ MeasurementDouble.create(M1, 2.0),
+ MeasurementDouble.create(M2, 2.0));
+ }
+
+ @Test
+ public void testDuplicateMeasureLongs() {
+ assertContains(
+ MeasureMapInternal.builder().put(M3, 100L).put(M3, 100L).build(),
+ MeasurementLong.create(M3, 100L));
+ assertContains(
+ MeasureMapInternal.builder().put(M3, 100L).put(M3, 200L).put(M3, 300L).build(),
+ MeasurementLong.create(M3, 300L));
+ assertContains(
+ MeasureMapInternal.builder().put(M3, 100L).put(M4, 200L).put(M3, 300L).build(),
+ MeasurementLong.create(M3, 300L),
+ MeasurementLong.create(M4, 200L));
+ assertContains(
+ MeasureMapInternal.builder().put(M3, 100L).put(M3, 200L).put(M4, 200L).build(),
+ MeasurementLong.create(M3, 200L),
+ MeasurementLong.create(M4, 200L));
+ }
+
+ @Test
+ public void testDuplicateMeasures() {
+ assertContains(
+ MeasureMapInternal.builder().put(M3, 100L).put(M1, 1.0).put(M3, 300L).build(),
+ MeasurementLong.create(M3, 300L),
+ MeasurementDouble.create(M1, 1.0));
+ assertContains(
+ MeasureMapInternal.builder().put(M2, 2.0).put(M3, 100L).put(M2, 3.0).build(),
+ MeasurementDouble.create(M2, 3.0),
+ MeasurementLong.create(M3, 100L));
+ }
+
+ private static final MeasureDouble M1 = makeSimpleMeasureDouble("m1");
+ private static final MeasureDouble M2 = makeSimpleMeasureDouble("m2");
+ private static final MeasureLong M3 = makeSimpleMeasureLong("m3");
+ private static final MeasureLong M4 = makeSimpleMeasureLong("m4");
+
+ private static MeasureDouble makeSimpleMeasureDouble(String measure) {
+ return Measure.MeasureDouble.create(measure, measure + " description", "1");
+ }
+
+ private static MeasureLong makeSimpleMeasureLong(String measure) {
+ return Measure.MeasureLong.create(measure, measure + " description", "1");
+ }
+
+ private static void assertContains(MeasureMapInternal metrics, Measurement... measurements) {
+ assertThat(Lists.newArrayList(metrics.iterator())).containsExactly((Object[]) measurements);
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java
new file mode 100644
index 00000000..0a198b0c
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed 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 io.opencensus.implcore.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.common.Timestamp;
+import io.opencensus.stats.Aggregation.Mean;
+import io.opencensus.stats.Measure;
+import io.opencensus.stats.StatsCollectionState;
+import io.opencensus.stats.View;
+import io.opencensus.stats.View.AggregationWindow.Cumulative;
+import io.opencensus.stats.View.Name;
+import io.opencensus.stats.ViewData;
+import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData;
+import io.opencensus.tags.TagKey;
+import io.opencensus.testing.common.TestClock;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link MeasureToViewMap}. */
+@RunWith(JUnit4.class)
+public class MeasureToViewMapTest {
+
+ private static final Measure MEASURE =
+ Measure.MeasureDouble.create("my measurement", "measurement description", "By");
+
+ private static final Name VIEW_NAME = View.Name.create("my view");
+
+ private static final Cumulative CUMULATIVE = Cumulative.create();
+
+ private static final View VIEW =
+ View.create(
+ VIEW_NAME,
+ "view description",
+ MEASURE,
+ Mean.create(),
+ Arrays.asList(TagKey.create("my key")),
+ CUMULATIVE);
+
+ @Test
+ public void testRegisterAndGetView() {
+ MeasureToViewMap measureToViewMap = new MeasureToViewMap();
+ TestClock clock = TestClock.create(Timestamp.create(10, 20));
+ measureToViewMap.registerView(VIEW, clock);
+ clock.setTime(Timestamp.create(30, 40));
+ ViewData viewData = measureToViewMap.getView(VIEW_NAME, clock, StatsCollectionState.ENABLED);
+ assertThat(viewData.getView()).isEqualTo(VIEW);
+ assertThat(viewData.getWindowData())
+ .isEqualTo(CumulativeData.create(Timestamp.create(10, 20), Timestamp.create(30, 40)));
+ assertThat(viewData.getAggregationMap()).isEmpty();
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java
new file mode 100644
index 00000000..054a5b44
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed 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 io.opencensus.implcore.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.common.Function;
+import io.opencensus.implcore.stats.MutableAggregation.MutableCount;
+import io.opencensus.implcore.stats.MutableAggregation.MutableDistribution;
+import io.opencensus.implcore.stats.MutableAggregation.MutableMean;
+import io.opencensus.implcore.stats.MutableAggregation.MutableSum;
+import io.opencensus.stats.BucketBoundaries;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link io.opencensus.implcore.stats.MutableAggregation}. */
+@RunWith(JUnit4.class)
+public class MutableAggregationTest {
+
+ @Rule public ExpectedException thrown = ExpectedException.none();
+
+ private static final double TOLERANCE = 1e-6;
+ private static final BucketBoundaries BUCKET_BOUNDARIES =
+ BucketBoundaries.create(Arrays.asList(-10.0, 0.0, 10.0));
+
+ @Test
+ public void testCreateEmpty() {
+ assertThat(MutableSum.create().getSum()).isWithin(TOLERANCE).of(0);
+ assertThat(MutableCount.create().getCount()).isEqualTo(0);
+ assertThat(MutableMean.create().getMean()).isWithin(TOLERANCE).of(0);
+
+ BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(0.1, 2.2, 33.3));
+ MutableDistribution mutableDistribution = MutableDistribution.create(bucketBoundaries);
+ assertThat(mutableDistribution.getMean()).isWithin(TOLERANCE).of(0);
+ assertThat(mutableDistribution.getCount()).isEqualTo(0);
+ assertThat(mutableDistribution.getMin()).isPositiveInfinity();
+ assertThat(mutableDistribution.getMax()).isNegativeInfinity();
+ assertThat(mutableDistribution.getSumOfSquaredDeviations()).isWithin(TOLERANCE).of(0);
+ assertThat(mutableDistribution.getBucketCounts()).isEqualTo(new long[4]);
+ }
+
+ @Test
+ public void testNullBucketBoundaries() {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("bucketBoundaries should not be null.");
+ MutableDistribution.create(null);
+ }
+
+ @Test
+ public void testNoBoundaries() {
+ List<Double> buckets = Arrays.asList();
+ MutableDistribution noBoundaries = MutableDistribution.create(BucketBoundaries.create(buckets));
+ assertThat(noBoundaries.getBucketCounts().length).isEqualTo(1);
+ assertThat(noBoundaries.getBucketCounts()[0]).isEqualTo(0);
+ }
+
+ @Test
+ public void testAdd() {
+ List<MutableAggregation> aggregations =
+ Arrays.asList(
+ MutableSum.create(),
+ MutableCount.create(),
+ MutableMean.create(),
+ MutableDistribution.create(BUCKET_BOUNDARIES));
+
+ List<Double> values = Arrays.asList(-1.0, 1.0, -5.0, 20.0, 5.0);
+
+ for (double value : values) {
+ for (MutableAggregation aggregation : aggregations) {
+ aggregation.add(value);
+ }
+ }
+
+ for (MutableAggregation aggregation : aggregations) {
+ aggregation.match(
+ new Function<MutableSum, Void>() {
+ @Override
+ public Void apply(MutableSum arg) {
+ assertThat(arg.getSum()).isWithin(TOLERANCE).of(20.0);
+ return null;
+ }
+ },
+ new Function<MutableCount, Void>() {
+ @Override
+ public Void apply(MutableCount arg) {
+ assertThat(arg.getCount()).isEqualTo(5);
+ return null;
+ }
+ },
+ new Function<MutableMean, Void>() {
+ @Override
+ public Void apply(MutableMean arg) {
+ assertThat(arg.getMean()).isWithin(TOLERANCE).of(4.0);
+ return null;
+ }
+ },
+ new Function<MutableDistribution, Void>() {
+ @Override
+ public Void apply(MutableDistribution arg) {
+ assertThat(arg.getBucketCounts()).isEqualTo(new long[] {0, 2, 2, 1});
+ return null;
+ }
+ });
+ }
+ }
+
+ @Test
+ public void testMatch() {
+ List<MutableAggregation> aggregations =
+ Arrays.asList(
+ MutableSum.create(),
+ MutableCount.create(),
+ MutableMean.create(),
+ MutableDistribution.create(BUCKET_BOUNDARIES));
+
+ List<String> actual = new ArrayList<String>();
+ for (MutableAggregation aggregation : aggregations) {
+ actual.add(
+ aggregation.match(
+ new Function<MutableSum, String>() {
+ @Override
+ public String apply(MutableSum arg) {
+ return "SUM";
+ }
+ },
+ new Function<MutableCount, String>() {
+ @Override
+ public String apply(MutableCount arg) {
+ return "COUNT";
+ }
+ },
+ new Function<MutableMean, String>() {
+ @Override
+ public String apply(MutableMean arg) {
+ return "MEAN";
+ }
+ },
+ new Function<MutableDistribution, String>() {
+ @Override
+ public String apply(MutableDistribution arg) {
+ return "DISTRIBUTION";
+ }
+ }));
+ }
+
+ assertThat(actual).isEqualTo(Arrays.asList("SUM", "COUNT", "MEAN", "DISTRIBUTION"));
+ }
+
+ @Test
+ public void testCombine_SumCountMean() {
+ // combine() for Mutable Sum, Count and Mean will pick up fractional stats
+ List<MutableAggregation> aggregations1 =
+ Arrays.asList(MutableSum.create(), MutableCount.create(), MutableMean.create());
+ List<MutableAggregation> aggregations2 =
+ Arrays.asList(MutableSum.create(), MutableCount.create(), MutableMean.create());
+
+ for (double val : Arrays.asList(-1.0, -5.0)) {
+ for (MutableAggregation aggregation : aggregations1) {
+ aggregation.add(val);
+ }
+ }
+ for (double val : Arrays.asList(10.0, 50.0)) {
+ for (MutableAggregation aggregation : aggregations2) {
+ aggregation.add(val);
+ }
+ }
+
+ List<MutableAggregation> combined =
+ Arrays.asList(MutableSum.create(), MutableCount.create(), MutableMean.create());
+ double fraction1 = 1.0;
+ double fraction2 = 0.6;
+ for (int i = 0; i < combined.size(); i++) {
+ combined.get(i).combine(aggregations1.get(i), fraction1);
+ combined.get(i).combine(aggregations2.get(i), fraction2);
+ }
+
+ assertThat(((MutableSum) combined.get(0)).getSum()).isWithin(TOLERANCE).of(30);
+ assertThat(((MutableCount) combined.get(1)).getCount()).isEqualTo(3);
+ assertThat(((MutableMean) combined.get(2)).getMean()).isWithin(TOLERANCE).of(10);
+ }
+
+ @Test
+ public void testCombine_Distribution() {
+ // combine() for Mutable Distribution will ignore fractional stats
+ MutableDistribution distribution1 = MutableDistribution.create(BUCKET_BOUNDARIES);
+ MutableDistribution distribution2 = MutableDistribution.create(BUCKET_BOUNDARIES);
+ MutableDistribution distribution3 = MutableDistribution.create(BUCKET_BOUNDARIES);
+
+ for (double val : Arrays.asList(5.0, -5.0)) {
+ distribution1.add(val);
+ }
+ for (double val : Arrays.asList(10.0, 20.0)) {
+ distribution2.add(val);
+ }
+ for (double val : Arrays.asList(-10.0, 15.0, -15.0, -20.0)) {
+ distribution3.add(val);
+ }
+
+ MutableDistribution combined = MutableDistribution.create(BUCKET_BOUNDARIES);
+ combined.combine(distribution1, 1.0); // distribution1 will be combined
+ combined.combine(distribution2, 0.6); // distribution2 will be ignored
+ verifyMutableDistribution(combined, 0, 2, -5, 5, 50.0, new long[] {0, 1, 1, 0}, TOLERANCE);
+
+ combined.combine(distribution2, 1.0); // distribution2 will be combined
+ verifyMutableDistribution(combined, 7.5, 4, -5, 20, 325.0, new long[] {0, 1, 1, 2}, TOLERANCE);
+
+ combined.combine(distribution3, 1.0); // distribution3 will be combined
+ verifyMutableDistribution(combined, 0, 8, -20, 20, 1500.0, new long[] {2, 2, 1, 3}, TOLERANCE);
+ }
+
+ private static void verifyMutableDistribution(
+ MutableDistribution mutableDistribution,
+ double mean,
+ long count,
+ double min,
+ double max,
+ double sumOfSquaredDeviations,
+ long[] bucketCounts,
+ double tolerance) {
+ assertThat(mutableDistribution.getMean()).isWithin(tolerance).of(mean);
+ assertThat(mutableDistribution.getCount()).isEqualTo(count);
+ assertThat(mutableDistribution.getMin()).isWithin(tolerance).of(min);
+ assertThat(mutableDistribution.getMax()).isWithin(tolerance).of(max);
+ assertThat(mutableDistribution.getSumOfSquaredDeviations())
+ .isWithin(tolerance)
+ .of(sumOfSquaredDeviations);
+ assertThat(mutableDistribution.getBucketCounts()).isEqualTo(bucketCounts);
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java
new file mode 100644
index 00000000..b4b4c85b
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed 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 io.opencensus.implcore.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+import static io.opencensus.implcore.stats.MutableViewData.toMillis;
+
+import com.google.common.collect.ImmutableMap;
+import io.opencensus.common.Duration;
+import io.opencensus.common.Timestamp;
+import io.opencensus.implcore.stats.MutableAggregation.MutableCount;
+import io.opencensus.implcore.stats.MutableAggregation.MutableDistribution;
+import io.opencensus.implcore.stats.MutableAggregation.MutableMean;
+import io.opencensus.implcore.stats.MutableAggregation.MutableSum;
+import io.opencensus.stats.Aggregation.Count;
+import io.opencensus.stats.Aggregation.Distribution;
+import io.opencensus.stats.Aggregation.Mean;
+import io.opencensus.stats.Aggregation.Sum;
+import io.opencensus.stats.AggregationData;
+import io.opencensus.stats.AggregationData.CountData;
+import io.opencensus.stats.AggregationData.DistributionData;
+import io.opencensus.stats.AggregationData.MeanData;
+import io.opencensus.stats.AggregationData.SumDataDouble;
+import io.opencensus.stats.AggregationData.SumDataLong;
+import io.opencensus.stats.BucketBoundaries;
+import io.opencensus.stats.Measure.MeasureDouble;
+import io.opencensus.stats.Measure.MeasureLong;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link MutableViewData}. */
+@RunWith(JUnit4.class)
+public class MutableViewDataTest {
+
+ private static final double EPSILON = 1e-7;
+
+ private static final TagKey ORIGINATOR = TagKey.create("originator");
+ private static final TagKey CALLER = TagKey.create("caller");
+ private static final TagKey METHOD = TagKey.create("method");
+ private static final TagValue CALLER_V = TagValue.create("some caller");
+ private static final TagValue METHOD_V = TagValue.create("some method");
+ private static final MeasureDouble MEASURE_DOUBLE =
+ MeasureDouble.create("measure1", "description", "1");
+ private static final MeasureLong MEASURE_LONG =
+ MeasureLong.create("measure2", "description", "1");
+
+ @Test
+ public void testConstants() {
+ assertThat(MutableViewData.UNKNOWN_TAG_VALUE).isNull();
+ assertThat(MutableViewData.ZERO_TIMESTAMP).isEqualTo(Timestamp.create(0, 0));
+ }
+
+ @Test
+ public void testGetTagValues() {
+ List<TagKey> columns = Arrays.asList(CALLER, METHOD, ORIGINATOR);
+ Map<TagKey, TagValue> tags = ImmutableMap.of(CALLER, CALLER_V, METHOD, METHOD_V);
+
+ assertThat(MutableViewData.getTagValues(tags, columns))
+ .containsExactly(CALLER_V, METHOD_V, MutableViewData.UNKNOWN_TAG_VALUE)
+ .inOrder();
+ }
+
+ @Test
+ public void createMutableAggregation() {
+ BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(-1.0, 0.0, 1.0));
+
+ assertThat(((MutableSum) MutableViewData.createMutableAggregation(Sum.create())).getSum())
+ .isWithin(EPSILON)
+ .of(0.0);
+ assertThat(((MutableCount) MutableViewData.createMutableAggregation(Count.create())).getCount())
+ .isEqualTo(0L);
+ assertThat(((MutableMean) MutableViewData.createMutableAggregation(Mean.create())).getMean())
+ .isWithin(EPSILON)
+ .of(0D);
+
+ MutableDistribution mutableDistribution =
+ (MutableDistribution)
+ MutableViewData.createMutableAggregation(Distribution.create(bucketBoundaries));
+ assertThat(mutableDistribution.getMin()).isPositiveInfinity();
+ assertThat(mutableDistribution.getMax()).isNegativeInfinity();
+ assertThat(mutableDistribution.getSumOfSquaredDeviations()).isWithin(EPSILON).of(0);
+ assertThat(mutableDistribution.getBucketCounts()).isEqualTo(new long[4]);
+ }
+
+ @Test
+ public void createAggregationData() {
+ BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(-1.0, 0.0, 1.0));
+ List<MutableAggregation> mutableAggregations =
+ Arrays.asList(
+ MutableCount.create(),
+ MutableMean.create(),
+ MutableDistribution.create(bucketBoundaries));
+ List<AggregationData> aggregates = new ArrayList<AggregationData>();
+
+ aggregates.add(MutableViewData.createAggregationData(MutableSum.create(), MEASURE_DOUBLE));
+ aggregates.add(MutableViewData.createAggregationData(MutableSum.create(), MEASURE_LONG));
+ for (MutableAggregation mutableAggregation : mutableAggregations) {
+ aggregates.add(MutableViewData.createAggregationData(mutableAggregation, MEASURE_DOUBLE));
+ }
+
+ assertThat(aggregates)
+ .containsExactly(
+ SumDataDouble.create(0),
+ SumDataLong.create(0),
+ CountData.create(0),
+ MeanData.create(0, 0),
+ DistributionData.create(
+ 0,
+ 0,
+ Double.POSITIVE_INFINITY,
+ Double.NEGATIVE_INFINITY,
+ 0,
+ Arrays.asList(new Long[] {0L, 0L, 0L, 0L})))
+ .inOrder();
+ }
+
+ @Test
+ public void testDurationToMillis() {
+ assertThat(toMillis(Duration.create(0, 0))).isEqualTo(0);
+ assertThat(toMillis(Duration.create(0, 987000000))).isEqualTo(987);
+ assertThat(toMillis(Duration.create(3, 456000000))).isEqualTo(3456);
+ assertThat(toMillis(Duration.create(0, -1000000))).isEqualTo(-1);
+ assertThat(toMillis(Duration.create(-1, 0))).isEqualTo(-1000);
+ assertThat(toMillis(Duration.create(-3, -456000000))).isEqualTo(-3456);
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java
new file mode 100644
index 00000000..49131d8a
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed 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 io.opencensus.implcore.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.implcore.internal.SimpleEventQueue;
+import io.opencensus.stats.StatsCollectionState;
+import io.opencensus.stats.StatsComponent;
+import io.opencensus.testing.common.TestClock;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link StatsComponentImplBase}. */
+@RunWith(JUnit4.class)
+public final class StatsComponentImplBaseTest {
+
+ @Rule public final ExpectedException thrown = ExpectedException.none();
+
+ private final StatsComponent statsComponent =
+ new StatsComponentImplBase(new SimpleEventQueue(), TestClock.create());
+
+ @Test
+ public void defaultState() {
+ assertThat(statsComponent.getState()).isEqualTo(StatsCollectionState.ENABLED);
+ }
+
+ @Test
+ public void setState_Disabled() {
+ statsComponent.setState(StatsCollectionState.DISABLED);
+ assertThat(statsComponent.getState()).isEqualTo(StatsCollectionState.DISABLED);
+ }
+
+ @Test
+ public void setState_Enabled() {
+ statsComponent.setState(StatsCollectionState.DISABLED);
+ statsComponent.setState(StatsCollectionState.ENABLED);
+ assertThat(statsComponent.getState()).isEqualTo(StatsCollectionState.ENABLED);
+ }
+
+ @Test
+ public void setState_DisallowsNull() {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("newState");
+ statsComponent.setState(null);
+ }
+
+ @Test
+ public void preventSettingStateAfterGettingState() {
+ statsComponent.setState(StatsCollectionState.DISABLED);
+ statsComponent.getState();
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("State was already read, cannot set state.");
+ statsComponent.setState(StatsCollectionState.ENABLED);
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java
new file mode 100644
index 00000000..b0533d0d
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed 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 io.opencensus.implcore.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+import static io.opencensus.implcore.stats.MutableViewData.ZERO_TIMESTAMP;
+import static io.opencensus.implcore.stats.StatsTestUtil.createEmptyViewData;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import io.grpc.Context;
+import io.opencensus.implcore.internal.SimpleEventQueue;
+import io.opencensus.stats.Aggregation.Sum;
+import io.opencensus.stats.Measure.MeasureDouble;
+import io.opencensus.stats.MeasureMap;
+import io.opencensus.stats.StatsCollectionState;
+import io.opencensus.stats.StatsComponent;
+import io.opencensus.stats.StatsRecorder;
+import io.opencensus.stats.View;
+import io.opencensus.stats.View.AggregationWindow.Cumulative;
+import io.opencensus.stats.ViewData;
+import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData;
+import io.opencensus.stats.ViewManager;
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.unsafe.ContextUtils;
+import io.opencensus.testing.common.TestClock;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link StatsRecorderImpl}. */
+@RunWith(JUnit4.class)
+public final class StatsRecorderImplTest {
+ private static final TagKey KEY = TagKey.create("KEY");
+ private static final TagValue VALUE = TagValue.create("VALUE");
+ private static final TagValue VALUE_2 = TagValue.create("VALUE_2");
+ private static final MeasureDouble MEASURE_DOUBLE =
+ MeasureDouble.create("my measurement", "description", "us");
+ private static final View.Name VIEW_NAME = View.Name.create("my view");
+
+ private final StatsComponent statsComponent =
+ new StatsComponentImplBase(new SimpleEventQueue(), TestClock.create());
+
+ private final ViewManager viewManager = statsComponent.getViewManager();
+ private final StatsRecorder statsRecorder = statsComponent.getStatsRecorder();
+
+ @Test
+ public void record_CurrentContextNotSet() {
+ View view =
+ View.create(
+ VIEW_NAME,
+ "description",
+ MEASURE_DOUBLE,
+ Sum.create(),
+ Arrays.asList(KEY),
+ Cumulative.create());
+ viewManager.registerView(view);
+ statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 1.0).record();
+ ViewData viewData = viewManager.getView(VIEW_NAME);
+
+ // record() should have used the default TagContext, so the tag value should be null.
+ assertThat(viewData.getAggregationMap().keySet())
+ .containsExactly(Arrays.asList((TagValue) null));
+ }
+
+ @Test
+ public void record_CurrentContextSet() {
+ View view =
+ View.create(
+ VIEW_NAME,
+ "description",
+ MEASURE_DOUBLE,
+ Sum.create(),
+ Arrays.asList(KEY),
+ Cumulative.create());
+ viewManager.registerView(view);
+ Context orig =
+ Context.current()
+ .withValue(ContextUtils.TAG_CONTEXT_KEY, new SimpleTagContext(Tag.create(KEY, VALUE)))
+ .attach();
+ try {
+ statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 1.0).record();
+ } finally {
+ Context.current().detach(orig);
+ }
+ ViewData viewData = viewManager.getView(VIEW_NAME);
+
+ // record() should have used the given TagContext.
+ assertThat(viewData.getAggregationMap().keySet()).containsExactly(Arrays.asList(VALUE));
+ }
+
+ @Test
+ public void recordTwice() {
+ View view =
+ View.create(
+ VIEW_NAME,
+ "description",
+ MEASURE_DOUBLE,
+ Sum.create(),
+ Arrays.asList(KEY),
+ Cumulative.create());
+ viewManager.registerView(view);
+ MeasureMap statsRecord = statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 1.0);
+ statsRecord.record(new SimpleTagContext(Tag.create(KEY, VALUE)));
+ statsRecord.record(new SimpleTagContext(Tag.create(KEY, VALUE_2)));
+ ViewData viewData = viewManager.getView(VIEW_NAME);
+
+ // There should be two entries.
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(Sum.create(), MEASURE_DOUBLE, 1.0),
+ Arrays.asList(VALUE_2),
+ StatsTestUtil.createAggregationData(Sum.create(), MEASURE_DOUBLE, 1.0)),
+ 1e-6);
+ }
+
+ @Test
+ public void record_StatsDisabled() {
+ View view =
+ View.create(
+ VIEW_NAME,
+ "description",
+ MEASURE_DOUBLE,
+ Sum.create(),
+ Arrays.asList(KEY),
+ Cumulative.create());
+
+ viewManager.registerView(view);
+ statsComponent.setState(StatsCollectionState.DISABLED);
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 1.0)
+ .record(new SimpleTagContext(Tag.create(KEY, VALUE)));
+ assertThat(viewManager.getView(VIEW_NAME)).isEqualTo(createEmptyViewData(view));
+ }
+
+ @Test
+ public void record_StatsReenabled() {
+ View view =
+ View.create(
+ VIEW_NAME,
+ "description",
+ MEASURE_DOUBLE,
+ Sum.create(),
+ Arrays.asList(KEY),
+ Cumulative.create());
+ viewManager.registerView(view);
+
+ statsComponent.setState(StatsCollectionState.DISABLED);
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 1.0)
+ .record(new SimpleTagContext(Tag.create(KEY, VALUE)));
+ assertThat(viewManager.getView(VIEW_NAME)).isEqualTo(createEmptyViewData(view));
+
+ statsComponent.setState(StatsCollectionState.ENABLED);
+ assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty();
+ assertThat(viewManager.getView(VIEW_NAME).getWindowData())
+ .isNotEqualTo(CumulativeData.create(ZERO_TIMESTAMP, ZERO_TIMESTAMP));
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 4.0)
+ .record(new SimpleTagContext(Tag.create(KEY, VALUE)));
+ StatsTestUtil.assertAggregationMapEquals(
+ viewManager.getView(VIEW_NAME).getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(Sum.create(), MEASURE_DOUBLE, 4.0)),
+ 1e-6);
+ }
+
+ private static final class SimpleTagContext extends TagContext {
+ private final List<Tag> tags;
+
+ SimpleTagContext(Tag... tags) {
+ this.tags = Collections.unmodifiableList(Lists.newArrayList(tags));
+ }
+
+ @Override
+ protected Iterator<Tag> getIterator() {
+ return tags.iterator();
+ }
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java
new file mode 100644
index 00000000..3a714af4
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed 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 io.opencensus.implcore.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+import static io.opencensus.implcore.stats.MutableViewData.ZERO_TIMESTAMP;
+
+import com.google.common.collect.Iterables;
+import io.opencensus.common.Function;
+import io.opencensus.common.Functions;
+import io.opencensus.stats.Aggregation;
+import io.opencensus.stats.AggregationData;
+import io.opencensus.stats.AggregationData.CountData;
+import io.opencensus.stats.AggregationData.DistributionData;
+import io.opencensus.stats.AggregationData.MeanData;
+import io.opencensus.stats.AggregationData.SumDataDouble;
+import io.opencensus.stats.AggregationData.SumDataLong;
+import io.opencensus.stats.Measure;
+import io.opencensus.stats.View;
+import io.opencensus.stats.ViewData;
+import io.opencensus.stats.ViewData.AggregationWindowData;
+import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData;
+import io.opencensus.stats.ViewData.AggregationWindowData.IntervalData;
+import io.opencensus.tags.TagValue;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/** Stats test utilities. */
+final class StatsTestUtil {
+
+ private StatsTestUtil() {}
+
+ /**
+ * Creates an {@link AggregationData} by adding the given sequence of values, based on the
+ * definition of the given {@link Aggregation}.
+ *
+ * @param aggregation the {@code Aggregation} to apply the values to.
+ * @param values the values to add to the {@code MutableAggregation}s.
+ * @return an {@code AggregationData}.
+ */
+ static AggregationData createAggregationData(
+ Aggregation aggregation, Measure measure, double... values) {
+ MutableAggregation mutableAggregation = MutableViewData.createMutableAggregation(aggregation);
+ for (double value : values) {
+ mutableAggregation.add(value);
+ }
+ return MutableViewData.createAggregationData(mutableAggregation, measure);
+ }
+
+ /**
+ * Compare the actual and expected AggregationMap within the given tolerance.
+ *
+ * @param expected the expected map.
+ * @param actual the actual mapping from {@code List<TagValue>} to {@code AggregationData}.
+ * @param tolerance the tolerance used for {@code double} comparison.
+ */
+ static void assertAggregationMapEquals(
+ Map<? extends List<? extends TagValue>, ? extends AggregationData> actual,
+ Map<? extends List<? extends TagValue>, ? extends AggregationData> expected,
+ double tolerance) {
+ assertThat(actual.keySet()).containsExactlyElementsIn(expected.keySet());
+ for (List<? extends TagValue> tagValues : actual.keySet()) {
+ assertAggregationDataEquals(expected.get(tagValues), actual.get(tagValues), tolerance);
+ }
+ }
+
+ /**
+ * Compare the expected and actual {@code AggregationData} within the given tolerance.
+ *
+ * @param expected the expected {@code AggregationData}.
+ * @param actual the actual {@code AggregationData}.
+ * @param tolerance the tolerance used for {@code double} comparison.
+ */
+ static void assertAggregationDataEquals(
+ AggregationData expected, final AggregationData actual, final double tolerance) {
+ expected.match(
+ new Function<SumDataDouble, Void>() {
+ @Override
+ public Void apply(SumDataDouble arg) {
+ assertThat(actual).isInstanceOf(SumDataDouble.class);
+ assertThat(((SumDataDouble) actual).getSum()).isWithin(tolerance).of(arg.getSum());
+ return null;
+ }
+ },
+ new Function<SumDataLong, Void>() {
+ @Override
+ public Void apply(SumDataLong arg) {
+ assertThat(actual).isInstanceOf(SumDataLong.class);
+ assertThat(((SumDataLong) actual).getSum()).isEqualTo(arg.getSum());
+ return null;
+ }
+ },
+ new Function<CountData, Void>() {
+ @Override
+ public Void apply(CountData arg) {
+ assertThat(actual).isInstanceOf(CountData.class);
+ assertThat(((CountData) actual).getCount()).isEqualTo(arg.getCount());
+ return null;
+ }
+ },
+ new Function<MeanData, Void>() {
+ @Override
+ public Void apply(MeanData arg) {
+ assertThat(actual).isInstanceOf(MeanData.class);
+ assertThat(((MeanData) actual).getMean()).isWithin(tolerance).of(arg.getMean());
+ return null;
+ }
+ },
+ new Function<DistributionData, Void>() {
+ @Override
+ public Void apply(DistributionData arg) {
+ assertThat(actual).isInstanceOf(DistributionData.class);
+ assertDistributionDataEquals(arg, (DistributionData) actual, tolerance);
+ return null;
+ }
+ },
+ Functions.<Void>throwIllegalArgumentException());
+ }
+
+ // Create an empty ViewData with the given View.
+ static ViewData createEmptyViewData(View view) {
+ return ViewData.create(
+ view,
+ Collections.<List<TagValue>, AggregationData>emptyMap(),
+ view.getWindow()
+ .match(
+ Functions.<AggregationWindowData>returnConstant(
+ CumulativeData.create(ZERO_TIMESTAMP, ZERO_TIMESTAMP)),
+ Functions.<AggregationWindowData>returnConstant(
+ IntervalData.create(ZERO_TIMESTAMP)),
+ Functions.<AggregationWindowData>throwAssertionError()));
+ }
+
+ // Compare the expected and actual DistributionData within the given tolerance.
+ private static void assertDistributionDataEquals(
+ DistributionData expected, DistributionData actual, double tolerance) {
+ assertThat(actual.getMean()).isWithin(tolerance).of(expected.getMean());
+ assertThat(actual.getCount()).isEqualTo(expected.getCount());
+ assertThat(actual.getMean()).isWithin(tolerance).of(expected.getMean());
+ assertThat(actual.getSumOfSquaredDeviations())
+ .isWithin(tolerance)
+ .of(expected.getSumOfSquaredDeviations());
+
+ if (expected.getMax() == Double.NEGATIVE_INFINITY
+ && expected.getMin() == Double.POSITIVE_INFINITY) {
+ assertThat(actual.getMax()).isNegativeInfinity();
+ assertThat(actual.getMin()).isPositiveInfinity();
+ } else {
+ assertThat(actual.getMax()).isWithin(tolerance).of(expected.getMax());
+ assertThat(actual.getMin()).isWithin(tolerance).of(expected.getMin());
+ }
+
+ assertThat(removeTrailingZeros((actual).getBucketCounts()))
+ .isEqualTo(removeTrailingZeros(expected.getBucketCounts()));
+ }
+
+ private static List<Long> removeTrailingZeros(List<Long> longs) {
+ if (longs == null) {
+ return null;
+ }
+ List<Long> truncated = new ArrayList<Long>(longs);
+ while (!truncated.isEmpty() && Iterables.getLast(truncated) == 0) {
+ truncated.remove(truncated.size() - 1);
+ }
+ return truncated;
+ }
+}
diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java
new file mode 100644
index 00000000..5eaa34e5
--- /dev/null
+++ b/impl_core/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java
@@ -0,0 +1,924 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed 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 io.opencensus.implcore.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+import static io.opencensus.implcore.stats.StatsTestUtil.assertAggregationMapEquals;
+import static io.opencensus.implcore.stats.StatsTestUtil.createAggregationData;
+import static io.opencensus.implcore.stats.StatsTestUtil.createEmptyViewData;
+
+import com.google.common.collect.ImmutableMap;
+import io.opencensus.common.Duration;
+import io.opencensus.common.Timestamp;
+import io.opencensus.implcore.internal.SimpleEventQueue;
+import io.opencensus.implcore.tags.TagsComponentImplBase;
+import io.opencensus.stats.Aggregation;
+import io.opencensus.stats.Aggregation.Distribution;
+import io.opencensus.stats.Aggregation.Mean;
+import io.opencensus.stats.Aggregation.Sum;
+import io.opencensus.stats.AggregationData;
+import io.opencensus.stats.AggregationData.MeanData;
+import io.opencensus.stats.AggregationData.SumDataDouble;
+import io.opencensus.stats.AggregationData.SumDataLong;
+import io.opencensus.stats.BucketBoundaries;
+import io.opencensus.stats.Measure;
+import io.opencensus.stats.Measure.MeasureDouble;
+import io.opencensus.stats.Measure.MeasureLong;
+import io.opencensus.stats.MeasureMap;
+import io.opencensus.stats.StatsCollectionState;
+import io.opencensus.stats.View;
+import io.opencensus.stats.View.AggregationWindow.Cumulative;
+import io.opencensus.stats.View.AggregationWindow.Interval;
+import io.opencensus.stats.View.Name;
+import io.opencensus.stats.ViewData;
+import io.opencensus.stats.ViewData.AggregationWindowData;
+import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData;
+import io.opencensus.stats.ViewData.AggregationWindowData.IntervalData;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.Tagger;
+import io.opencensus.tags.TagsComponent;
+import io.opencensus.testing.common.TestClock;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link ViewManagerImpl}. */
+@RunWith(JUnit4.class)
+public class ViewManagerImplTest {
+
+ @Rule public final ExpectedException thrown = ExpectedException.none();
+
+ private static final TagKey KEY = TagKey.create("KEY");
+
+ private static final TagValue VALUE = TagValue.create("VALUE");
+ private static final TagValue VALUE_2 = TagValue.create("VALUE_2");
+
+ private static final String MEASURE_NAME = "my measurement";
+
+ private static final String MEASURE_NAME_2 = "my measurement 2";
+
+ private static final String MEASURE_UNIT = "us";
+
+ private static final String MEASURE_DESCRIPTION = "measure description";
+
+ private static final MeasureDouble MEASURE_DOUBLE =
+ MeasureDouble.create(MEASURE_NAME, MEASURE_DESCRIPTION, MEASURE_UNIT);
+
+ private static final MeasureLong MEASURE_LONG =
+ MeasureLong.create(MEASURE_NAME_2, MEASURE_DESCRIPTION, MEASURE_UNIT);
+
+ private static final Name VIEW_NAME = Name.create("my view");
+ private static final Name VIEW_NAME_2 = Name.create("my view 2");
+
+ private static final String VIEW_DESCRIPTION = "view description";
+
+ private static final Cumulative CUMULATIVE = Cumulative.create();
+
+ private static final double EPSILON = 1e-7;
+ private static final int MILLIS_PER_SECOND = 1000;
+ private static final Duration TEN_SECONDS = Duration.create(10, 0);
+
+ private static final BucketBoundaries BUCKET_BOUNDARIES =
+ BucketBoundaries.create(
+ Arrays.asList(
+ 0.0, 0.2, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0, 7.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0));
+
+ private static final Sum SUM = Sum.create();
+ private static final Mean MEAN = Mean.create();
+ private static final Distribution DISTRIBUTION = Distribution.create(BUCKET_BOUNDARIES);
+
+ private final TestClock clock = TestClock.create();
+
+ private final StatsComponentImplBase statsComponent =
+ new StatsComponentImplBase(new SimpleEventQueue(), clock);
+ private final TagsComponent tagsComponent = new TagsComponentImplBase();
+
+ private final Tagger tagger = tagsComponent.getTagger();
+ private final ViewManagerImpl viewManager = statsComponent.getViewManager();
+ private final StatsRecorderImpl statsRecorder = statsComponent.getStatsRecorder();
+
+ private static View createCumulativeView() {
+ return createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY));
+ }
+
+ private static View createCumulativeView(
+ View.Name name, Measure measure, Aggregation aggregation, List<TagKey> keys) {
+ return View.create(name, VIEW_DESCRIPTION, measure, aggregation, keys, CUMULATIVE);
+ }
+
+ @Test
+ public void testRegisterAndGetCumulativeView() {
+ View view = createCumulativeView();
+ viewManager.registerView(view);
+ assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(view);
+ assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty();
+ assertThat(viewManager.getView(VIEW_NAME).getWindowData()).isInstanceOf(CumulativeData.class);
+ }
+
+ @Test
+ public void testRegisterAndGetIntervalView() {
+ View intervalView =
+ View.create(
+ VIEW_NAME,
+ VIEW_DESCRIPTION,
+ MEASURE_DOUBLE,
+ DISTRIBUTION,
+ Arrays.asList(KEY),
+ Interval.create(Duration.create(60, 0)));
+ viewManager.registerView(intervalView);
+ assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(intervalView);
+ assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty();
+ assertThat(viewManager.getView(VIEW_NAME).getWindowData()).isInstanceOf(IntervalData.class);
+ }
+
+ @Test
+ public void allowRegisteringSameViewTwice() {
+ View view = createCumulativeView();
+ viewManager.registerView(view);
+ viewManager.registerView(view);
+ assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(view);
+ }
+
+ @Test
+ public void preventRegisteringDifferentViewWithSameName() {
+ View view1 =
+ View.create(
+ VIEW_NAME,
+ "View description.",
+ MEASURE_DOUBLE,
+ DISTRIBUTION,
+ Arrays.asList(KEY),
+ CUMULATIVE);
+ View view2 =
+ View.create(
+ VIEW_NAME,
+ "This is a different description.",
+ MEASURE_DOUBLE,
+ DISTRIBUTION,
+ Arrays.asList(KEY),
+ CUMULATIVE);
+ testFailedToRegisterView(
+ view1, view2, "A different view with the same name is already registered");
+ }
+
+ @Test
+ public void preventRegisteringDifferentMeasureWithSameName() {
+ MeasureDouble measure1 = MeasureDouble.create("measure", "description", "1");
+ MeasureLong measure2 = MeasureLong.create("measure", "description", "1");
+ View view1 =
+ View.create(
+ VIEW_NAME, VIEW_DESCRIPTION, measure1, DISTRIBUTION, Arrays.asList(KEY), CUMULATIVE);
+ View view2 =
+ View.create(
+ VIEW_NAME_2, VIEW_DESCRIPTION, measure2, DISTRIBUTION, Arrays.asList(KEY), CUMULATIVE);
+ testFailedToRegisterView(
+ view1, view2, "A different measure with the same name is already registered");
+ }
+
+ private void testFailedToRegisterView(View view1, View view2, String message) {
+ viewManager.registerView(view1);
+ try {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage(message);
+ viewManager.registerView(view2);
+ } finally {
+ assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(view1);
+ }
+ }
+
+ @Test
+ public void returnNullWhenGettingNonexistentViewData() {
+ assertThat(viewManager.getView(VIEW_NAME)).isNull();
+ }
+
+ @Test
+ public void testRecordDouble_distribution_cumulative() {
+ testRecordCumulative(MEASURE_DOUBLE, DISTRIBUTION, 10.0, 20.0, 30.0, 40.0);
+ }
+
+ @Test
+ public void testRecordLong_distribution_cumulative() {
+ testRecordCumulative(MEASURE_LONG, DISTRIBUTION, 1000, 2000, 3000, 4000);
+ }
+
+ @Test
+ public void testRecordDouble_sum_cumulative() {
+ testRecordCumulative(MEASURE_DOUBLE, SUM, 11.1, 22.2, 33.3, 44.4);
+ }
+
+ @Test
+ public void testRecordLong_sum_cumulative() {
+ testRecordCumulative(MEASURE_LONG, SUM, 1000, 2000, 3000, 4000);
+ }
+
+ private void testRecordCumulative(Measure measure, Aggregation aggregation, double... values) {
+ View view = createCumulativeView(VIEW_NAME, measure, aggregation, Arrays.asList(KEY));
+ clock.setTime(Timestamp.create(1, 2));
+ viewManager.registerView(view);
+ TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build();
+ for (double val : values) {
+ putToMeasureMap(statsRecorder.newMeasureMap(), measure, val).record(tags);
+ }
+ clock.setTime(Timestamp.create(3, 4));
+ ViewData viewData = viewManager.getView(VIEW_NAME);
+ assertThat(viewData.getView()).isEqualTo(view);
+ assertThat(viewData.getWindowData())
+ .isEqualTo(CumulativeData.create(Timestamp.create(1, 2), Timestamp.create(3, 4)));
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(aggregation, measure, values)),
+ EPSILON);
+ }
+
+ @Test
+ public void testRecordDouble_mean_interval() {
+ testRecordInterval(
+ MEASURE_DOUBLE,
+ MEAN,
+ new double[] {20.0, -1.0, 1.0, -5.0, 5.0},
+ 9.0,
+ 30.0,
+ MeanData.create((19 * 0.6 + 1) / 4, 4),
+ MeanData.create(0.2 * 5 + 9, 1),
+ MeanData.create(30.0, 1));
+ }
+
+ @Test
+ public void testRecordLong_mean_interval() {
+ testRecordInterval(
+ MEASURE_LONG,
+ MEAN,
+ new double[] {1000, 2000, 3000, 4000, 5000},
+ -5000,
+ 30,
+ MeanData.create((3000 * 0.6 + 12000) / 4, 4),
+ MeanData.create(-4000, 1),
+ MeanData.create(30, 1));
+ }
+
+ @Test
+ public void testRecordDouble_sum_interval() {
+ testRecordInterval(
+ MEASURE_DOUBLE,
+ SUM,
+ new double[] {20.0, -1.0, 1.0, -5.0, 5.0},
+ 9.0,
+ 30.0,
+ SumDataDouble.create(19 * 0.6 + 1),
+ SumDataDouble.create(0.2 * 5 + 9),
+ SumDataDouble.create(30.0));
+ }
+
+ @Test
+ public void testRecordLong_sum_interval() {
+ testRecordInterval(
+ MEASURE_LONG,
+ SUM,
+ new double[] {1000, 2000, 3000, 4000, 5000},
+ -5000,
+ 30,
+ SumDataLong.create(Math.round(3000 * 0.6 + 12000)),
+ SumDataLong.create(-4000),
+ SumDataLong.create(30));
+ }
+
+ private void testRecordInterval(
+ Measure measure,
+ Aggregation aggregation,
+ double[] initialValues, /* There are 5 initial values recorded before we call getView(). */
+ double value6,
+ double value7,
+ AggregationData expectedValues1,
+ AggregationData expectedValues2,
+ AggregationData expectedValues3) {
+ // The interval is 10 seconds, i.e. values should expire after 10 seconds.
+ // Each bucket has a duration of 2.5 seconds.
+ View view =
+ View.create(
+ VIEW_NAME,
+ VIEW_DESCRIPTION,
+ measure,
+ aggregation,
+ Arrays.asList(KEY),
+ Interval.create(TEN_SECONDS));
+ long startTimeMillis = 30 * MILLIS_PER_SECOND; // start at 30s
+ clock.setTime(Timestamp.fromMillis(startTimeMillis));
+ viewManager.registerView(view);
+
+ TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build();
+
+ for (int i = 1; i <= 5; i++) {
+ /*
+ * Add each value in sequence, at 31s, 32s, 33s, etc.
+ * 1st and 2nd values should fall into the first bucket [30.0, 32.5),
+ * 3rd and 4th values should fall into the second bucket [32.5, 35.0),
+ * 5th value should fall into the third bucket [35.0, 37.5).
+ */
+ clock.setTime(Timestamp.fromMillis(startTimeMillis + i * MILLIS_PER_SECOND));
+ putToMeasureMap(statsRecorder.newMeasureMap(), measure, initialValues[i - 1]).record(tags);
+ }
+
+ clock.setTime(Timestamp.fromMillis(startTimeMillis + 8 * MILLIS_PER_SECOND));
+ // 38s, no values should have expired
+ StatsTestUtil.assertAggregationMapEquals(
+ viewManager.getView(VIEW_NAME).getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(aggregation, measure, initialValues)),
+ EPSILON);
+
+ clock.setTime(Timestamp.fromMillis(startTimeMillis + 11 * MILLIS_PER_SECOND));
+ // 41s, 40% of the values in the first bucket should have expired (1 / 2.5 = 0.4).
+ StatsTestUtil.assertAggregationMapEquals(
+ viewManager.getView(VIEW_NAME).getAggregationMap(),
+ ImmutableMap.of(Arrays.asList(VALUE), expectedValues1),
+ EPSILON);
+
+ clock.setTime(Timestamp.fromMillis(startTimeMillis + 12 * MILLIS_PER_SECOND));
+ // 42s, add a new value value1, should fall into bucket [40.0, 42.5)
+ putToMeasureMap(statsRecorder.newMeasureMap(), measure, value6).record(tags);
+
+ clock.setTime(Timestamp.fromMillis(startTimeMillis + 17 * MILLIS_PER_SECOND));
+ // 47s, values in the first and second bucket should have expired, and 80% of values in the
+ // third bucket should have expired. The new value should persist.
+ StatsTestUtil.assertAggregationMapEquals(
+ viewManager.getView(VIEW_NAME).getAggregationMap(),
+ ImmutableMap.of(Arrays.asList(VALUE), expectedValues2),
+ EPSILON);
+
+ clock.setTime(Timestamp.fromMillis(60 * MILLIS_PER_SECOND));
+ // 60s, all previous values should have expired, add another value value2
+ putToMeasureMap(statsRecorder.newMeasureMap(), measure, value7).record(tags);
+ StatsTestUtil.assertAggregationMapEquals(
+ viewManager.getView(VIEW_NAME).getAggregationMap(),
+ ImmutableMap.of(Arrays.asList(VALUE), expectedValues3),
+ EPSILON);
+
+ clock.setTime(Timestamp.fromMillis(100 * MILLIS_PER_SECOND));
+ // 100s, all values should have expired
+ assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty();
+ }
+
+ @Test
+ public void getViewDoesNotClearStats() {
+ View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY));
+ clock.setTime(Timestamp.create(10, 0));
+ viewManager.registerView(view);
+ TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build();
+ statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 0.1).record(tags);
+ clock.setTime(Timestamp.create(11, 0));
+ ViewData viewData1 = viewManager.getView(VIEW_NAME);
+ assertThat(viewData1.getWindowData())
+ .isEqualTo(CumulativeData.create(Timestamp.create(10, 0), Timestamp.create(11, 0)));
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData1.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 0.1)),
+ EPSILON);
+
+ statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 0.2).record(tags);
+ clock.setTime(Timestamp.create(12, 0));
+ ViewData viewData2 = viewManager.getView(VIEW_NAME);
+
+ // The second view should have the same start time as the first view, and it should include both
+ // recorded values:
+ assertThat(viewData2.getWindowData())
+ .isEqualTo(CumulativeData.create(Timestamp.create(10, 0), Timestamp.create(12, 0)));
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData2.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 0.1, 0.2)),
+ EPSILON);
+ }
+
+ @Test
+ public void testRecordCumulativeMultipleTagValues() {
+ viewManager.registerView(
+ createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)));
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 10.0)
+ .record(tagger.emptyBuilder().put(KEY, VALUE).build());
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 30.0)
+ .record(tagger.emptyBuilder().put(KEY, VALUE_2).build());
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 50.0)
+ .record(tagger.emptyBuilder().put(KEY, VALUE_2).build());
+ ViewData viewData = viewManager.getView(VIEW_NAME);
+ assertAggregationMapEquals(
+ viewData.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0),
+ Arrays.asList(VALUE_2),
+ createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 30.0, 50.0)),
+ EPSILON);
+ }
+
+ @Test
+ public void testRecordIntervalMultipleTagValues() {
+ // The interval is 10 seconds, i.e. values should expire after 10 seconds.
+ View view =
+ View.create(
+ VIEW_NAME,
+ VIEW_DESCRIPTION,
+ MEASURE_DOUBLE,
+ DISTRIBUTION,
+ Arrays.asList(KEY),
+ Interval.create(TEN_SECONDS));
+ clock.setTime(Timestamp.create(10, 0)); // Start at 10s
+ viewManager.registerView(view);
+
+ // record for TagValue1 at 11s
+ clock.setTime(Timestamp.fromMillis(11 * MILLIS_PER_SECOND));
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 10.0)
+ .record(tagger.emptyBuilder().put(KEY, VALUE).build());
+
+ // record for TagValue2 at 15s
+ clock.setTime(Timestamp.fromMillis(15 * MILLIS_PER_SECOND));
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 30.0)
+ .record(tagger.emptyBuilder().put(KEY, VALUE_2).build());
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 50.0)
+ .record(tagger.emptyBuilder().put(KEY, VALUE_2).build());
+
+ // get ViewData at 19s, no stats should have expired.
+ clock.setTime(Timestamp.fromMillis(19 * MILLIS_PER_SECOND));
+ ViewData viewData1 = viewManager.getView(VIEW_NAME);
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData1.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0),
+ Arrays.asList(VALUE_2),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 30.0, 50.0)),
+ EPSILON);
+
+ // record for TagValue2 again at 20s
+ clock.setTime(Timestamp.fromMillis(20 * MILLIS_PER_SECOND));
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 40.0)
+ .record(tagger.emptyBuilder().put(KEY, VALUE_2).build());
+
+ // get ViewData at 25s, stats for TagValue1 should have expired.
+ clock.setTime(Timestamp.fromMillis(25 * MILLIS_PER_SECOND));
+ ViewData viewData2 = viewManager.getView(VIEW_NAME);
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData2.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE_2),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 30.0, 50.0, 40.0)),
+ EPSILON);
+
+ // get ViewData at 30s, the first two values for TagValue2 should have expired.
+ clock.setTime(Timestamp.fromMillis(30 * MILLIS_PER_SECOND));
+ ViewData viewData3 = viewManager.getView(VIEW_NAME);
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData3.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE_2),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 40.0)),
+ EPSILON);
+
+ // get ViewData at 40s, all stats should have expired.
+ clock.setTime(Timestamp.fromMillis(40 * MILLIS_PER_SECOND));
+ ViewData viewData4 = viewManager.getView(VIEW_NAME);
+ assertThat(viewData4.getAggregationMap()).isEmpty();
+ }
+
+ // This test checks that MeasureMaper.record(...) does not throw an exception when no views are
+ // registered.
+ @Test
+ public void allowRecordingWithoutRegisteringMatchingViewData() {
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 10)
+ .record(tagger.emptyBuilder().put(KEY, VALUE).build());
+ }
+
+ @Test
+ public void testRecordWithEmptyStatsContext() {
+ viewManager.registerView(
+ createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)));
+ // DEFAULT doesn't have tags, but the view has tag key "KEY".
+ statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 10.0).record(tagger.empty());
+ ViewData viewData = viewManager.getView(VIEW_NAME);
+ assertAggregationMapEquals(
+ viewData.getAggregationMap(),
+ ImmutableMap.of(
+ // Tag is missing for associated measureValues, should use default tag value
+ // "unknown/not set".
+ Arrays.asList(MutableViewData.UNKNOWN_TAG_VALUE),
+ // Should record stats with default tag value: "KEY" : "unknown/not set".
+ createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0)),
+ EPSILON);
+ }
+
+ @Test
+ public void testRecord_MeasureNameNotMatch() {
+ testRecord_MeasureNotMatch(
+ MeasureDouble.create(MEASURE_NAME, "measure", MEASURE_UNIT),
+ MeasureDouble.create(MEASURE_NAME_2, "measure", MEASURE_UNIT),
+ 10.0);
+ }
+
+ @Test
+ public void testRecord_MeasureTypeNotMatch() {
+ testRecord_MeasureNotMatch(
+ MeasureLong.create(MEASURE_NAME, "measure", MEASURE_UNIT),
+ MeasureDouble.create(MEASURE_NAME, "measure", MEASURE_UNIT),
+ 10.0);
+ }
+
+ private void testRecord_MeasureNotMatch(Measure measure1, Measure measure2, double value) {
+ viewManager.registerView(createCumulativeView(VIEW_NAME, measure1, MEAN, Arrays.asList(KEY)));
+ TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build();
+ putToMeasureMap(statsRecorder.newMeasureMap(), measure2, value).record(tags);
+ ViewData view = viewManager.getView(VIEW_NAME);
+ assertThat(view.getAggregationMap()).isEmpty();
+ }
+
+ @Test
+ public void testRecordWithTagsThatDoNotMatchViewData() {
+ viewManager.registerView(
+ createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)));
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 10.0)
+ .record(tagger.emptyBuilder().put(TagKey.create("wrong key"), VALUE).build());
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 50.0)
+ .record(tagger.emptyBuilder().put(TagKey.create("another wrong key"), VALUE).build());
+ ViewData viewData = viewManager.getView(VIEW_NAME);
+ assertAggregationMapEquals(
+ viewData.getAggregationMap(),
+ ImmutableMap.of(
+ // Won't record the unregistered tag key, for missing registered keys will use default
+ // tag value : "unknown/not set".
+ Arrays.asList(MutableViewData.UNKNOWN_TAG_VALUE),
+ // Should record stats with default tag value: "KEY" : "unknown/not set".
+ createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0, 50.0)),
+ EPSILON);
+ }
+
+ @Test
+ public void testViewDataWithMultipleTagKeys() {
+ TagKey key1 = TagKey.create("Key-1");
+ TagKey key2 = TagKey.create("Key-2");
+ viewManager.registerView(
+ createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(key1, key2)));
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 1.1)
+ .record(
+ tagger
+ .emptyBuilder()
+ .put(key1, TagValue.create("v1"))
+ .put(key2, TagValue.create("v10"))
+ .build());
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 2.2)
+ .record(
+ tagger
+ .emptyBuilder()
+ .put(key1, TagValue.create("v1"))
+ .put(key2, TagValue.create("v20"))
+ .build());
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 3.3)
+ .record(
+ tagger
+ .emptyBuilder()
+ .put(key1, TagValue.create("v2"))
+ .put(key2, TagValue.create("v10"))
+ .build());
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 4.4)
+ .record(
+ tagger
+ .emptyBuilder()
+ .put(key1, TagValue.create("v1"))
+ .put(key2, TagValue.create("v10"))
+ .build());
+ ViewData viewData = viewManager.getView(VIEW_NAME);
+ assertAggregationMapEquals(
+ viewData.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(TagValue.create("v1"), TagValue.create("v10")),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 1.1, 4.4),
+ Arrays.asList(TagValue.create("v1"), TagValue.create("v20")),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 2.2),
+ Arrays.asList(TagValue.create("v2"), TagValue.create("v10")),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 3.3)),
+ EPSILON);
+ }
+
+ @Test
+ public void testMultipleViewSameMeasure() {
+ final View view1 =
+ createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY));
+ final View view2 =
+ createCumulativeView(VIEW_NAME_2, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY));
+ clock.setTime(Timestamp.create(1, 1));
+ viewManager.registerView(view1);
+ clock.setTime(Timestamp.create(2, 2));
+ viewManager.registerView(view2);
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 5.0)
+ .record(tagger.emptyBuilder().put(KEY, VALUE).build());
+ clock.setTime(Timestamp.create(3, 3));
+ ViewData viewData1 = viewManager.getView(VIEW_NAME);
+ clock.setTime(Timestamp.create(4, 4));
+ ViewData viewData2 = viewManager.getView(VIEW_NAME_2);
+ assertThat(viewData1.getWindowData())
+ .isEqualTo(CumulativeData.create(Timestamp.create(1, 1), Timestamp.create(3, 3)));
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData1.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 5.0)),
+ EPSILON);
+ assertThat(viewData2.getWindowData())
+ .isEqualTo(CumulativeData.create(Timestamp.create(2, 2), Timestamp.create(4, 4)));
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData2.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 5.0)),
+ EPSILON);
+ }
+
+ @Test
+ public void testMultipleViews_DifferentMeasureNames() {
+ testMultipleViews_DifferentMeasures(
+ MeasureDouble.create(MEASURE_NAME, MEASURE_DESCRIPTION, MEASURE_UNIT),
+ MeasureDouble.create(MEASURE_NAME_2, MEASURE_DESCRIPTION, MEASURE_UNIT),
+ 1.1,
+ 2.2);
+ }
+
+ @Test
+ public void testMultipleViews_DifferentMeasureTypes() {
+ testMultipleViews_DifferentMeasures(
+ MeasureDouble.create(MEASURE_NAME, MEASURE_DESCRIPTION, MEASURE_UNIT),
+ MeasureLong.create(MEASURE_NAME_2, MEASURE_DESCRIPTION, MEASURE_UNIT),
+ 1.1,
+ 5000);
+ }
+
+ private void testMultipleViews_DifferentMeasures(
+ Measure measure1, Measure measure2, double value1, double value2) {
+ final View view1 = createCumulativeView(VIEW_NAME, measure1, DISTRIBUTION, Arrays.asList(KEY));
+ final View view2 =
+ createCumulativeView(VIEW_NAME_2, measure2, DISTRIBUTION, Arrays.asList(KEY));
+ clock.setTime(Timestamp.create(1, 0));
+ viewManager.registerView(view1);
+ clock.setTime(Timestamp.create(2, 0));
+ viewManager.registerView(view2);
+ TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build();
+ MeasureMap measureMap = statsRecorder.newMeasureMap();
+ putToMeasureMap(measureMap, measure1, value1);
+ putToMeasureMap(measureMap, measure2, value2);
+ measureMap.record(tags);
+ clock.setTime(Timestamp.create(3, 0));
+ ViewData viewData1 = viewManager.getView(VIEW_NAME);
+ clock.setTime(Timestamp.create(4, 0));
+ ViewData viewData2 = viewManager.getView(VIEW_NAME_2);
+ assertThat(viewData1.getWindowData())
+ .isEqualTo(CumulativeData.create(Timestamp.create(1, 0), Timestamp.create(3, 0)));
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData1.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, measure1, value1)),
+ EPSILON);
+ assertThat(viewData2.getWindowData())
+ .isEqualTo(CumulativeData.create(Timestamp.create(2, 0), Timestamp.create(4, 0)));
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData2.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(DISTRIBUTION, measure2, value2)),
+ EPSILON);
+ }
+
+ @Test
+ public void testGetCumulativeViewDataWithEmptyBucketBoundaries() {
+ Aggregation noHistogram =
+ Distribution.create(BucketBoundaries.create(Collections.<Double>emptyList()));
+ View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, noHistogram, Arrays.asList(KEY));
+ clock.setTime(Timestamp.create(1, 0));
+ viewManager.registerView(view);
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 1.1)
+ .record(tagger.emptyBuilder().put(KEY, VALUE).build());
+ clock.setTime(Timestamp.create(3, 0));
+ ViewData viewData = viewManager.getView(VIEW_NAME);
+ assertThat(viewData.getWindowData())
+ .isEqualTo(CumulativeData.create(Timestamp.create(1, 0), Timestamp.create(3, 0)));
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(noHistogram, MEASURE_DOUBLE, 1.1)),
+ EPSILON);
+ }
+
+ @Test
+ public void testGetCumulativeViewDataWithoutBucketBoundaries() {
+ View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY));
+ clock.setTime(Timestamp.create(1, 0));
+ viewManager.registerView(view);
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 1.1)
+ .record(tagger.emptyBuilder().put(KEY, VALUE).build());
+ clock.setTime(Timestamp.create(3, 0));
+ ViewData viewData = viewManager.getView(VIEW_NAME);
+ assertThat(viewData.getWindowData())
+ .isEqualTo(CumulativeData.create(Timestamp.create(1, 0), Timestamp.create(3, 0)));
+ StatsTestUtil.assertAggregationMapEquals(
+ viewData.getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE), StatsTestUtil.createAggregationData(MEAN, MEASURE_DOUBLE, 1.1)),
+ EPSILON);
+ }
+
+ @Test
+ public void registerRecordAndGetView_StatsDisabled() {
+ statsComponent.setState(StatsCollectionState.DISABLED);
+ View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY));
+ viewManager.registerView(view);
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 1.1)
+ .record(tagger.emptyBuilder().put(KEY, VALUE).build());
+ assertThat(viewManager.getView(VIEW_NAME)).isEqualTo(createEmptyViewData(view));
+ }
+
+ @Test
+ public void registerRecordAndGetView_StatsReenabled() {
+ statsComponent.setState(StatsCollectionState.DISABLED);
+ statsComponent.setState(StatsCollectionState.ENABLED);
+ View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY));
+ viewManager.registerView(view);
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 1.1)
+ .record(tagger.emptyBuilder().put(KEY, VALUE).build());
+ StatsTestUtil.assertAggregationMapEquals(
+ viewManager.getView(VIEW_NAME).getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE), StatsTestUtil.createAggregationData(MEAN, MEASURE_DOUBLE, 1.1)),
+ EPSILON);
+ }
+
+ @Test
+ public void registerViewWithStatsDisabled_RecordAndGetViewWithStatsEnabled() {
+ statsComponent.setState(StatsCollectionState.DISABLED);
+ View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY));
+ viewManager.registerView(view); // view will still be registered.
+
+ statsComponent.setState(StatsCollectionState.ENABLED);
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 1.1)
+ .record(tagger.emptyBuilder().put(KEY, VALUE).build());
+ StatsTestUtil.assertAggregationMapEquals(
+ viewManager.getView(VIEW_NAME).getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE), StatsTestUtil.createAggregationData(MEAN, MEASURE_DOUBLE, 1.1)),
+ EPSILON);
+ }
+
+ @Test
+ public void registerDifferentViewWithSameNameWithStatsDisabled() {
+ statsComponent.setState(StatsCollectionState.DISABLED);
+ View view1 =
+ View.create(
+ VIEW_NAME,
+ "View description.",
+ MEASURE_DOUBLE,
+ DISTRIBUTION,
+ Arrays.asList(KEY),
+ CUMULATIVE);
+ View view2 =
+ View.create(
+ VIEW_NAME,
+ "This is a different description.",
+ MEASURE_DOUBLE,
+ DISTRIBUTION,
+ Arrays.asList(KEY),
+ CUMULATIVE);
+ testFailedToRegisterView(
+ view1, view2, "A different view with the same name is already registered");
+ }
+
+ @Test
+ public void settingStateToDisabledWillClearStats_Cumulative() {
+ View cumulativeView = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY));
+ settingStateToDisabledWillClearStats(cumulativeView);
+ }
+
+ @Test
+ public void settingStateToDisabledWillClearStats_Interval() {
+ View intervalView =
+ View.create(
+ VIEW_NAME_2,
+ VIEW_DESCRIPTION,
+ MEASURE_DOUBLE,
+ MEAN,
+ Arrays.asList(KEY),
+ Interval.create(Duration.create(60, 0)));
+ settingStateToDisabledWillClearStats(intervalView);
+ }
+
+ private void settingStateToDisabledWillClearStats(View view) {
+ Timestamp timestamp1 = Timestamp.create(1, 0);
+ clock.setTime(timestamp1);
+ viewManager.registerView(view);
+ statsRecorder
+ .newMeasureMap()
+ .put(MEASURE_DOUBLE, 1.1)
+ .record(tagger.emptyBuilder().put(KEY, VALUE).build());
+ StatsTestUtil.assertAggregationMapEquals(
+ viewManager.getView(view.getName()).getAggregationMap(),
+ ImmutableMap.of(
+ Arrays.asList(VALUE),
+ StatsTestUtil.createAggregationData(view.getAggregation(), view.getMeasure(), 1.1)),
+ EPSILON);
+
+ Timestamp timestamp2 = Timestamp.create(2, 0);
+ clock.setTime(timestamp2);
+ statsComponent.setState(StatsCollectionState.DISABLED); // This will clear stats.
+ assertThat(viewManager.getView(view.getName())).isEqualTo(createEmptyViewData(view));
+
+ Timestamp timestamp3 = Timestamp.create(3, 0);
+ clock.setTime(timestamp3);
+ statsComponent.setState(StatsCollectionState.ENABLED);
+
+ Timestamp timestamp4 = Timestamp.create(4, 0);
+ clock.setTime(timestamp4);
+ // This ViewData does not have any stats, but it should not be an empty ViewData, since it has
+ // non-zero TimeStamps.
+ ViewData viewData = viewManager.getView(view.getName());
+ assertThat(viewData.getAggregationMap()).isEmpty();
+ AggregationWindowData windowData = viewData.getWindowData();
+ if (windowData instanceof CumulativeData) {
+ assertThat(windowData).isEqualTo(CumulativeData.create(timestamp3, timestamp4));
+ } else {
+ assertThat(windowData).isEqualTo(IntervalData.create(timestamp4));
+ }
+ }
+
+ private static MeasureMap putToMeasureMap(MeasureMap measureMap, Measure measure, double value) {
+ if (measure instanceof MeasureDouble) {
+ return measureMap.put((MeasureDouble) measure, value);
+ } else if (measure instanceof MeasureLong) {
+ return measureMap.put((MeasureLong) measure, Math.round(value));
+ } else {
+ // Future measures.
+ throw new AssertionError();
+ }
+ }
+}