1/*
2 * Copyright (C) 2018 The Android Open Source Project
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
17package com.android.server.wifi.util;
18
19import static org.hamcrest.core.IsEqual.equalTo;
20
21import android.util.SparseIntArray;
22
23import org.junit.Before;
24import org.junit.Rule;
25import org.junit.Test;
26import org.junit.rules.ErrorCollector;
27import org.mockito.MockitoAnnotations;
28
29/**
30 * Unit test harness for MetricsUtils.
31 */
32public class MetricsUtilsTest {
33    @Rule
34    public ErrorCollector collector = new ErrorCollector();
35
36    /**
37     * Pre-test configuration. Initialize and install mocks.
38     */
39    @Before
40    public void setUp() throws Exception {
41        MockitoAnnotations.initMocks(this);
42    }
43
44    /**
45     * Histogram of following buckets, start[i] = 0 + 1 * 10^i with 9 sub-buckets, i=0,...,5
46     * 1 - 10: 9 sub-buckets each of width 1
47     * 10 - 100: 10
48     * 100 - 10e3: 10^2
49     * 10e3 - 10e4: 10^3
50     * 10e4 - 10e5: 10^4
51     * 10e5 - 10e6: 10^5
52     */
53    private static final MetricsUtils.LogHistParms HIST1 = new MetricsUtils.LogHistParms(0, 1, 10,
54            9, 6);
55
56    /**
57     * Histogram of following buckets, start[i] = -20 + 2 * 5^i with 40 sub-buckets, i=0,...,2
58     * -18 - -10: 40 sub-bucket each of width 0.2
59     * -10 - 30: 1
60     * 30 - 230: 5
61     */
62    private static final MetricsUtils.LogHistParms HIST2 = new MetricsUtils.LogHistParms(-20, 2, 5,
63            40, 3);
64
65    // Linear histogram of following buckets:
66    //   <10
67    //   [10, 30)
68    //   [30, 60)
69    //   [60, 100)
70    //   >100
71    private static final int[] HIST_LINEAR = {10, 30, 60, 100};
72
73    /**
74     * Validate that a set of values are bucketed correctly into the histogram, and that they are
75     * converted to a primitive proto-buffer array correctly.
76     */
77    @Test
78    public void testHistBucketing() {
79        SparseIntArray hist1 = new SparseIntArray();
80        SparseIntArray hist2 = new SparseIntArray();
81
82        bucketValueAndVerify("HIST1: x=", -5, hist1, HIST1, 0, 1);
83        bucketValueAndVerify("HIST1: x=", 0, hist1, HIST1, 0, 2);
84        bucketValueAndVerify("HIST1: x=", 1, hist1, HIST1, 0, 3);
85        bucketValueAndVerify("HIST1: x=", 9, hist1, HIST1, 8, 1);
86        bucketValueAndVerify("HIST1: x=", 10, hist1, HIST1, 9, 1);
87        bucketValueAndVerify("HIST1: x=", 99, hist1, HIST1, 17, 1);
88        bucketValueAndVerify("HIST1: x=", 100, hist1, HIST1, 18, 1);
89        bucketValueAndVerify("HIST1: x=", 989, hist1, HIST1, 26, 1);
90        bucketValueAndVerify("HIST1: x=", 990, hist1, HIST1, 26, 2);
91        bucketValueAndVerify("HIST1: x=", 999, hist1, HIST1, 26, 3);
92        bucketValueAndVerify("HIST1: x=", 1000, hist1, HIST1, 27, 1);
93        bucketValueAndVerify("HIST1: x=", 9899, hist1, HIST1, 35, 1);
94        bucketValueAndVerify("HIST1: x=", 9900, hist1, HIST1, 35, 2);
95        bucketValueAndVerify("HIST1: x=", 9999, hist1, HIST1, 35, 3);
96        bucketValueAndVerify("HIST1: x=", 10000, hist1, HIST1, 36, 1);
97        bucketValueAndVerify("HIST1: x=", 98999, hist1, HIST1, 44, 1);
98        bucketValueAndVerify("HIST1: x=", 99000, hist1, HIST1, 44, 2);
99        bucketValueAndVerify("HIST1: x=", 99999, hist1, HIST1, 44, 3);
100        bucketValueAndVerify("HIST1: x=", 100000, hist1, HIST1, 45, 1);
101        bucketValueAndVerify("HIST1: x=", 989999, hist1, HIST1, 53, 1);
102        bucketValueAndVerify("HIST1: x=", 990000, hist1, HIST1, 53, 2);
103        bucketValueAndVerify("HIST1: x=", 999999, hist1, HIST1, 53, 3);
104        bucketValueAndVerify("HIST1: x=", 1000000, hist1, HIST1, 53, 4);
105        bucketValueAndVerify("HIST1: x=", 1000001, hist1, HIST1, 53, 5);
106        bucketValueAndVerify("HIST1: x=", 5000000, hist1, HIST1, 53, 6);
107        bucketValueAndVerify("HIST1: x=", 10000000, hist1, HIST1, 53, 7);
108
109        MetricsUtils.GenericBucket[] phb1 = MetricsUtils.logHistogramToGenericBuckets(hist1, HIST1);
110        collector.checkThat("Number of buckets #1", phb1.length, equalTo(hist1.size()));
111        validateProtoHistBucket("Bucket1[0]", phb1[0], 1, 2, 3);
112        validateProtoHistBucket("Bucket1[1]", phb1[1], 9, 10, 1);
113        validateProtoHistBucket("Bucket1[2]", phb1[2], 10, 20, 1);
114        validateProtoHistBucket("Bucket1[3]", phb1[3], 90, 100, 1);
115        validateProtoHistBucket("Bucket1[4]", phb1[4], 100, 200, 1);
116        validateProtoHistBucket("Bucket1[5]", phb1[5], 900, 1000, 3);
117        validateProtoHistBucket("Bucket1[6]", phb1[6], 1000, 2000, 1);
118        validateProtoHistBucket("Bucket1[7]", phb1[7], 9000, 10000, 3);
119        validateProtoHistBucket("Bucket1[8]", phb1[8], 10000, 20000, 1);
120        validateProtoHistBucket("Bucket1[9]", phb1[9], 90000, 100000, 3);
121        validateProtoHistBucket("Bucket1[10]", phb1[10], 100000, 200000, 1);
122        validateProtoHistBucket("Bucket1[11]", phb1[11], 900000, 1000000, 7);
123
124        bucketValueAndVerify("HIST2: x=", -20, hist2, HIST2, 0, 1);
125        bucketValueAndVerify("HIST2: x=", -18, hist2, HIST2, 0, 2);
126        bucketValueAndVerify("HIST2: x=", -17, hist2, HIST2, 5, 1);
127        bucketValueAndVerify("HIST2: x=", -11, hist2, HIST2, 35, 1);
128        bucketValueAndVerify("HIST2: x=", -10, hist2, HIST2, 40, 1);
129        bucketValueAndVerify("HIST2: x=", 29, hist2, HIST2, 79, 1);
130        bucketValueAndVerify("HIST2: x=", 30, hist2, HIST2, 80, 1);
131        bucketValueAndVerify("HIST2: x=", 229, hist2, HIST2, 119, 1);
132        bucketValueAndVerify("HIST2: x=", 230, hist2, HIST2, 119, 2);
133        bucketValueAndVerify("HIST2: x=", 300, hist2, HIST2, 119, 3);
134        bucketValueAndVerify("HIST2: x=", 1000000, hist2, HIST2, 119, 4);
135
136        MetricsUtils.GenericBucket[] phb2 = MetricsUtils.logHistogramToGenericBuckets(hist2, HIST2);
137        collector.checkThat("Number of buckets #2", phb2.length, equalTo(hist2.size()));
138        validateProtoHistBucket("Bucket2[0]", phb2[0], -18, -17, 2);
139        validateProtoHistBucket("Bucket2[1]", phb2[1], -17, -16, 1);
140        validateProtoHistBucket("Bucket2[2]", phb2[2], -11, -10, 1);
141        validateProtoHistBucket("Bucket2[3]", phb2[3], -10, -9, 1);
142        validateProtoHistBucket("Bucket2[4]", phb2[4], 29, 30, 1);
143        validateProtoHistBucket("Bucket2[5]", phb2[5], 30, 35, 1);
144        validateProtoHistBucket("Bucket2[6]", phb2[6], 225, 230, 4);
145    }
146
147    /**
148     * Validate that a set of values are bucketed correctly into the linear histogram, and that
149     * they are converted to a primitive proto-buffer array correctly.
150     */
151    @Test
152    public void testLinearHistBucketing() {
153        SparseIntArray hist = new SparseIntArray();
154
155        bucketValueAndVerify("HIST_LINEAR: x=", -5, hist, HIST_LINEAR, 0, 1);
156        bucketValueAndVerify("HIST_LINEAR: x=", 0, hist, HIST_LINEAR, 0, 2);
157        bucketValueAndVerify("HIST_LINEAR: x=", 1, hist, HIST_LINEAR, 0, 3);
158        bucketValueAndVerify("HIST_LINEAR: x=", 9, hist, HIST_LINEAR, 0, 4);
159        bucketValueAndVerify("HIST_LINEAR: x=", 10, hist, HIST_LINEAR, 1, 1);
160        bucketValueAndVerify("HIST_LINEAR: x=", 20, hist, HIST_LINEAR, 1, 2);
161        bucketValueAndVerify("HIST_LINEAR: x=", 30, hist, HIST_LINEAR, 2, 1);
162        bucketValueAndVerify("HIST_LINEAR: x=", 40, hist, HIST_LINEAR, 2, 2);
163        bucketValueAndVerify("HIST_LINEAR: x=", 50, hist, HIST_LINEAR, 2, 3);
164        bucketValueAndVerify("HIST_LINEAR: x=", 60, hist, HIST_LINEAR, 3, 1);
165        bucketValueAndVerify("HIST_LINEAR: x=", 70, hist, HIST_LINEAR, 3, 2);
166        bucketValueAndVerify("HIST_LINEAR: x=", 80, hist, HIST_LINEAR, 3, 3);
167        bucketValueAndVerify("HIST_LINEAR: x=", 90, hist, HIST_LINEAR, 3, 4);
168        bucketValueAndVerify("HIST_LINEAR: x=", 100, hist, HIST_LINEAR, 4, 1);
169        bucketValueAndVerify("HIST_LINEAR: x=", 110, hist, HIST_LINEAR, 4, 2);
170        bucketValueAndVerify("HIST_LINEAR: x=", 98999, hist, HIST_LINEAR, 4, 3);
171
172        MetricsUtils.GenericBucket[] phb = MetricsUtils.linearHistogramToGenericBuckets(hist,
173                HIST_LINEAR);
174        collector.checkThat("Number of buckets", phb.length, equalTo(hist.size()));
175        validateProtoHistBucket("Bucket[0]", phb[0], Integer.MIN_VALUE, 10, 4);
176        validateProtoHistBucket("Bucket[1]", phb[1], 10, 30, 2);
177        validateProtoHistBucket("Bucket[2]", phb[2], 30, 60, 3);
178        validateProtoHistBucket("Bucket[3]", phb[3], 60, 100, 4);
179        validateProtoHistBucket("Bucket[4]", phb[4], 100, Integer.MAX_VALUE, 3);
180    }
181
182    // utilities
183
184    private void bucketValueAndVerify(String prefix, long value, SparseIntArray h,
185            MetricsUtils.LogHistParms hp, int expectedKey, int expectedValue) {
186        MetricsUtils.addValueToLogHistogram(value, h, hp);
187        collector.checkThat(prefix + value, h.get(expectedKey), equalTo(expectedValue));
188    }
189
190    private void bucketValueAndVerify(String prefix, int value, SparseIntArray h, int[] hp,
191            int expectedKey, int expectedValue) {
192        MetricsUtils.addValueToLinearHistogram(value, h, hp);
193        collector.checkThat(prefix + value, h.get(expectedKey), equalTo(expectedValue));
194    }
195
196    private void validateProtoHistBucket(String prefix, MetricsUtils.GenericBucket bucket,
197            long start, long end, int count) {
198        collector.checkThat(prefix + ": start", bucket.start, equalTo(start));
199        collector.checkThat(prefix + ": end", bucket.end, equalTo(end));
200        collector.checkThat(prefix + ": count", bucket.count, equalTo(count));
201    }
202}
203