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