/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app.usage; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.net.ConnectivityManager; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; import android.net.NetworkStats.Entry; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.RemoteException; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; @RunWith(AndroidJUnit4.class) @SmallTest public class NetworkStatsManagerTest { private @Mock INetworkStatsService mService; private @Mock INetworkStatsSession mStatsSession; private NetworkStatsManager mManager; // TODO: change to NetworkTemplate.MATCH_MOBILE once internal constant rename is merged to aosp. private static final int MATCH_MOBILE_ALL = 1; @Before public void setUp() { MockitoAnnotations.initMocks(this); mManager = new NetworkStatsManager(InstrumentationRegistry.getContext(), mService); } @Test public void testQueryDetails() throws RemoteException { final String subscriberId = "subid"; final long startTime = 1; final long endTime = 100; final int uid1 = 10001; final int uid2 = 10002; final int uid3 = 10003; Entry uid1Entry1 = new Entry("if1", uid1, android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE, 100, 10, 200, 20, 0); Entry uid1Entry2 = new Entry( "if2", uid1, android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE, 100, 10, 200, 20, 0); Entry uid2Entry1 = new Entry("if1", uid2, android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE, 150, 10, 250, 20, 0); Entry uid2Entry2 = new Entry( "if2", uid2, android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE, 150, 10, 250, 20, 0); NetworkStatsHistory history1 = new NetworkStatsHistory(10, 2); history1.recordData(10, 20, uid1Entry1); history1.recordData(20, 30, uid1Entry2); NetworkStatsHistory history2 = new NetworkStatsHistory(10, 2); history1.recordData(30, 40, uid2Entry1); history1.recordData(35, 45, uid2Entry2); when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession); when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2, uid3 }); when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class), eq(uid1), eq(android.net.NetworkStats.SET_ALL), eq(android.net.NetworkStats.TAG_NONE), eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime))) .then((InvocationOnMock inv) -> { NetworkTemplate template = inv.getArgument(0); assertEquals(MATCH_MOBILE_ALL, template.getMatchRule()); assertEquals(subscriberId, template.getSubscriberId()); return history1; }); when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class), eq(uid2), eq(android.net.NetworkStats.SET_ALL), eq(android.net.NetworkStats.TAG_NONE), eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime))) .then((InvocationOnMock inv) -> { NetworkTemplate template = inv.getArgument(0); assertEquals(MATCH_MOBILE_ALL, template.getMatchRule()); assertEquals(subscriberId, template.getSubscriberId()); return history2; }); NetworkStats stats = mManager.queryDetails( ConnectivityManager.TYPE_MOBILE, subscriberId, startTime, endTime); NetworkStats.Bucket bucket = new NetworkStats.Bucket(); // First 2 buckets exactly match entry timings assertTrue(stats.getNextBucket(bucket)); assertEquals(10, bucket.getStartTimeStamp()); assertEquals(20, bucket.getEndTimeStamp()); assertBucketMatches(uid1Entry1, bucket); assertTrue(stats.getNextBucket(bucket)); assertEquals(20, bucket.getStartTimeStamp()); assertEquals(30, bucket.getEndTimeStamp()); assertBucketMatches(uid1Entry2, bucket); // 30 -> 40: contains uid2Entry1 and half of uid2Entry2 assertTrue(stats.getNextBucket(bucket)); assertEquals(30, bucket.getStartTimeStamp()); assertEquals(40, bucket.getEndTimeStamp()); assertEquals(225, bucket.getRxBytes()); assertEquals(15, bucket.getRxPackets()); assertEquals(375, bucket.getTxBytes()); assertEquals(30, bucket.getTxPackets()); // 40 -> 50: contains half of uid2Entry2 assertTrue(stats.getNextBucket(bucket)); assertEquals(40, bucket.getStartTimeStamp()); assertEquals(50, bucket.getEndTimeStamp()); assertEquals(75, bucket.getRxBytes()); assertEquals(5, bucket.getRxPackets()); assertEquals(125, bucket.getTxBytes()); assertEquals(10, bucket.getTxPackets()); assertFalse(stats.hasNextBucket()); } @Test public void testQueryDetails_NoSubscriberId() throws RemoteException { final long startTime = 1; final long endTime = 100; final int uid1 = 10001; final int uid2 = 10002; when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession); when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2 }); NetworkStats stats = mManager.queryDetails( ConnectivityManager.TYPE_MOBILE, null, startTime, endTime); when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class), anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyLong())) .thenReturn(new NetworkStatsHistory(10, 0)); verify(mStatsSession, times(1)).getHistoryIntervalForUid( argThat((NetworkTemplate t) -> // No subscriberId: MATCH_MOBILE_WILDCARD template t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD), eq(uid1), eq(android.net.NetworkStats.SET_ALL), eq(android.net.NetworkStats.TAG_NONE), eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)); verify(mStatsSession, times(1)).getHistoryIntervalForUid( argThat((NetworkTemplate t) -> // No subscriberId: MATCH_MOBILE_WILDCARD template t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD), eq(uid2), eq(android.net.NetworkStats.SET_ALL), eq(android.net.NetworkStats.TAG_NONE), eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)); assertFalse(stats.hasNextBucket()); } private void assertBucketMatches(Entry expected, NetworkStats.Bucket actual) { assertEquals(expected.uid, actual.getUid()); assertEquals(expected.rxBytes, actual.getRxBytes()); assertEquals(expected.rxPackets, actual.getRxPackets()); assertEquals(expected.txBytes, actual.getTxBytes()); assertEquals(expected.txPackets, actual.getTxPackets()); } }