163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey/*
263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Copyright (C) 2012 The Android Open Source Project
363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey *
463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * you may not use this file except in compliance with the License.
663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * You may obtain a copy of the License at
763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey *
863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey *
1063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Unless required by applicable law or agreed to in writing, software
1163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
1263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * See the License for the specific language governing permissions and
1463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * limitations under the License.
1563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */
1663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
1763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeypackage com.android.server.net;
1863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
191efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidsonimport static android.net.ConnectivityManager.TYPE_MOBILE;
20f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport static android.net.NetworkStats.SET_ALL;
2170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkeyimport static android.net.NetworkStats.SET_DEFAULT;
2270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkeyimport static android.net.NetworkStats.TAG_NONE;
2370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkeyimport static android.net.NetworkStats.UID_ALL;
24f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport static android.net.NetworkStatsHistory.FIELD_ALL;
2563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.NetworkTemplate.buildTemplateMobileAll;
26f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport static android.os.Process.myUid;
2770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkeyimport static android.text.format.DateUtils.HOUR_IN_MILLIS;
2863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.text.format.DateUtils.MINUTE_IN_MILLIS;
293d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichiimport static org.junit.Assert.assertEquals;
303d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichiimport static org.junit.Assert.assertNotNull;
313d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichiimport static org.junit.Assert.fail;
3263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
33d405d0555ce704d0417b85884ed267ac141302deJeff Sharkeyimport static com.android.server.net.NetworkStatsCollection.multiplySafe;
34d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
3563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.content.res.Resources;
36d405d0555ce704d0417b85884ed267ac141302deJeff Sharkeyimport android.net.ConnectivityManager;
371efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidsonimport android.net.NetworkIdentity;
3863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStats;
39f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport android.net.NetworkStatsHistory;
4063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkTemplate;
411efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidsonimport android.os.Process;
421efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidsonimport android.os.UserHandle;
433d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichiimport android.support.test.InstrumentationRegistry;
443d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichiimport android.support.test.filters.SmallTest;
453d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichiimport android.support.test.runner.AndroidJUnit4;
46f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport android.telephony.SubscriptionPlan;
471efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidsonimport android.telephony.TelephonyManager;
481efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidsonimport android.test.MoreAsserts;
49f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport android.text.format.DateUtils;
50d405d0555ce704d0417b85884ed267ac141302deJeff Sharkeyimport android.util.RecurrenceRule;
5163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
52e7e10303f3bc545a9763fab7a7e89da9120bedfaHugo Benichiimport com.android.frameworks.tests.net.R;
5363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
54f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport libcore.io.IoUtils;
55f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport libcore.io.Streams;
56f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
5763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.ByteArrayInputStream;
5863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.ByteArrayOutputStream;
5963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.DataOutputStream;
6063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.File;
6163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.FileOutputStream;
6263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.InputStream;
6363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.OutputStream;
64d405d0555ce704d0417b85884ed267ac141302deJeff Sharkeyimport java.time.Clock;
65d405d0555ce704d0417b85884ed267ac141302deJeff Sharkeyimport java.time.Instant;
66d405d0555ce704d0417b85884ed267ac141302deJeff Sharkeyimport java.time.ZoneId;
67f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport java.time.ZonedDateTime;
68f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport java.util.ArrayList;
69f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport java.util.List;
7063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
713d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichiimport org.junit.After;
723d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichiimport org.junit.Before;
733d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichiimport org.junit.Test;
743d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichiimport org.junit.runner.RunWith;
753d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi
7663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey/**
7763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Tests for {@link NetworkStatsCollection}.
7863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */
793d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi@RunWith(AndroidJUnit4.class)
80e7e10303f3bc545a9763fab7a7e89da9120bedfaHugo Benichi@SmallTest
813d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichipublic class NetworkStatsCollectionTest {
820cf6de0c930c9082b7bffdb9824e4a7c7832b6dfJeff Sharkey
8363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final String TEST_FILE = "test.bin";
8463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final String TEST_IMSI = "310260000000000";
8563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
86f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    private static final long TIME_A = 1326088800000L; // UTC: Monday 9th January 2012 06:00:00 AM
87f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    private static final long TIME_B = 1326110400000L; // UTC: Monday 9th January 2012 12:00:00 PM
88f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    private static final long TIME_C = 1326132000000L; // UTC: Monday 9th January 2012 06:00:00 PM
89f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
90d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey    private static Clock sOriginalClock;
91d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
923d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @Before
9370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    public void setUp() throws Exception {
94d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        sOriginalClock = RecurrenceRule.sClock;
9570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        // ignore any device overlay while testing
9670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        NetworkTemplate.forceAllNetworkTypes();
9770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    }
9870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
993d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @After
1003d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    public void tearDown() throws Exception {
101d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        RecurrenceRule.sClock = sOriginalClock;
102d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey    }
103d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
104d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey    private void setClock(Instant instant) {
105d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        RecurrenceRule.sClock = Clock.fixed(instant, ZoneId.systemDefault());
106d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey    }
107d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
1083d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @Test
10963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void testReadLegacyNetwork() throws Exception {
1103d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi        final File testFile =
1113d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi                new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
11263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        stageFile(R.raw.netstats_v1, testFile);
11363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
11463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
11563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.readLegacyNetwork(testFile);
1160cf6de0c930c9082b7bffdb9824e4a7c7832b6dfJeff Sharkey
11763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // verify that history read correctly
11863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
1191efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
12063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
12163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // now export into a unified format
12263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
12363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.write(new DataOutputStream(bos));
12463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
12563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // clear structure completely
12663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.reset();
12763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
1281efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
12963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
13063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // and read back into structure, verifying that totals are same
13163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.read(new ByteArrayInputStream(bos.toByteArray()));
13263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
1331efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
13463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
13563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
1363d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @Test
13763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void testReadLegacyUid() throws Exception {
1383d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi        final File testFile =
1393d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi                new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
14063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        stageFile(R.raw.netstats_uid_v4, testFile);
14163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
14263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
14363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.readLegacyUid(testFile, false);
14463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
14563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // verify that history read correctly
14663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
1471efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
14863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
14963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // now export into a unified format
15063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
15163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.write(new DataOutputStream(bos));
15263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
15363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // clear structure completely
15463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.reset();
15563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
1561efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
15763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
15863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // and read back into structure, verifying that totals are same
15963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.read(new ByteArrayInputStream(bos.toByteArray()));
16063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
1611efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
16263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
16363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
1643d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @Test
16563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void testReadLegacyUidTags() throws Exception {
1663d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi        final File testFile =
1673d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi                new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
16863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        stageFile(R.raw.netstats_uid_v4, testFile);
16963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
17063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
17163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.readLegacyUid(testFile, true);
17263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
17363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // verify that history read correctly
17463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
17563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                77017831L, 100995L, 35436758L, 92344L);
17663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
17763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // now export into a unified format
17863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
17963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.write(new DataOutputStream(bos));
18063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
18163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // clear structure completely
18263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.reset();
18363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
18463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                0L, 0L, 0L, 0L);
18563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
18663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // and read back into structure, verifying that totals are same
18763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.read(new ByteArrayInputStream(bos.toByteArray()));
18863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
18963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                77017831L, 100995L, 35436758L, 92344L);
19063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
19163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
1923d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @Test
19370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    public void testStartEndAtomicBuckets() throws Exception {
19470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
19570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
19670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        // record empty data straddling between buckets
19770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        final NetworkStats.Entry entry = new NetworkStats.Entry();
19870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        entry.rxBytes = 32;
19970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        collection.recordData(null, UID_ALL, SET_DEFAULT, TAG_NONE, 30 * MINUTE_IN_MILLIS,
20070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey                90 * MINUTE_IN_MILLIS, entry);
20170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
20270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        // assert that we report boundary in atomic buckets
20370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        assertEquals(0, collection.getStartMillis());
20470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        assertEquals(2 * HOUR_IN_MILLIS, collection.getEndMillis());
20570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    }
20670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
2073d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @Test
2081efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson    public void testAccessLevels() throws Exception {
2091efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
2101efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        final NetworkStats.Entry entry = new NetworkStats.Entry();
2111efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        final NetworkIdentitySet identSet = new NetworkIdentitySet();
2121efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
213d3e4a1e250194bbf59b1e04b60711f97001f61f8Lorenzo Colitti                TEST_IMSI, null, false, true, true));
2141efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson
2151efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        int myUid = Process.myUid();
2161efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        int otherUidInSameUser = Process.myUid() + 1;
2171efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        int uidInDifferentUser = Process.myUid() + UserHandle.PER_USER_RANGE;
2181efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson
2191efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        // Record one entry for the current UID.
2201efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        entry.rxBytes = 32;
2211efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        collection.recordData(identSet, myUid, SET_DEFAULT, TAG_NONE, 0, 60 * MINUTE_IN_MILLIS,
2221efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                entry);
2231efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson
2241efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        // Record one entry for another UID in this user.
2251efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        entry.rxBytes = 64;
2261efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        collection.recordData(identSet, otherUidInSameUser, SET_DEFAULT, TAG_NONE, 0,
2271efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                60 * MINUTE_IN_MILLIS, entry);
2281efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson
2291efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        // Record one entry for the system UID.
2301efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        entry.rxBytes = 128;
2311efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        collection.recordData(identSet, Process.SYSTEM_UID, SET_DEFAULT, TAG_NONE, 0,
2321efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                60 * MINUTE_IN_MILLIS, entry);
2331efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson
2341efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        // Record one entry for a UID in a different user.
2351efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        entry.rxBytes = 256;
2361efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        collection.recordData(identSet, uidInDifferentUser, SET_DEFAULT, TAG_NONE, 0,
2371efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                60 * MINUTE_IN_MILLIS, entry);
2381efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson
2391efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        // Verify the set of relevant UIDs for each access level.
2401efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        MoreAsserts.assertEquals(new int[] { myUid },
2411efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                collection.getRelevantUids(NetworkStatsAccess.Level.DEFAULT));
2421efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        MoreAsserts.assertEquals(new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser },
2431efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                collection.getRelevantUids(NetworkStatsAccess.Level.USER));
2441efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        MoreAsserts.assertEquals(
2451efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser, uidInDifferentUser },
2461efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                collection.getRelevantUids(NetworkStatsAccess.Level.DEVICE));
2471efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson
2481efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        // Verify security check in getHistory.
249f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertNotNull(collection.getHistory(buildTemplateMobileAll(TEST_IMSI), null, myUid, SET_DEFAULT,
250f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                TAG_NONE, 0, 0L, 0L, NetworkStatsAccess.Level.DEFAULT, myUid));
2511efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        try {
252f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            collection.getHistory(buildTemplateMobileAll(TEST_IMSI), null, otherUidInSameUser,
253f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                    SET_DEFAULT, TAG_NONE, 0, 0L, 0L, NetworkStatsAccess.Level.DEFAULT, myUid);
2541efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson            fail("Should have thrown SecurityException for accessing different UID");
2551efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        } catch (SecurityException e) {
2561efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson            // expected
2571efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        }
2581efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson
2591efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        // Verify appropriate aggregation in getSummary.
2601efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32, 0, 0, 0,
2611efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                NetworkStatsAccess.Level.DEFAULT);
2621efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128, 0, 0, 0,
2631efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                NetworkStatsAccess.Level.USER);
2641efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128 + 256, 0, 0,
2651efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                0, NetworkStatsAccess.Level.DEVICE);
2661efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson    }
2671efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson
2683d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @Test
269f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    public void testAugmentPlan() throws Exception {
2703d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi        final File testFile =
2713d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi                new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
272f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        stageFile(R.raw.netstats_v1, testFile);
273f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
274f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        final NetworkStatsCollection emptyCollection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
275f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
276f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        collection.readLegacyNetwork(testFile);
277f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
278d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        // We're in the future, but not that far off
279d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        setClock(Instant.parse("2012-06-01T00:00:00.00Z"));
280d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
281f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // Test a bunch of plans that should result in no augmentation
282f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        final List<SubscriptionPlan> plans = new ArrayList<>();
283f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
284f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // No plan
285f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        plans.add(null);
286f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // No usage anchor
287f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        plans.add(SubscriptionPlan.Builder
288f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z")).build());
289f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // Usage anchor far in past
290f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        plans.add(SubscriptionPlan.Builder
291f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z"))
292f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                .setDataUsage(1000L, TIME_A - DateUtils.YEAR_IN_MILLIS).build());
293f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // Usage anchor far in future
294f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        plans.add(SubscriptionPlan.Builder
295f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z"))
296f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                .setDataUsage(1000L, TIME_A + DateUtils.YEAR_IN_MILLIS).build());
297f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // Usage anchor near but outside cycle
298f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        plans.add(SubscriptionPlan.Builder
299f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
300f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                        ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
301f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                .setDataUsage(1000L, TIME_C).build());
302f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
303f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        for (SubscriptionPlan plan : plans) {
304f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            int i;
305f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            NetworkStatsHistory history;
306f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
307f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Empty collection should be untouched
308f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
309f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEquals(0L, history.getTotalBytes());
310f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
311f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Normal collection should be untouched
312f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
313f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
314f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
315f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
316f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
317f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
318f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
319f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(10747, 50, 16838, 55, history.getValues(i++, null));
320f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(10747, 49, 16838, 54, history.getValues(i++, null));
321f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(89191, 151, 18021, 140, history.getValues(i++, null));
322f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(89190, 150, 18020, 139, history.getValues(i++, null));
323f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(3821, 22, 4525, 26, history.getValues(i++, null));
324f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(3820, 22, 4524, 26, history.getValues(i++, null));
325f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
326f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
327f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
328f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
329f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
330f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
331f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
332f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
333f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
334f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
335f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
336f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
337f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEquals(history.size(), i);
338f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
339f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Slice from middle should be untouched
340f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
341f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                    TIME_B + HOUR_IN_MILLIS); i = 0;
342f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(3821, 22, 4525, 26, history.getValues(i++, null));
343f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(3820, 22, 4524, 26, history.getValues(i++, null));
344f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
345f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
346f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEquals(history.size(), i);
347f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        }
348f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
349f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // Lower anchor in the middle of plan
350f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        {
351f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            int i;
352f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            NetworkStatsHistory history;
353f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
354f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            final SubscriptionPlan plan = SubscriptionPlan.Builder
355f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                    .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
356f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                            ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
357f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                    .setDataUsage(200000L, TIME_B).build();
358f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
359f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Empty collection should be augmented
360f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
361f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEquals(200000L, history.getTotalBytes());
362f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
363f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Normal collection should be augmented
364f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
365f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
366f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
367f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
368f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
369f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
370f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
371f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Cycle point; start data normalization
372f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
373f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
374f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(62309, 0, 12589, 0, history.getValues(i++, null));
375f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(62309, 0, 12588, 0, history.getValues(i++, null));
376f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
377f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
378f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Anchor point; end data normalization
379f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
380f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
381f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
382f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
383f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
384f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
385f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Cycle point
386f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
387f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
388f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
389f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
390f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
391f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
392f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEquals(history.size(), i);
393f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
394f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Slice from middle should be augmented
395f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
396f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                    TIME_B + HOUR_IN_MILLIS); i = 0;
397f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
398f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
399f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
400f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
401f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEquals(history.size(), i);
402f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        }
403f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
404f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // Higher anchor in the middle of plan
405f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        {
406f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            int i;
407f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            NetworkStatsHistory history;
408f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
409f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            final SubscriptionPlan plan = SubscriptionPlan.Builder
410f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                    .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
411f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                            ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
412f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                    .setDataUsage(400000L, TIME_B + MINUTE_IN_MILLIS).build();
413f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
414f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Empty collection should be augmented
415f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
416f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEquals(400000L, history.getTotalBytes());
417f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
418f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Normal collection should be augmented
419f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
420f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
421f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
422f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
423f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
424f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
425f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
426f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Cycle point; start data normalization
427f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(15015, 0, 23526, 0, history.getValues(i++, null));
428f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(15015, 0, 23526, 0, history.getValues(i++, null));
429f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(124619, 0, 25179, 0, history.getValues(i++, null));
430f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(124618, 0, 25177, 0, history.getValues(i++, null));
431f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
432f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
433f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Anchor point; end data normalization
434f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
435f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
436f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
437f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
438f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
439f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
440f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Cycle point
441f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
442f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
443f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
444f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
445f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
446f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
447f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
448f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            // Slice from middle should be augmented
449f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
450f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                    TIME_B + HOUR_IN_MILLIS); i = 0;
451f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
452f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
453f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
454f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
455f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEquals(history.size(), i);
456f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        }
457f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    }
458f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
4593d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @Test
460d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey    public void testAugmentPlanGigantic() throws Exception {
461d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        // We're in the future, but not that far off
462d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        setClock(Instant.parse("2012-06-01T00:00:00.00Z"));
463d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
464d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        // Create a simple history with a ton of measured usage
465d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        final NetworkStatsCollection large = new NetworkStatsCollection(HOUR_IN_MILLIS);
466d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        final NetworkIdentitySet ident = new NetworkIdentitySet();
467d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null,
468d3e4a1e250194bbf59b1e04b60711f97001f61f8Lorenzo Colitti                false, true, true));
469d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B,
470d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey                new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0));
471d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
472d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        // Verify untouched total
473d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(12_730_893_164L, getHistory(large, null, TIME_A, TIME_C).getTotalBytes());
474d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
475d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        // Verify anchor that might cause overflows
476d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        final SubscriptionPlan plan = SubscriptionPlan.Builder
477d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey                .createRecurringMonthly(ZonedDateTime.parse("2012-01-09T00:00:00.00Z"))
478d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey                .setDataUsage(4_939_212_390L, TIME_B).build();
479d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(4_939_212_386L, getHistory(large, plan, TIME_A, TIME_C).getTotalBytes());
480d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey    }
481d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
4823d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @Test
483f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    public void testRounding() throws Exception {
484f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        final NetworkStatsCollection coll = new NetworkStatsCollection(HOUR_IN_MILLIS);
485f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
486f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // Special values should remain unchanged
487f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        for (long time : new long[] {
488f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                Long.MIN_VALUE, Long.MAX_VALUE, SubscriptionPlan.TIME_UNKNOWN
489f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        }) {
490f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEquals(time, coll.roundUp(time));
491f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            assertEquals(time, coll.roundDown(time));
492f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        }
493f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
494f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEquals(TIME_A, coll.roundUp(TIME_A));
495f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEquals(TIME_A, coll.roundDown(TIME_A));
496f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
497f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEquals(TIME_A + HOUR_IN_MILLIS, coll.roundUp(TIME_A + 1));
498f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEquals(TIME_A, coll.roundDown(TIME_A + 1));
499f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
500f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEquals(TIME_A, coll.roundUp(TIME_A - 1));
501f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEquals(TIME_A - HOUR_IN_MILLIS, coll.roundDown(TIME_A - 1));
502f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    }
503f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
5043d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi    @Test
505d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey    public void testMultiplySafe() {
506d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(25, multiplySafe(50, 1, 2));
507d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(100, multiplySafe(50, 2, 1));
508d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
509d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(-10, multiplySafe(30, -1, 3));
510d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(0, multiplySafe(30, 0, 3));
511d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(10, multiplySafe(30, 1, 3));
512d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(20, multiplySafe(30, 2, 3));
513d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(30, multiplySafe(30, 3, 3));
514d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(40, multiplySafe(30, 4, 3));
515d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
516d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(100_000_000_000L,
517d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey                multiplySafe(300_000_000_000L, 10_000_000_000L, 30_000_000_000L));
518d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(100_000_000_010L,
519d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey                multiplySafe(300_000_000_000L, 10_000_000_001L, 30_000_000_000L));
520d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey        assertEquals(823_202_048L,
521d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey                multiplySafe(4_939_212_288L, 2_121_815_528L, 12_730_893_165L));
522d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey    }
523d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey
52463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
52563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Copy a {@link Resources#openRawResource(int)} into {@link File} for
52663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * testing purposes.
52763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
52863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private void stageFile(int rawId, File file) throws Exception {
52963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        new File(file.getParent()).mkdirs();
53063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        InputStream in = null;
53163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        OutputStream out = null;
53263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        try {
5333d6ba6ed6d1d3ab90a50fb3b461d833db381fe9fHugo Benichi            in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
53463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            out = new FileOutputStream(file);
53563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            Streams.copy(in, out);
53663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } finally {
53763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            IoUtils.closeQuietly(in);
53863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            IoUtils.closeQuietly(out);
53963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
54063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
54163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
542f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    private static NetworkStatsHistory getHistory(NetworkStatsCollection collection,
543f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            SubscriptionPlan augmentPlan, long start, long end) {
544f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        return collection.getHistory(buildTemplateMobileAll(TEST_IMSI), augmentPlan, UID_ALL,
545f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                SET_ALL, TAG_NONE, FIELD_ALL, start, end, NetworkStatsAccess.Level.DEVICE, myUid());
546f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    }
547f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
54863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static void assertSummaryTotal(NetworkStatsCollection collection,
5491efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson            NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets,
5501efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson            @NetworkStatsAccess.Level int accessLevel) {
551f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        final NetworkStats.Entry actual = collection.getSummary(
552f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                template, Long.MIN_VALUE, Long.MAX_VALUE, accessLevel, myUid())
5531efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                .getTotal(null);
554f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEntry(rxBytes, rxPackets, txBytes, txPackets, actual);
55563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
55663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
55763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection,
55863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
559f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        final NetworkStats.Entry actual = collection.getSummary(
560f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                template, Long.MIN_VALUE, Long.MAX_VALUE, NetworkStatsAccess.Level.DEVICE, myUid())
5611efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                .getTotalIncludingTags(null);
562f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEntry(rxBytes, rxPackets, txBytes, txPackets, actual);
563f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    }
564f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
565f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
566f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            NetworkStats.Entry actual) {
567f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
568f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    }
569f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
570f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
571f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            NetworkStatsHistory.Entry actual) {
572f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
573f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    }
574f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
575f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    private static void assertEntry(NetworkStats.Entry expected,
576f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            NetworkStatsHistory.Entry actual) {
577f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEntry(expected, new NetworkStats.Entry(actual.rxBytes, actual.rxPackets,
578f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                actual.txBytes, actual.txPackets, 0L));
57963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
58063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
581f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    private static void assertEntry(NetworkStats.Entry expected,
582f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey            NetworkStats.Entry actual) {
583f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEquals("unexpected rxBytes", expected.rxBytes, actual.rxBytes);
584f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEquals("unexpected rxPackets", expected.rxPackets, actual.rxPackets);
585f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEquals("unexpected txBytes", expected.txBytes, actual.txBytes);
586f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        assertEquals("unexpected txPackets", expected.txPackets, actual.txPackets);
58763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
58863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey}
589