NetworkStatsHistoryTest.java revision 7ee8658453fe4efe04781bea9a14368e1d5ff41f
175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey/*
275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Copyright (C) 2011 The Android Open Source Project
375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey *
475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * you may not use this file except in compliance with the License.
675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * You may obtain a copy of the License at
775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey *
875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey *
1075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
1175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
1275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * See the License for the specific language governing permissions and
1475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * limitations under the License.
1575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */
1675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
1775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeypackage android.net;
1875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
1963d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.FIELD_ALL;
2063d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.FIELD_OPERATIONS;
2163d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
2263d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.FIELD_RX_PACKETS;
2363d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
2463d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
2563d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
2663d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.Entry.UNKNOWN;
2775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.DAY_IN_MILLIS;
2875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.HOUR_IN_MILLIS;
2975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.MINUTE_IN_MILLIS;
3075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.SECOND_IN_MILLIS;
3175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.WEEK_IN_MILLIS;
3275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.YEAR_IN_MILLIS;
3375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
34a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport android.test.AndroidTestCase;
3575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.test.suitebuilder.annotation.SmallTest;
3675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.test.suitebuilder.annotation.Suppress;
3775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.util.Log;
3875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
39a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport com.android.frameworks.coretests.R;
4075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
4163d27a9233fed934340231f438493746084a681dJeff Sharkeyimport java.io.ByteArrayInputStream;
4263d27a9233fed934340231f438493746084a681dJeff Sharkeyimport java.io.ByteArrayOutputStream;
43a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport java.io.DataInputStream;
4463d27a9233fed934340231f438493746084a681dJeff Sharkeyimport java.io.DataOutputStream;
4575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.util.Random;
4675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
4775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey@SmallTest
48a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeypublic class NetworkStatsHistoryTest extends AndroidTestCase {
4975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private static final String TAG = "NetworkStatsHistoryTest";
5075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
5175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private static final long TEST_START = 1194220800000L;
5275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
5363d27a9233fed934340231f438493746084a681dJeff Sharkey    private static final long KB_IN_BYTES = 1024;
5463d27a9233fed934340231f438493746084a681dJeff Sharkey    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
5563d27a9233fed934340231f438493746084a681dJeff Sharkey    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
5663d27a9233fed934340231f438493746084a681dJeff Sharkey
5775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private NetworkStatsHistory stats;
5875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
5975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    @Override
6075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    protected void tearDown() throws Exception {
6175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        super.tearDown();
6275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (stats != null) {
6375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            assertConsistent(stats);
6475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
6575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
6675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
67a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void testReadOriginalVersion() throws Exception {
68a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        final DataInputStream in = new DataInputStream(
69a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                getContext().getResources().openRawResource(R.raw.history_v1));
70a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
71a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        NetworkStatsHistory.Entry entry = null;
72a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        try {
73a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final NetworkStatsHistory history = new NetworkStatsHistory(in);
74a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            assertEquals(15 * SECOND_IN_MILLIS, history.getBucketDuration());
75a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
76a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            entry = history.getValues(0, entry);
77a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            assertEquals(29143L, entry.rxBytes);
78a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            assertEquals(6223L, entry.txBytes);
79a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
80a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            entry = history.getValues(history.size() - 1, entry);
81a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            assertEquals(1476L, entry.rxBytes);
82a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            assertEquals(838L, entry.txBytes);
83a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
84a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            entry = history.getValues(Long.MIN_VALUE, Long.MAX_VALUE, entry);
85a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            assertEquals(332401L, entry.rxBytes);
86a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            assertEquals(64314L, entry.txBytes);
87a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
88a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        } finally {
89a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            in.close();
90a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        }
91a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
92a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
9375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRecordSingleBucket() throws Exception {
9475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long BUCKET_SIZE = HOUR_IN_MILLIS;
95d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
9675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
9775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // record data into narrow window to get single bucket
9863d27a9233fed934340231f438493746084a681dJeff Sharkey        stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
9963d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
10075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
101d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(1, stats.size());
102558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L);
10375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
10475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
10575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRecordEqualBuckets() throws Exception {
10675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long bucketDuration = HOUR_IN_MILLIS;
107d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey        stats = new NetworkStatsHistory(bucketDuration);
10875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
10975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // split equally across two buckets
11075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long recordStart = TEST_START + (bucketDuration / 2);
11163d27a9233fed934340231f438493746084a681dJeff Sharkey        stats.recordData(recordStart, recordStart + bucketDuration,
11263d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(1024L, 10L, 128L, 2L, 2L));
11375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
114d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(2, stats.size());
115558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 0, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
116558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 1, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
11775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
11875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
11975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRecordTouchingBuckets() throws Exception {
12075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
121d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
12275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
12375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // split almost completely into middle bucket, but with a few minutes
12475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // overlap into neighboring buckets. total record is 20 minutes.
12575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
12675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
12763d27a9233fed934340231f438493746084a681dJeff Sharkey        stats.recordData(recordStart, recordEnd,
12863d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(1000L, 2000L, 5000L, 10000L, 100L));
12975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
130d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(3, stats.size());
13175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // first bucket should have (1/20 of value)
132558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 0, MINUTE_IN_MILLIS, 50L, 100L, 250L, 500L, 5L);
13375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // second bucket should have (15/20 of value)
134558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 1, 15 * MINUTE_IN_MILLIS, 750L, 1500L, 3750L, 7500L, 75L);
13575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // final bucket should have (4/20 of value)
136558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 2, 4 * MINUTE_IN_MILLIS, 200L, 400L, 1000L, 2000L, 20L);
13775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
13875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
13975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRecordGapBuckets() throws Exception {
14075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long BUCKET_SIZE = HOUR_IN_MILLIS;
141d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
14275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
14375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // record some data today and next week with large gap
14475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long firstStart = TEST_START;
14575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long lastStart = TEST_START + WEEK_IN_MILLIS;
14663d27a9233fed934340231f438493746084a681dJeff Sharkey        stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS,
14763d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(128L, 2L, 256L, 4L, 1L));
14863d27a9233fed934340231f438493746084a681dJeff Sharkey        stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS,
14963d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(64L, 1L, 512L, 8L, 2L));
15075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
15175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // we should have two buckets, far apart from each other
152d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(2, stats.size());
153558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
154558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 1, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
15575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
15675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // now record something in middle, spread across two buckets
15775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long middleStart = TEST_START + DAY_IN_MILLIS;
15875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
15963d27a9233fed934340231f438493746084a681dJeff Sharkey        stats.recordData(middleStart, middleEnd,
16063d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(2048L, 4L, 2048L, 4L, 2L));
16175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
16275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // now should have four buckets, with new record in middle two buckets
163d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(4, stats.size());
164558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
165558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 1, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
166558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 2, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
167558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 3, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
16875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
16975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
17075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRecordOverlapBuckets() throws Exception {
17175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long BUCKET_SIZE = HOUR_IN_MILLIS;
172d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
17375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
17475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // record some data in one bucket, and another overlapping buckets
17563d27a9233fed934340231f438493746084a681dJeff Sharkey        stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
17663d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(256L, 2L, 256L, 2L, 1L));
17775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
17863d27a9233fed934340231f438493746084a681dJeff Sharkey        stats.recordData(midStart, midStart + HOUR_IN_MILLIS,
17963d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(1024L, 10L, 1024L, 10L, 10L));
18075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
18175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // should have two buckets, with some data mixed together
182d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(2, stats.size());
183558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 0, SECOND_IN_MILLIS + (HOUR_IN_MILLIS / 2), 768L, 7L, 768L, 7L, 6L);
184558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, 1, (HOUR_IN_MILLIS / 2), 512L, 5L, 512L, 5L, 5L);
18575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
18675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
18719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    public void testRecordEntireGapIdentical() throws Exception {
18819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // first, create two separate histories far apart
18919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
19019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L);
19119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
19219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final long TEST_START_2 = TEST_START + DAY_IN_MILLIS;
19319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS);
19419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L);
19519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
19619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // combine together with identical bucket size
19719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
19819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats1);
19919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats2);
20019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
20119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // first verify that totals match up
202434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L);
20319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
20419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // now inspect internal buckets
205434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 0, 1000L, 500L);
206434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 1, 1000L, 500L);
207434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 2, 500L, 250L);
208434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 3, 500L, 250L);
20919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
21019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
21119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    public void testRecordEntireOverlapVaryingBuckets() throws Exception {
21219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // create history just over hour bucket boundary
21319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
21419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L);
21519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
21619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS;
21719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS);
21819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L);
21919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
22019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // combine together with minute bucket size
22119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats = new NetworkStatsHistory(MINUTE_IN_MILLIS);
22219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats1);
22319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats2);
22419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
22519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // first verify that totals match up
226434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
22719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
22819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // now inspect internal buckets
229434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 0, 10L, 10L);
230434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 1, 20L, 20L);
231434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 2, 20L, 20L);
232434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 3, 20L, 20L);
233434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 4, 20L, 20L);
234434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 5, 20L, 20L);
235434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 6, 10L, 10L);
23619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
23719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // now combine using 15min buckets
23819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4);
23919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats1);
24019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats2);
24119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
24219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // first verify that totals match up
243434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
24419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
24519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // and inspect buckets
246434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 0, 200L, 200L);
247434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 1, 150L, 150L);
248434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 2, 150L, 150L);
249434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, 3, 150L, 150L);
25019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
25119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
25275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRemove() throws Exception {
25319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
25475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
25575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // record some data across 24 buckets
25675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
257d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(24, stats.size());
25875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
2597ee8658453fe4efe04781bea9a14368e1d5ff41fJeff Sharkey        // try removing invalid data; should be no change
2607ee8658453fe4efe04781bea9a14368e1d5ff41fJeff Sharkey        stats.removeBucketsBefore(0 - DAY_IN_MILLIS);
2617ee8658453fe4efe04781bea9a14368e1d5ff41fJeff Sharkey        assertEquals(24, stats.size());
2627ee8658453fe4efe04781bea9a14368e1d5ff41fJeff Sharkey
26375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // try removing far before buckets; should be no change
26475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS);
265d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(24, stats.size());
26675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
26775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // try removing just moments into first bucket; should be no change
26875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // since that bucket contains data beyond the cutoff
26975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.removeBucketsBefore(TEST_START + SECOND_IN_MILLIS);
270d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(24, stats.size());
27175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
27275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // try removing single bucket
27375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.removeBucketsBefore(TEST_START + HOUR_IN_MILLIS);
274d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(23, stats.size());
27575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
27675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // try removing multiple buckets
27775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.removeBucketsBefore(TEST_START + (4 * HOUR_IN_MILLIS));
278d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(20, stats.size());
27975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
28075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // try removing all buckets
28175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.removeBucketsBefore(TEST_START + YEAR_IN_MILLIS);
282d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(0, stats.size());
28375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
28475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
28519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    public void testTotalData() throws Exception {
28619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final long BUCKET_SIZE = HOUR_IN_MILLIS;
28719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
28819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
28919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // record uniform data across day
29019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L);
29119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
29219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // verify that total outside range is 0
293434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L);
29419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
29519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // verify total in first hour
296434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L);
29719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
29819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // verify total across 1.5 hours
299434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L);
30019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
30119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // verify total beyond end
302434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L);
30319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
30419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // verify everything total
305434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L);
30619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
30719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
30819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
30975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    @Suppress
31075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testFuzzing() throws Exception {
31175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        try {
31275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // fuzzing with random events, looking for crashes
31363d27a9233fed934340231f438493746084a681dJeff Sharkey            final NetworkStats.Entry entry = new NetworkStats.Entry();
31475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final Random r = new Random();
31575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            for (int i = 0; i < 500; i++) {
316d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey                stats = new NetworkStatsHistory(r.nextLong());
31775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                for (int j = 0; j < 10000; j++) {
31875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                    if (r.nextBoolean()) {
31975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        // add range
32075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        final long start = r.nextLong();
32175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        final long end = start + r.nextInt();
32263d27a9233fed934340231f438493746084a681dJeff Sharkey                        entry.rxBytes = nextPositiveLong(r);
32363d27a9233fed934340231f438493746084a681dJeff Sharkey                        entry.rxPackets = nextPositiveLong(r);
32463d27a9233fed934340231f438493746084a681dJeff Sharkey                        entry.txBytes = nextPositiveLong(r);
32563d27a9233fed934340231f438493746084a681dJeff Sharkey                        entry.txPackets = nextPositiveLong(r);
32663d27a9233fed934340231f438493746084a681dJeff Sharkey                        entry.operations = nextPositiveLong(r);
32763d27a9233fed934340231f438493746084a681dJeff Sharkey                        stats.recordData(start, end, entry);
32875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                    } else {
32975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        // trim something
33075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        stats.removeBucketsBefore(r.nextLong());
33175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                    }
33275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                }
33375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                assertConsistent(stats);
33475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            }
33575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        } catch (Throwable e) {
33675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            Log.e(TAG, String.valueOf(stats));
33775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            throw new RuntimeException(e);
33875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
33975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
34075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
34163d27a9233fed934340231f438493746084a681dJeff Sharkey    private static long nextPositiveLong(Random r) {
34263d27a9233fed934340231f438493746084a681dJeff Sharkey        final long value = r.nextLong();
34363d27a9233fed934340231f438493746084a681dJeff Sharkey        return value < 0 ? -value : value;
34463d27a9233fed934340231f438493746084a681dJeff Sharkey    }
34563d27a9233fed934340231f438493746084a681dJeff Sharkey
34663d27a9233fed934340231f438493746084a681dJeff Sharkey    public void testIgnoreFields() throws Exception {
34763d27a9233fed934340231f438493746084a681dJeff Sharkey        final NetworkStatsHistory history = new NetworkStatsHistory(
34863d27a9233fed934340231f438493746084a681dJeff Sharkey                MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
34963d27a9233fed934340231f438493746084a681dJeff Sharkey
35063d27a9233fed934340231f438493746084a681dJeff Sharkey        history.recordData(0, MINUTE_IN_MILLIS,
35163d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
352558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        history.recordData(0, 2 * MINUTE_IN_MILLIS,
35363d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(2L, 2L, 2L, 2L, 2L));
35463d27a9233fed934340231f438493746084a681dJeff Sharkey
355558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
35663d27a9233fed934340231f438493746084a681dJeff Sharkey    }
35763d27a9233fed934340231f438493746084a681dJeff Sharkey
35863d27a9233fed934340231f438493746084a681dJeff Sharkey    public void testIgnoreFieldsRecordIn() throws Exception {
35963d27a9233fed934340231f438493746084a681dJeff Sharkey        final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
36063d27a9233fed934340231f438493746084a681dJeff Sharkey        final NetworkStatsHistory partial = new NetworkStatsHistory(
36163d27a9233fed934340231f438493746084a681dJeff Sharkey                MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
36263d27a9233fed934340231f438493746084a681dJeff Sharkey
36363d27a9233fed934340231f438493746084a681dJeff Sharkey        full.recordData(0, MINUTE_IN_MILLIS,
36463d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
36563d27a9233fed934340231f438493746084a681dJeff Sharkey        partial.recordEntireHistory(full);
36663d27a9233fed934340231f438493746084a681dJeff Sharkey
367558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
36863d27a9233fed934340231f438493746084a681dJeff Sharkey    }
36963d27a9233fed934340231f438493746084a681dJeff Sharkey
37063d27a9233fed934340231f438493746084a681dJeff Sharkey    public void testIgnoreFieldsRecordOut() throws Exception {
37163d27a9233fed934340231f438493746084a681dJeff Sharkey        final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
37263d27a9233fed934340231f438493746084a681dJeff Sharkey        final NetworkStatsHistory partial = new NetworkStatsHistory(
37363d27a9233fed934340231f438493746084a681dJeff Sharkey                MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
37463d27a9233fed934340231f438493746084a681dJeff Sharkey
37563d27a9233fed934340231f438493746084a681dJeff Sharkey        partial.recordData(0, MINUTE_IN_MILLIS,
37663d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
37763d27a9233fed934340231f438493746084a681dJeff Sharkey        full.recordEntireHistory(partial);
37863d27a9233fed934340231f438493746084a681dJeff Sharkey
379558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L);
38063d27a9233fed934340231f438493746084a681dJeff Sharkey    }
38163d27a9233fed934340231f438493746084a681dJeff Sharkey
38263d27a9233fed934340231f438493746084a681dJeff Sharkey    public void testSerialize() throws Exception {
38363d27a9233fed934340231f438493746084a681dJeff Sharkey        final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
384558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        before.recordData(0, 4 * MINUTE_IN_MILLIS,
38563d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
38663d27a9233fed934340231f438493746084a681dJeff Sharkey        before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS,
38763d27a9233fed934340231f438493746084a681dJeff Sharkey                new NetworkStats.Entry(10L, 20L, 30L, 40L, 50L));
38863d27a9233fed934340231f438493746084a681dJeff Sharkey
38963d27a9233fed934340231f438493746084a681dJeff Sharkey        final ByteArrayOutputStream out = new ByteArrayOutputStream();
39063d27a9233fed934340231f438493746084a681dJeff Sharkey        before.writeToStream(new DataOutputStream(out));
39163d27a9233fed934340231f438493746084a681dJeff Sharkey        out.close();
39263d27a9233fed934340231f438493746084a681dJeff Sharkey
39363d27a9233fed934340231f438493746084a681dJeff Sharkey        final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
39463d27a9233fed934340231f438493746084a681dJeff Sharkey        final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in));
39563d27a9233fed934340231f438493746084a681dJeff Sharkey
39663d27a9233fed934340231f438493746084a681dJeff Sharkey        // must have identical totals before and after
397558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertFullValues(before, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
398558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertFullValues(after, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
39963d27a9233fed934340231f438493746084a681dJeff Sharkey    }
40063d27a9233fed934340231f438493746084a681dJeff Sharkey
40163d27a9233fed934340231f438493746084a681dJeff Sharkey    public void testVarLong() throws Exception {
40263d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals(0L, performVarLong(0L));
40363d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals(-1L, performVarLong(-1L));
40463d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals(1024L, performVarLong(1024L));
40563d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals(-1024L, performVarLong(-1024L));
40663d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES));
40763d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES));
40863d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE));
40963d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE));
41063d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40));
41163d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
41263d27a9233fed934340231f438493746084a681dJeff Sharkey    }
41363d27a9233fed934340231f438493746084a681dJeff Sharkey
41469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    public void testIndexBeforeAfter() throws Exception {
41569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final long BUCKET_SIZE = HOUR_IN_MILLIS;
41669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
41769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
41869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final long FIRST_START = TEST_START;
41969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
42069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
42169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
42269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
42369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
42469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
42569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        stats.recordData(FIRST_START, FIRST_END,
42669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
42769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        stats.recordData(SECOND_START, SECOND_END,
42869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
42969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        stats.recordData(THIRD_START, THIRD_END,
43069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
43169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
43269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        // should have buckets: 2+1+2
43369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertEquals(5, stats.size());
43469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
43569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE);
43669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 0, 1, FIRST_START);
43769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS);
43869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS);
43969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
44069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS);
44169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 1, 2, FIRST_END);
44269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS);
44369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS);
44469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 1, 3, SECOND_START);
44569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 2, 3, SECOND_END);
44669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS);
44769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS);
44869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 2, 4, THIRD_START);
44969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS);
45069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS);
45169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 4, 4, THIRD_END);
45269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS);
45369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
45469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    }
45569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
45669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    private static void assertIndexBeforeAfter(
45769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            NetworkStatsHistory stats, int before, int after, long time) {
45869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertEquals("unexpected before", before, stats.getIndexBefore(time));
45969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        assertEquals("unexpected after", after, stats.getIndexAfter(time));
46069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    }
46169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
46263d27a9233fed934340231f438493746084a681dJeff Sharkey    private static long performVarLong(long before) throws Exception {
46363d27a9233fed934340231f438493746084a681dJeff Sharkey        final ByteArrayOutputStream out = new ByteArrayOutputStream();
46463d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLong(new DataOutputStream(out), before);
46563d27a9233fed934340231f438493746084a681dJeff Sharkey
46663d27a9233fed934340231f438493746084a681dJeff Sharkey        final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
46763d27a9233fed934340231f438493746084a681dJeff Sharkey        return readVarLong(new DataInputStream(in));
46863d27a9233fed934340231f438493746084a681dJeff Sharkey    }
46963d27a9233fed934340231f438493746084a681dJeff Sharkey
47075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private static void assertConsistent(NetworkStatsHistory stats) {
47175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // verify timestamps are monotonic
472d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        long lastStart = Long.MIN_VALUE;
473d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        NetworkStatsHistory.Entry entry = null;
474d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        for (int i = 0; i < stats.size(); i++) {
475d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            entry = stats.getValues(i, entry);
476d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            assertTrue(lastStart < entry.bucketStart);
477d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            lastStart = entry.bucketStart;
47875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
47975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
48075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
481434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    private static void assertValues(
482d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            NetworkStatsHistory stats, int index, long rxBytes, long txBytes) {
483d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
484d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
485d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
48675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
48775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
488434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    private static void assertValues(
489434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) {
490434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
491434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
492434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
493434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
494434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
495558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private static void assertValues(NetworkStatsHistory stats, int index, long activeTime,
496558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
49763d27a9233fed934340231f438493746084a681dJeff Sharkey        final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
498558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertEquals("unexpected activeTime", activeTime, entry.activeTime);
49963d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
50063d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
50163d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
50263d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals("unexpected txPackets", txPackets, entry.txPackets);
50363d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals("unexpected operations", operations, entry.operations);
50463d27a9233fed934340231f438493746084a681dJeff Sharkey    }
50563d27a9233fed934340231f438493746084a681dJeff Sharkey
506558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private static void assertFullValues(NetworkStatsHistory stats, long activeTime, long rxBytes,
50763d27a9233fed934340231f438493746084a681dJeff Sharkey            long rxPackets, long txBytes, long txPackets, long operations) {
508558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertValues(stats, Long.MIN_VALUE, Long.MAX_VALUE, activeTime, rxBytes, rxPackets, txBytes,
509558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey                txPackets, operations);
510558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    }
511558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey
512558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private static void assertValues(NetworkStatsHistory stats, long start, long end,
513558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            long activeTime, long rxBytes, long rxPackets, long txBytes, long txPackets,
514558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            long operations) {
51563d27a9233fed934340231f438493746084a681dJeff Sharkey        final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
516558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        assertEquals("unexpected activeTime", activeTime, entry.activeTime);
51763d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
51863d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
51963d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
52063d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals("unexpected txPackets", txPackets, entry.txPackets);
52163d27a9233fed934340231f438493746084a681dJeff Sharkey        assertEquals("unexpected operations", operations, entry.operations);
52263d27a9233fed934340231f438493746084a681dJeff Sharkey    }
52375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey}
524