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