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