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