NetworkStatsHistoryTest.java revision d37948f6ed1667d077e0e3a38808f42f981ddcc2
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
1975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.DAY_IN_MILLIS;
2075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.HOUR_IN_MILLIS;
2175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.MINUTE_IN_MILLIS;
2275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.SECOND_IN_MILLIS;
2375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.WEEK_IN_MILLIS;
2475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport static android.text.format.DateUtils.YEAR_IN_MILLIS;
2575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
2675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.test.suitebuilder.annotation.SmallTest;
2775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.test.suitebuilder.annotation.Suppress;
2875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.util.Log;
2975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
3075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport junit.framework.TestCase;
3175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
3275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.util.Random;
3375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
3475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey@SmallTest
3575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeypublic class NetworkStatsHistoryTest extends TestCase {
3675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private static final String TAG = "NetworkStatsHistoryTest";
3775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
3875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private static final long TEST_START = 1194220800000L;
3975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
4075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private NetworkStatsHistory stats;
4175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
4275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    @Override
4375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    protected void tearDown() throws Exception {
4475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        super.tearDown();
4575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (stats != null) {
4675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            assertConsistent(stats);
4775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
4875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
4975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
5075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRecordSingleBucket() throws Exception {
5175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long BUCKET_SIZE = HOUR_IN_MILLIS;
52d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
5375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
5475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // record data into narrow window to get single bucket
5575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L);
5675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
57d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(1, stats.size());
58d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 0, 1024L, 2048L);
5975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
6075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
6175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRecordEqualBuckets() throws Exception {
6275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long bucketDuration = HOUR_IN_MILLIS;
63d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey        stats = new NetworkStatsHistory(bucketDuration);
6475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
6575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // split equally across two buckets
6675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long recordStart = TEST_START + (bucketDuration / 2);
6775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.recordData(recordStart, recordStart + bucketDuration, 1024L, 128L);
6875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
69d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(2, stats.size());
70d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 0, 512L, 64L);
71d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 1, 512L, 64L);
7275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
7375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
7475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRecordTouchingBuckets() throws Exception {
7575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
76d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
7775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
7875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // split almost completely into middle bucket, but with a few minutes
7975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // overlap into neighboring buckets. total record is 20 minutes.
8075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
8175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
8275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.recordData(recordStart, recordEnd, 1000L, 5000L);
8375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
84d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(3, stats.size());
8575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // first bucket should have (1/20 of value)
86d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 0, 50L, 250L);
8775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // second bucket should have (15/20 of value)
88d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 1, 750L, 3750L);
8975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // final bucket should have (4/20 of value)
90d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 2, 200L, 1000L);
9175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
9275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
9375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRecordGapBuckets() throws Exception {
9475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long BUCKET_SIZE = HOUR_IN_MILLIS;
95d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
9675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
9775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // record some data today and next week with large gap
9875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long firstStart = TEST_START;
9975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long lastStart = TEST_START + WEEK_IN_MILLIS;
10075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS, 128L, 256L);
10175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS, 64L, 512L);
10275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
10375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // we should have two buckets, far apart from each other
104d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(2, stats.size());
105d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 0, 128L, 256L);
106d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 1, 64L, 512L);
10775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
10875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // now record something in middle, spread across two buckets
10975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long middleStart = TEST_START + DAY_IN_MILLIS;
11075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
11175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.recordData(middleStart, middleEnd, 2048L, 2048L);
11275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
11375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // now should have four buckets, with new record in middle two buckets
114d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(4, stats.size());
115d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 0, 128L, 256L);
116d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 1, 1024L, 1024L);
117d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 2, 1024L, 1024L);
118d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 3, 64L, 512L);
11975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
12075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
12175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRecordOverlapBuckets() throws Exception {
12275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long BUCKET_SIZE = HOUR_IN_MILLIS;
123d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
12475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
12575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // record some data in one bucket, and another overlapping buckets
12675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 256L, 256L);
12775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
12875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.recordData(midStart, midStart + HOUR_IN_MILLIS, 1024L, 1024L);
12975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
13075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // should have two buckets, with some data mixed together
131d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(2, stats.size());
132d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 0, 768L, 768L);
133d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 1, 512L, 512L);
13475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
13575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
13619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    public void testRecordEntireGapIdentical() throws Exception {
13719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final long[] total = new long[2];
13819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
13919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // first, create two separate histories far apart
14019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
14119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L);
14219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
14319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final long TEST_START_2 = TEST_START + DAY_IN_MILLIS;
14419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS);
14519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L);
14619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
14719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // combine together with identical bucket size
14819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
14919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats1);
15019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats2);
15119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
15219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // first verify that totals match up
15319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
15419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        assertTotalEquals(total, 3000L, 1500L);
15519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
15619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // now inspect internal buckets
157d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 0, 1000L, 500L);
158d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 1, 1000L, 500L);
159d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 2, 500L, 250L);
160d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 3, 500L, 250L);
16119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
16219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
16319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    public void testRecordEntireOverlapVaryingBuckets() throws Exception {
16419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final long[] total = new long[2];
16519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
16619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // create history just over hour bucket boundary
16719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
16819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L);
16919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
17019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS;
17119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS);
17219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L);
17319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
17419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // combine together with minute bucket size
17519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats = new NetworkStatsHistory(MINUTE_IN_MILLIS);
17619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats1);
17719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats2);
17819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
17919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // first verify that totals match up
18019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
18119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        assertTotalEquals(total, 650L, 650L);
18219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
18319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // now inspect internal buckets
184d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 0, 10L, 10L);
185d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 1, 20L, 20L);
186d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 2, 20L, 20L);
187d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 3, 20L, 20L);
188d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 4, 20L, 20L);
189d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 5, 20L, 20L);
190d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 6, 10L, 10L);
19119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
19219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // now combine using 15min buckets
19319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4);
19419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats1);
19519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordEntireHistory(stats2);
19619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
19719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // first verify that totals match up
19819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
19919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        assertTotalEquals(total, 650L, 650L);
20019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
20119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // and inspect buckets
202d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 0, 200L, 200L);
203d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 1, 150L, 150L);
204d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 2, 150L, 150L);
205d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEntry(stats, 3, 150L, 150L);
20619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
20719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
20875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testRemove() throws Exception {
20919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
21075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
21175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // record some data across 24 buckets
21275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
213d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(24, stats.size());
21475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
21575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // try removing far before buckets; should be no change
21675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS);
217d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(24, stats.size());
21875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
21975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // try removing just moments into first bucket; should be no change
22075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // since that bucket contains data beyond the cutoff
22175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.removeBucketsBefore(TEST_START + SECOND_IN_MILLIS);
222d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(24, stats.size());
22375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
22475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // try removing single bucket
22575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.removeBucketsBefore(TEST_START + HOUR_IN_MILLIS);
226d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(23, stats.size());
22775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
22875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // try removing multiple buckets
22975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.removeBucketsBefore(TEST_START + (4 * HOUR_IN_MILLIS));
230d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(20, stats.size());
23175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
23275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // try removing all buckets
23375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        stats.removeBucketsBefore(TEST_START + YEAR_IN_MILLIS);
234d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals(0, stats.size());
23575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
23675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
23719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    public void testTotalData() throws Exception {
23819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final long BUCKET_SIZE = HOUR_IN_MILLIS;
23919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats = new NetworkStatsHistory(BUCKET_SIZE);
24019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
24119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // record uniform data across day
24219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L);
24319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
24419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        final long[] total = new long[2];
24519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
24619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // verify that total outside range is 0
24719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, total);
24819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        assertTotalEquals(total, 0, 0);
24919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
25019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // verify total in first hour
25119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.getTotalData(TEST_START, TEST_START + HOUR_IN_MILLIS, total);
25219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        assertTotalEquals(total, 100, 200);
25319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
25419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // verify total across 1.5 hours
25519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.getTotalData(TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), total);
25619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        assertTotalEquals(total, 150, 300);
25719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
25819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // verify total beyond end
25919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.getTotalData(TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, total);
26019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        assertTotalEquals(total, 100, 200);
26119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
26219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        // verify everything total
26319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
26419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        assertTotalEquals(total, 2400, 4800);
26519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
26619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
26719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
26875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    @Suppress
26975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void testFuzzing() throws Exception {
27075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        try {
27175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // fuzzing with random events, looking for crashes
27275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final Random r = new Random();
27375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            for (int i = 0; i < 500; i++) {
274d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey                stats = new NetworkStatsHistory(r.nextLong());
27575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                for (int j = 0; j < 10000; j++) {
27675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                    if (r.nextBoolean()) {
27775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        // add range
27875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        final long start = r.nextLong();
27975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        final long end = start + r.nextInt();
28075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        stats.recordData(start, end, r.nextLong(), r.nextLong());
28175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                    } else {
28275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        // trim something
28375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                        stats.removeBucketsBefore(r.nextLong());
28475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                    }
28575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                }
28675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                assertConsistent(stats);
28775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            }
28875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        } catch (Throwable e) {
28975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            Log.e(TAG, String.valueOf(stats));
29075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            throw new RuntimeException(e);
29175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
29275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
29375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
29475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private static void assertConsistent(NetworkStatsHistory stats) {
29575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // verify timestamps are monotonic
296d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        long lastStart = Long.MIN_VALUE;
297d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        NetworkStatsHistory.Entry entry = null;
298d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        for (int i = 0; i < stats.size(); i++) {
299d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            entry = stats.getValues(i, entry);
300d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            assertTrue(lastStart < entry.bucketStart);
301d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            lastStart = entry.bucketStart;
30275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
30375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
30475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
305d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private static void assertTotalEquals(long[] total, long rxBytes, long txBytes) {
306d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals("unexpected rxBytes", rxBytes, total[0]);
307d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals("unexpected txBytes", txBytes, total[1]);
30819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
30919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
310d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private static void assertEntry(
311d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            NetworkStatsHistory stats, int index, long rxBytes, long txBytes) {
312d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
313d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
314d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
31575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
31675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
31775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey}
318