• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 
17 package android.net;
18 
19 import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
20 import static android.net.NetworkStats.IFACE_ALL;
21 import static android.net.NetworkStats.METERED_NO;
22 import static android.net.NetworkStats.ROAMING_NO;
23 import static android.net.NetworkStats.SET_DEFAULT;
24 import static android.net.NetworkStats.TAG_NONE;
25 import static android.net.NetworkStats.UID_ALL;
26 import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
27 import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
28 import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
29 import static android.net.NetworkStatsHistory.FIELD_ALL;
30 import static android.net.NetworkStatsHistory.FIELD_OPERATIONS;
31 import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
32 import static android.net.NetworkStatsHistory.FIELD_RX_PACKETS;
33 import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
34 import static android.net.TrafficStats.GB_IN_BYTES;
35 import static android.net.TrafficStats.MB_IN_BYTES;
36 import static android.text.format.DateUtils.DAY_IN_MILLIS;
37 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
38 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
39 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
40 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
41 import static android.text.format.DateUtils.YEAR_IN_MILLIS;
42 
43 import static org.junit.Assert.assertEquals;
44 import static org.junit.Assert.assertFalse;
45 import static org.junit.Assert.assertTrue;
46 
47 import android.content.Context;
48 import android.os.Build;
49 import android.util.Log;
50 
51 import androidx.test.InstrumentationRegistry;
52 import androidx.test.filters.SmallTest;
53 
54 import com.android.frameworks.tests.net.R;
55 import com.android.testutils.DevSdkIgnoreRule;
56 import com.android.testutils.DevSdkIgnoreRunner;
57 
58 import org.junit.After;
59 import org.junit.Test;
60 import org.junit.runner.RunWith;
61 
62 import java.io.ByteArrayInputStream;
63 import java.io.ByteArrayOutputStream;
64 import java.io.DataInputStream;
65 import java.io.DataOutputStream;
66 import java.util.Random;
67 
68 @RunWith(DevSdkIgnoreRunner.class)
69 @SmallTest
70 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
71 public class NetworkStatsHistoryTest {
72     private static final String TAG = "NetworkStatsHistoryTest";
73 
74     private static final long TEST_START = 1194220800000L;
75 
76     private NetworkStatsHistory stats;
77 
78     @After
tearDown()79     public void tearDown() throws Exception {
80         if (stats != null) {
81             assertConsistent(stats);
82         }
83     }
84 
85     @Test
testReadOriginalVersion()86     public void testReadOriginalVersion() throws Exception {
87         final Context context = InstrumentationRegistry.getContext();
88         final DataInputStream in =
89                 new DataInputStream(context.getResources().openRawResource(R.raw.history_v1));
90 
91         NetworkStatsHistory.Entry entry = null;
92         try {
93             final NetworkStatsHistory history = new NetworkStatsHistory(in);
94             assertEquals(15 * SECOND_IN_MILLIS, history.getBucketDuration());
95 
96             entry = history.getValues(0, entry);
97             assertEquals(29143L, entry.rxBytes);
98             assertEquals(6223L, entry.txBytes);
99 
100             entry = history.getValues(history.size() - 1, entry);
101             assertEquals(1476L, entry.rxBytes);
102             assertEquals(838L, entry.txBytes);
103 
104             entry = history.getValues(Long.MIN_VALUE, Long.MAX_VALUE, entry);
105             assertEquals(332401L, entry.rxBytes);
106             assertEquals(64314L, entry.txBytes);
107 
108         } finally {
109             in.close();
110         }
111     }
112 
113     @Test
testRecordSingleBucket()114     public void testRecordSingleBucket() throws Exception {
115         final long BUCKET_SIZE = HOUR_IN_MILLIS;
116         stats = new NetworkStatsHistory(BUCKET_SIZE);
117 
118         // record data into narrow window to get single bucket
119         stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
120                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
121                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
122 
123         assertEquals(1, stats.size());
124         assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L);
125     }
126 
127     @Test
testRecordEqualBuckets()128     public void testRecordEqualBuckets() throws Exception {
129         final long bucketDuration = HOUR_IN_MILLIS;
130         stats = new NetworkStatsHistory(bucketDuration);
131 
132         // split equally across two buckets
133         final long recordStart = TEST_START + (bucketDuration / 2);
134         stats.recordData(recordStart, recordStart + bucketDuration,
135                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
136                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 128L, 2L, 2L));
137 
138         assertEquals(2, stats.size());
139         assertValues(stats, 0, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
140         assertValues(stats, 1, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
141     }
142 
143     @Test
testRecordTouchingBuckets()144     public void testRecordTouchingBuckets() throws Exception {
145         final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
146         stats = new NetworkStatsHistory(BUCKET_SIZE);
147 
148         // split almost completely into middle bucket, but with a few minutes
149         // overlap into neighboring buckets. total record is 20 minutes.
150         final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
151         final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
152         stats.recordData(recordStart, recordEnd,
153                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
154                 ROAMING_NO, DEFAULT_NETWORK_NO, 1000L, 2000L, 5000L, 10000L, 100L));
155 
156         assertEquals(3, stats.size());
157         // first bucket should have (1/20 of value)
158         assertValues(stats, 0, MINUTE_IN_MILLIS, 50L, 100L, 250L, 500L, 5L);
159         // second bucket should have (15/20 of value)
160         assertValues(stats, 1, 15 * MINUTE_IN_MILLIS, 750L, 1500L, 3750L, 7500L, 75L);
161         // final bucket should have (4/20 of value)
162         assertValues(stats, 2, 4 * MINUTE_IN_MILLIS, 200L, 400L, 1000L, 2000L, 20L);
163     }
164 
165     @Test
testRecordGapBuckets()166     public void testRecordGapBuckets() throws Exception {
167         final long BUCKET_SIZE = HOUR_IN_MILLIS;
168         stats = new NetworkStatsHistory(BUCKET_SIZE);
169 
170         // record some data today and next week with large gap
171         final long firstStart = TEST_START;
172         final long lastStart = TEST_START + WEEK_IN_MILLIS;
173         stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS,
174                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
175                 ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 2L, 256L, 4L, 1L));
176         stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS,
177                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
178                 ROAMING_NO, DEFAULT_NETWORK_NO, 64L, 1L, 512L, 8L, 2L));
179 
180         // we should have two buckets, far apart from each other
181         assertEquals(2, stats.size());
182         assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
183         assertValues(stats, 1, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
184 
185         // now record something in middle, spread across two buckets
186         final long middleStart = TEST_START + DAY_IN_MILLIS;
187         final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
188         stats.recordData(middleStart, middleEnd,
189                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
190                 ROAMING_NO, DEFAULT_NETWORK_NO, 2048L, 4L, 2048L, 4L, 2L));
191 
192         // now should have four buckets, with new record in middle two buckets
193         assertEquals(4, stats.size());
194         assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
195         assertValues(stats, 1, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
196         assertValues(stats, 2, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
197         assertValues(stats, 3, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
198     }
199 
200     @Test
testRecordOverlapBuckets()201     public void testRecordOverlapBuckets() throws Exception {
202         final long BUCKET_SIZE = HOUR_IN_MILLIS;
203         stats = new NetworkStatsHistory(BUCKET_SIZE);
204 
205         // record some data in one bucket, and another overlapping buckets
206         stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
207                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
208                 ROAMING_NO, DEFAULT_NETWORK_NO, 256L, 2L, 256L, 2L, 1L));
209         final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
210         stats.recordData(midStart, midStart + HOUR_IN_MILLIS,
211                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
212                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 1024L, 10L, 10L));
213 
214         // should have two buckets, with some data mixed together
215         assertEquals(2, stats.size());
216         assertValues(stats, 0, SECOND_IN_MILLIS + (HOUR_IN_MILLIS / 2), 768L, 7L, 768L, 7L, 6L);
217         assertValues(stats, 1, (HOUR_IN_MILLIS / 2), 512L, 5L, 512L, 5L, 5L);
218     }
219 
220     @Test
testRecordEntireGapIdentical()221     public void testRecordEntireGapIdentical() throws Exception {
222         // first, create two separate histories far apart
223         final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
224         stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L);
225 
226         final long TEST_START_2 = TEST_START + DAY_IN_MILLIS;
227         final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS);
228         stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L);
229 
230         // combine together with identical bucket size
231         stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
232         stats.recordEntireHistory(stats1);
233         stats.recordEntireHistory(stats2);
234 
235         // first verify that totals match up
236         assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L);
237 
238         // now inspect internal buckets
239         assertValues(stats, 0, 1000L, 500L);
240         assertValues(stats, 1, 1000L, 500L);
241         assertValues(stats, 2, 500L, 250L);
242         assertValues(stats, 3, 500L, 250L);
243     }
244 
245     @Test
testRecordEntireOverlapVaryingBuckets()246     public void testRecordEntireOverlapVaryingBuckets() throws Exception {
247         // create history just over hour bucket boundary
248         final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
249         stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L);
250 
251         final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS;
252         final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS);
253         stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L);
254 
255         // combine together with minute bucket size
256         stats = new NetworkStatsHistory(MINUTE_IN_MILLIS);
257         stats.recordEntireHistory(stats1);
258         stats.recordEntireHistory(stats2);
259 
260         // first verify that totals match up
261         assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
262 
263         // now inspect internal buckets
264         assertValues(stats, 0, 10L, 10L);
265         assertValues(stats, 1, 20L, 20L);
266         assertValues(stats, 2, 20L, 20L);
267         assertValues(stats, 3, 20L, 20L);
268         assertValues(stats, 4, 20L, 20L);
269         assertValues(stats, 5, 20L, 20L);
270         assertValues(stats, 6, 10L, 10L);
271 
272         // now combine using 15min buckets
273         stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4);
274         stats.recordEntireHistory(stats1);
275         stats.recordEntireHistory(stats2);
276 
277         // first verify that totals match up
278         assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
279 
280         // and inspect buckets
281         assertValues(stats, 0, 200L, 200L);
282         assertValues(stats, 1, 150L, 150L);
283         assertValues(stats, 2, 150L, 150L);
284         assertValues(stats, 3, 150L, 150L);
285     }
286 
287     @Test
testRemoveStartingBefore()288     public void testRemoveStartingBefore() throws Exception {
289         stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
290 
291         // record some data across 24 buckets
292         stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
293         assertEquals(24, stats.size());
294 
295         // try removing invalid data; should be no change
296         stats.removeBucketsStartingBefore(0 - DAY_IN_MILLIS);
297         assertEquals(24, stats.size());
298 
299         // try removing far before buckets; should be no change
300         stats.removeBucketsStartingBefore(TEST_START - YEAR_IN_MILLIS);
301         assertEquals(24, stats.size());
302 
303         // try removing just moments into first bucket; should be no change
304         // since that bucket doesn't contain data starts before the cutoff
305         stats.removeBucketsStartingBefore(TEST_START);
306         assertEquals(24, stats.size());
307 
308         // try removing single bucket
309         stats.removeBucketsStartingBefore(TEST_START + HOUR_IN_MILLIS);
310         assertEquals(23, stats.size());
311 
312         // try removing multiple buckets
313         stats.removeBucketsStartingBefore(TEST_START + (4 * HOUR_IN_MILLIS));
314         assertEquals(20, stats.size());
315 
316         // try removing all buckets
317         stats.removeBucketsStartingBefore(TEST_START + YEAR_IN_MILLIS);
318         assertEquals(0, stats.size());
319     }
320 
321     @Test
testTotalData()322     public void testTotalData() throws Exception {
323         final long BUCKET_SIZE = HOUR_IN_MILLIS;
324         stats = new NetworkStatsHistory(BUCKET_SIZE);
325 
326         // record uniform data across day
327         stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L);
328 
329         // verify that total outside range is 0
330         assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L);
331 
332         // verify total in first hour
333         assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L);
334 
335         // verify total across 1.5 hours
336         assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L);
337 
338         // verify total beyond end
339         assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L);
340 
341         // verify everything total
342         assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L);
343 
344     }
345 
346     @Test
testFuzzing()347     public void testFuzzing() throws Exception {
348         try {
349             // fuzzing with random events, looking for crashes
350             final NetworkStats.Entry entry = new NetworkStats.Entry();
351             final Random r = new Random();
352             for (int i = 0; i < 500; i++) {
353                 stats = new NetworkStatsHistory(r.nextLong());
354                 for (int j = 0; j < 10000; j++) {
355                     if (r.nextBoolean()) {
356                         // add range
357                         final long start = r.nextLong();
358                         final long end = start + r.nextInt();
359                         entry.rxBytes = nextPositiveLong(r);
360                         entry.rxPackets = nextPositiveLong(r);
361                         entry.txBytes = nextPositiveLong(r);
362                         entry.txPackets = nextPositiveLong(r);
363                         entry.operations = nextPositiveLong(r);
364                         stats.recordData(start, end, entry);
365                     } else {
366                         // trim something
367                         stats.removeBucketsStartingBefore(r.nextLong());
368                     }
369                 }
370                 assertConsistent(stats);
371             }
372         } catch (Throwable e) {
373             Log.e(TAG, String.valueOf(stats));
374             throw new RuntimeException(e);
375         }
376     }
377 
nextPositiveLong(Random r)378     private static long nextPositiveLong(Random r) {
379         final long value = r.nextLong();
380         return value < 0 ? -value : value;
381     }
382 
383     @Test
testIgnoreFields()384     public void testIgnoreFields() throws Exception {
385         final NetworkStatsHistory history = new NetworkStatsHistory(
386                 MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
387 
388         history.recordData(0, MINUTE_IN_MILLIS,
389                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
390                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L));
391         history.recordData(0, 2 * MINUTE_IN_MILLIS,
392                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
393                 ROAMING_NO, DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 2L));
394 
395         assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
396     }
397 
398     @Test
testIgnoreFieldsRecordIn()399     public void testIgnoreFieldsRecordIn() throws Exception {
400         final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
401         final NetworkStatsHistory partial = new NetworkStatsHistory(
402                 MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
403 
404         full.recordData(0, MINUTE_IN_MILLIS,
405                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
406                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L));
407         partial.recordEntireHistory(full);
408 
409         assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
410     }
411 
412     @Test
testIgnoreFieldsRecordOut()413     public void testIgnoreFieldsRecordOut() throws Exception {
414         final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
415         final NetworkStatsHistory partial = new NetworkStatsHistory(
416                 MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
417 
418         partial.recordData(0, MINUTE_IN_MILLIS,
419                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
420                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L));
421         full.recordEntireHistory(partial);
422 
423         assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L);
424     }
425 
426     @Test
testSerialize()427     public void testSerialize() throws Exception {
428         final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
429         before.recordData(0, 4 * MINUTE_IN_MILLIS,
430                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
431                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L));
432         before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS,
433                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
434                 ROAMING_NO, DEFAULT_NETWORK_NO, 10L, 20L, 30L, 40L, 50L));
435 
436         final ByteArrayOutputStream out = new ByteArrayOutputStream();
437         before.writeToStream(new DataOutputStream(out));
438         out.close();
439 
440         final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
441         final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in));
442 
443         // must have identical totals before and after
444         assertFullValues(before, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
445         assertFullValues(after, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
446     }
447 
448     @Test
testVarLong()449     public void testVarLong() throws Exception {
450         assertEquals(0L, performVarLong(0L));
451         assertEquals(-1L, performVarLong(-1L));
452         assertEquals(1024L, performVarLong(1024L));
453         assertEquals(-1024L, performVarLong(-1024L));
454         assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES));
455         assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES));
456         assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE));
457         assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE));
458         assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40));
459         assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
460     }
461 
462     @Test
testIndexBeforeAfter()463     public void testIndexBeforeAfter() throws Exception {
464         final long BUCKET_SIZE = HOUR_IN_MILLIS;
465         stats = new NetworkStatsHistory(BUCKET_SIZE);
466 
467         final long FIRST_START = TEST_START;
468         final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
469         final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
470         final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
471         final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
472         final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
473 
474         stats.recordData(FIRST_START, FIRST_END,
475                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
476                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
477         stats.recordData(SECOND_START, SECOND_END,
478                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
479                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
480         stats.recordData(THIRD_START, THIRD_END,
481                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
482                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
483 
484         // should have buckets: 2+1+2
485         assertEquals(5, stats.size());
486 
487         assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE);
488         assertIndexBeforeAfter(stats, 0, 1, FIRST_START);
489         assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS);
490         assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS);
491         assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
492         assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS);
493         assertIndexBeforeAfter(stats, 1, 2, FIRST_END);
494         assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS);
495         assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS);
496         assertIndexBeforeAfter(stats, 1, 3, SECOND_START);
497         assertIndexBeforeAfter(stats, 2, 3, SECOND_END);
498         assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS);
499         assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS);
500         assertIndexBeforeAfter(stats, 2, 4, THIRD_START);
501         assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS);
502         assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS);
503         assertIndexBeforeAfter(stats, 4, 4, THIRD_END);
504         assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS);
505         assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
506     }
507 
508     @Test
testIntersects()509     public void testIntersects() throws Exception {
510         final long BUCKET_SIZE = HOUR_IN_MILLIS;
511         stats = new NetworkStatsHistory(BUCKET_SIZE);
512 
513         final long FIRST_START = TEST_START;
514         final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
515         final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
516         final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
517         final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
518         final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
519 
520         stats.recordData(FIRST_START, FIRST_END,
521                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
522                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
523         stats.recordData(SECOND_START, SECOND_END,
524                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
525                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
526         stats.recordData(THIRD_START, THIRD_END,
527                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
528                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
529 
530         assertFalse(stats.intersects(10, 20));
531         assertFalse(stats.intersects(TEST_START + YEAR_IN_MILLIS, TEST_START + YEAR_IN_MILLIS + 1));
532         assertFalse(stats.intersects(Long.MAX_VALUE, Long.MIN_VALUE));
533 
534         assertTrue(stats.intersects(Long.MIN_VALUE, Long.MAX_VALUE));
535         assertTrue(stats.intersects(10, TEST_START + YEAR_IN_MILLIS));
536         assertTrue(stats.intersects(TEST_START, TEST_START));
537         assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, TEST_START + DAY_IN_MILLIS + 1));
538         assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, Long.MAX_VALUE));
539         assertTrue(stats.intersects(TEST_START + 1, Long.MAX_VALUE));
540 
541         assertFalse(stats.intersects(Long.MIN_VALUE, TEST_START - 1));
542         assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START));
543         assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1));
544     }
545 
546     @Test
testSetValues()547     public void testSetValues() throws Exception {
548         stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
549         stats.recordData(TEST_START, TEST_START + 1,
550                 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
551                 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
552 
553         assertEquals(1024L + 2048L, stats.getTotalBytes());
554 
555         final NetworkStatsHistory.Entry entry = stats.getValues(0, null);
556         entry.rxBytes /= 2;
557         entry.txBytes *= 2;
558         stats.setValues(0, entry);
559 
560         assertEquals(512L + 4096L, stats.getTotalBytes());
561     }
562 
assertIndexBeforeAfter( NetworkStatsHistory stats, int before, int after, long time)563     private static void assertIndexBeforeAfter(
564             NetworkStatsHistory stats, int before, int after, long time) {
565         assertEquals("unexpected before", before, stats.getIndexBefore(time));
566         assertEquals("unexpected after", after, stats.getIndexAfter(time));
567     }
568 
performVarLong(long before)569     private static long performVarLong(long before) throws Exception {
570         final ByteArrayOutputStream out = new ByteArrayOutputStream();
571         writeVarLong(new DataOutputStream(out), before);
572 
573         final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
574         return readVarLong(new DataInputStream(in));
575     }
576 
assertConsistent(NetworkStatsHistory stats)577     private static void assertConsistent(NetworkStatsHistory stats) {
578         // verify timestamps are monotonic
579         long lastStart = Long.MIN_VALUE;
580         NetworkStatsHistory.Entry entry = null;
581         for (int i = 0; i < stats.size(); i++) {
582             entry = stats.getValues(i, entry);
583             assertTrue(lastStart < entry.bucketStart);
584             lastStart = entry.bucketStart;
585         }
586     }
587 
588     private static void assertValues(
589             NetworkStatsHistory stats, int index, long rxBytes, long txBytes) {
590         final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
591         assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
592         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
593     }
594 
595     private static void assertValues(
596             NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) {
597         final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
598         assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
599         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
600     }
601 
602     private static void assertValues(NetworkStatsHistory stats, int index, long activeTime,
603             long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
604         final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
605         assertEquals("unexpected activeTime", activeTime, entry.activeTime);
606         assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
607         assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
608         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
609         assertEquals("unexpected txPackets", txPackets, entry.txPackets);
610         assertEquals("unexpected operations", operations, entry.operations);
611     }
612 
613     private static void assertFullValues(NetworkStatsHistory stats, long activeTime, long rxBytes,
614             long rxPackets, long txBytes, long txPackets, long operations) {
615         assertValues(stats, Long.MIN_VALUE, Long.MAX_VALUE, activeTime, rxBytes, rxPackets, txBytes,
616                 txPackets, operations);
617     }
618 
619     private static void assertValues(NetworkStatsHistory stats, long start, long end,
620             long activeTime, long rxBytes, long rxPackets, long txBytes, long txPackets,
621             long operations) {
622         final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
623         assertEquals("unexpected activeTime", activeTime, entry.activeTime);
624         assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
625         assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
626         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
627         assertEquals("unexpected txPackets", txPackets, entry.txPackets);
628         assertEquals("unexpected operations", operations, entry.operations);
629     }
630 }
631