Skip to content
This repository was archived by the owner on Dec 23, 2023. It is now read-only.

Commit 8b19f6e

Browse files
authored
Add IntervalBucket and tests. (#537)
1 parent e24096c commit 8b19f6e

File tree

5 files changed

+221
-1
lines changed

5 files changed

+221
-1
lines changed

api/src/main/java/io/opencensus/common/Duration.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
*/
3232
@Immutable
3333
@AutoValue
34+
// TODO(songya): implements Comparable<Duration>
3435
public abstract class Duration {
3536
private static final Duration ZERO = create(0, 0);
3637

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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.base.Preconditions.checkArgument;
20+
import static com.google.common.base.Preconditions.checkNotNull;
21+
import static io.opencensus.implcore.stats.MutableViewData.toMillis;
22+
23+
import com.google.common.collect.Maps;
24+
import io.opencensus.common.Duration;
25+
import io.opencensus.common.Timestamp;
26+
import io.opencensus.stats.Aggregation;
27+
import io.opencensus.tags.TagValue;
28+
import java.util.List;
29+
import java.util.Map;
30+
31+
/** The bucket with aggregated {@code MeasureValue}s used for {@code IntervalViewData}. */
32+
final class IntervalBucket {
33+
34+
private final Timestamp start;
35+
private final Duration duration;
36+
private final List<Aggregation> aggregations;
37+
private final Map<List<TagValue>, List<MutableAggregation>> tagValueAggregationMap =
38+
Maps.newHashMap();
39+
40+
IntervalBucket(Timestamp start, Duration duration, List<Aggregation> aggregations) {
41+
checkNotNull(start, "Start");
42+
checkNotNull(duration, "Duration");
43+
checkNotNull(aggregations, "Aggregations");
44+
this.start = start;
45+
this.duration = duration;
46+
this.aggregations = aggregations;
47+
}
48+
49+
Map<List<TagValue>, List<MutableAggregation>> getTagValueAggregationMap() {
50+
return tagValueAggregationMap;
51+
}
52+
53+
Timestamp getStart() {
54+
return start;
55+
}
56+
57+
// Puts a new value into the internal MutableAggregations, based on the TagValues.
58+
void record(List<TagValue> tagValues, double value) {
59+
if (!tagValueAggregationMap.containsKey(tagValues)) {
60+
tagValueAggregationMap.put(
61+
tagValues, MutableViewData.createMutableAggregations(aggregations));
62+
}
63+
for (MutableAggregation aggregation : tagValueAggregationMap.get(tagValues)) {
64+
aggregation.add(value);
65+
}
66+
}
67+
68+
/*
69+
* Returns how much fraction of duration has passed in this IntervalBucket. For example, if this
70+
* bucket starts at 10s and has a duration of 20s, and now is 15s, then getFraction() should
71+
* return (15 - 10) / 20 = 0.25.
72+
*
73+
* This IntervalBucket must be current, i.e. the current timestamp must be within
74+
* [this.start, this.start + this.duration).
75+
*/
76+
double getFraction(Timestamp now) {
77+
Duration elapsedTime = now.subtractTimestamp(start);
78+
checkArgument(toMillis(elapsedTime) >= 0 && toMillis(elapsedTime) < toMillis(duration),
79+
"This bucket must be current.");
80+
return ((double) toMillis(elapsedTime)) / toMillis(duration);
81+
}
82+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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+
21+
import io.opencensus.common.Duration;
22+
import io.opencensus.common.Timestamp;
23+
import io.opencensus.implcore.stats.MutableAggregation.MutableCount;
24+
import io.opencensus.implcore.stats.MutableAggregation.MutableHistogram;
25+
import io.opencensus.implcore.stats.MutableAggregation.MutableSum;
26+
import io.opencensus.stats.Aggregation;
27+
import io.opencensus.stats.Aggregation.Count;
28+
import io.opencensus.stats.Aggregation.Histogram;
29+
import io.opencensus.stats.Aggregation.Sum;
30+
import io.opencensus.stats.BucketBoundaries;
31+
import io.opencensus.tags.TagValue;
32+
import io.opencensus.tags.TagValue.TagValueString;
33+
import java.util.Arrays;
34+
import java.util.Collections;
35+
import java.util.List;
36+
import org.junit.Rule;
37+
import org.junit.Test;
38+
import org.junit.rules.ExpectedException;
39+
import org.junit.runner.RunWith;
40+
import org.junit.runners.JUnit4;
41+
42+
/** Tests for {@link IntervalBucket}. */
43+
@RunWith(JUnit4.class)
44+
public class IntervalBucketTest {
45+
46+
@Rule public final ExpectedException thrown = ExpectedException.none();
47+
48+
private static final double TOLERANCE = 1e-6;
49+
private static final Duration MINUTE = Duration.create(60, 0);
50+
private static final Timestamp START = Timestamp.create(60, 0);
51+
private static final BucketBoundaries BUCKET_BOUNDARIES =
52+
BucketBoundaries.create(Arrays.asList(-10.0, 0.0, 10.0));
53+
private static final List<Aggregation> AGGREGATIONS_V1 =
54+
Collections.unmodifiableList(Arrays.asList(
55+
Sum.create(), Count.create(), Histogram.create(BUCKET_BOUNDARIES)));
56+
57+
@Test
58+
public void preventNullStartTime() {
59+
thrown.expect(NullPointerException.class);
60+
new IntervalBucket(null, MINUTE, AGGREGATIONS_V1);
61+
}
62+
63+
@Test
64+
public void preventNullDuration() {
65+
thrown.expect(NullPointerException.class);
66+
new IntervalBucket(START, null, AGGREGATIONS_V1);
67+
}
68+
69+
@Test
70+
public void preventNullAggregationList() {
71+
thrown.expect(NullPointerException.class);
72+
new IntervalBucket(START, MINUTE, null);
73+
}
74+
75+
@Test
76+
public void testGetTagValueAggregationMap_empty() {
77+
assertThat(new IntervalBucket(START, MINUTE, AGGREGATIONS_V1).getTagValueAggregationMap())
78+
.isEmpty();
79+
}
80+
81+
@Test
82+
public void testGetStart() {
83+
assertThat(new IntervalBucket(START, MINUTE, AGGREGATIONS_V1).getStart()).isEqualTo(START);
84+
}
85+
86+
@Test
87+
public void testRecord() {
88+
IntervalBucket bucket = new IntervalBucket(START, MINUTE, AGGREGATIONS_V1);
89+
List<TagValue> tagValues1 = Arrays.<TagValue>asList(TagValueString.create("VALUE1"));
90+
List<TagValue> tagValues2 = Arrays.<TagValue>asList(TagValueString.create("VALUE2"));
91+
bucket.record(tagValues1, 5.0);
92+
bucket.record(tagValues1, 15.0);
93+
bucket.record(tagValues2, 10.0);
94+
assertThat(bucket.getTagValueAggregationMap()).containsKey(tagValues1);
95+
verifyMutableAggregations(bucket.getTagValueAggregationMap().get(tagValues1),
96+
20.0, 2, new long[]{0, 0, 1, 1}, TOLERANCE);
97+
assertThat(bucket.getTagValueAggregationMap()).containsKey(tagValues2);
98+
verifyMutableAggregations(bucket.getTagValueAggregationMap().get(tagValues2),
99+
10.0, 1, new long[]{0, 0, 0, 1}, TOLERANCE);
100+
}
101+
102+
private static void verifyMutableAggregations(
103+
List<MutableAggregation> aggregations, double sum, long count, long[] bucketCounts,
104+
double tolerance) {
105+
assertThat(aggregations).hasSize(3);
106+
assertThat(aggregations.get(0)).isInstanceOf(MutableSum.class);
107+
assertThat(((MutableSum) aggregations.get(0)).getSum()).isWithin(tolerance).of(sum);
108+
assertThat(aggregations.get(1)).isInstanceOf(MutableCount.class);
109+
assertThat(((MutableCount) aggregations.get(1)).getCount()).isEqualTo(count);
110+
assertThat(aggregations.get(2)).isInstanceOf(MutableHistogram.class);
111+
assertThat(((MutableHistogram) aggregations.get(2)).getBucketCounts()).isEqualTo(bucketCounts);
112+
}
113+
114+
@Test
115+
public void testGetFraction() {
116+
Timestamp thirtySecondsAfterStart = Timestamp.create(90, 0);
117+
assertThat(
118+
new IntervalBucket(START, MINUTE, AGGREGATIONS_V1).getFraction(thirtySecondsAfterStart))
119+
.isWithin(TOLERANCE).of(0.5);
120+
}
121+
122+
@Test
123+
public void preventCallingGetFractionOnPastBuckets() {
124+
IntervalBucket bucket = new IntervalBucket(START, MINUTE, AGGREGATIONS_V1);
125+
Timestamp twoMinutesAfterStart = Timestamp.create(180, 0);
126+
thrown.expect(IllegalArgumentException.class);
127+
bucket.getFraction(twoMinutesAfterStart);
128+
}
129+
130+
@Test
131+
public void preventCallingGetFractionOnFutureBuckets() {
132+
IntervalBucket bucket = new IntervalBucket(START, MINUTE, AGGREGATIONS_V1);
133+
Timestamp thirtySecondsBeforeStart = Timestamp.create(30, 0);
134+
thrown.expect(IllegalArgumentException.class);
135+
bucket.getFraction(thirtySecondsBeforeStart);
136+
}
137+
}

gradle/wrapper/gradle-wrapper.jar

0 Bytes
Binary file not shown.

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#Tue Jul 11 16:36:46 PDT 2017
1+
#Sun Sep 03 20:39:13 PDT 2017
22
distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME

0 commit comments

Comments
 (0)