1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.netstats
18 
19 import android.net.NetworkStats
20 import android.net.NetworkStats.DEFAULT_NETWORK_NO
21 import android.net.NetworkStats.DEFAULT_NETWORK_YES
22 import android.net.NetworkStats.Entry
23 import android.net.NetworkStats.IFACE_VT
24 import android.net.NetworkStats.METERED_NO
25 import android.net.NetworkStats.METERED_YES
26 import android.net.NetworkStats.ROAMING_NO
27 import android.net.NetworkStats.ROAMING_YES
28 import android.net.NetworkStats.SET_DEFAULT
29 import android.net.NetworkStats.SET_FOREGROUND
30 import android.net.NetworkStats.TAG_NONE
31 import android.os.Build
32 import androidx.test.filters.SmallTest
33 import com.android.testutils.DevSdkIgnoreRule
34 import com.android.testutils.assertNetworkStatsEquals
35 import com.android.testutils.assertParcelingIsLossless
36 import org.junit.Before
37 import org.junit.Rule
38 import org.junit.Test
39 import org.junit.runner.RunWith
40 import org.junit.runners.JUnit4
41 import kotlin.test.assertEquals
42 
43 @RunWith(JUnit4::class)
44 @SmallTest
45 class NetworkStatsApiTest {
46     @Rule
47     @JvmField
48     val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q)
49 
50     private val testStatsEmpty = NetworkStats(0L, 0)
51 
52     // Note that these variables need to be initialized outside of constructor, initialize
53     // here with methods that don't exist in Q devices will result in crash.
54 
55     // stats1 and stats2 will have some entries with common keys, which are expected to
56     // be merged if performing add on these 2 stats.
57     private lateinit var testStats1: NetworkStats
58     private lateinit var testStats2: NetworkStats
59 
60     // This is a result of adding stats1 and stats2, while the merging of common key items is
61     // subject to test later, this should not be initialized with for a loop to add stats1
62     // and stats2 above.
63     private lateinit var testStats3: NetworkStats
64 
65     companion object {
66         private const val TEST_IFACE = "test0"
67         private const val TEST_UID1 = 1001
68         private const val TEST_UID2 = 1002
69     }
70 
71     @Before
72     fun setUp() {
73         testStats1 = NetworkStats(0L, 0)
74                 // Entries which only appear in set1.
75                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
76                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
77                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
78                         METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
79                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
80                         METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
81                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
82                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 37, 52, 1, 10, 4))
83                 // Entries which are common for set1 and set2.
84                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
85                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
86                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
87                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 17, 2, 11, 1, 0))
88                 .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
89                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 40, 1, 0, 0, 8))
90                 .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
91                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0))
92         assertEquals(8, testStats1.size())
93 
94         testStats2 = NetworkStats(0L, 0)
95                 // Entries which are common for set1 and set2.
96                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
97                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1))
98                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
99                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
100                 .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
101                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7))
102                 .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
103                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0))
104                 // Entry which only appears in set2.
105                 .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
106                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
107         assertEquals(5, testStats2.size())
108 
109         testStats3 = NetworkStats(0L, 9)
110                 // Entries which are unique either in stats1 or stats2.
111                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
112                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
113                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
114                         METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
115                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
116                         METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
117                 .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
118                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
119                 // Entries which are common for stats1 and stats2 are being merged.
120                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
121                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
122                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
123                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 20, 17, 13, 32, 1))
124                 .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
125                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50, 113, 11, 11, 49))
126                 .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
127                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 51, 3, 3, 4, 15))
128                 .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
129                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7, 4, 8, 3, 0))
130         assertEquals(9, testStats3.size())
131     }
132 
133     @Test
134     fun testAddEntry() {
135         val expectedEntriesInStats2 = arrayOf(
136                 Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
137                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1),
138                 Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
139                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45),
140                 Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
141                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7),
142                 Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
143                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0),
144                 Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
145                         METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
146 
147         // While testStats* are already initialized with addEntry, verify content added
148         // matches expectation.
149         for (i in expectedEntriesInStats2.indices) {
150             val entry = testStats2.getValues(i, null)
151             assertEquals(expectedEntriesInStats2[i], entry)
152         }
153 
154         // Verify entry updated with addEntry.
155         val stats = testStats2.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
156                 METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12, -5, 7, 0, 9))
157         assertEquals(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
158                 METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16, -2, 9, 1, 9),
159                 stats.getValues(3, null))
160     }
161 
162     @Test
163     fun testAdd() {
164         var stats = NetworkStats(0L, 0)
165         assertNetworkStatsEquals(testStatsEmpty, stats)
166         stats = stats.add(testStats2)
167         assertNetworkStatsEquals(testStats2, stats)
168         stats = stats.add(testStats1)
169         // EMPTY + STATS2 + STATS1 = STATS3
170         assertNetworkStatsEquals(testStats3, stats)
171     }
172 
173     @Test
174     fun testParcelUnparcel() {
175         assertParcelingIsLossless(testStatsEmpty)
176         assertParcelingIsLossless(testStats1)
177         assertParcelingIsLossless(testStats2)
178     }
179 
180     @Test
181     fun testDescribeContents() {
182         assertEquals(0, testStatsEmpty.describeContents())
183         assertEquals(0, testStats1.describeContents())
184         assertEquals(0, testStats2.describeContents())
185         assertEquals(0, testStats3.describeContents())
186     }
187 
188     @Test
189     fun testSubtract() {
190         // STATS3 - STATS2 = STATS1
191         assertNetworkStatsEquals(testStats1, testStats3.subtract(testStats2))
192         // STATS3 - STATS1 = STATS2
193         assertNetworkStatsEquals(testStats2, testStats3.subtract(testStats1))
194     }
195 
196     @Test
197     fun testMethodsDontModifyReceiver() {
198         listOf(testStatsEmpty, testStats1, testStats2, testStats3).forEach {
199             val origStats = it.clone()
200             it.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
201                     METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
202             it.add(testStats3)
203             it.subtract(testStats1)
204             assertNetworkStatsEquals(origStats, it)
205         }
206     }
207 }