[SP26] add CTS for NetworkStats

Test: atest NetworkStatsApiTest
Test: atest CtsNetTestCasesLatestSdk:NetworkStatsApiTest on Q device
Bug: 150644692
Change-Id: I690704b43cfd16de70c4c83916f6d750cf613f67
diff --git a/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt b/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt
new file mode 100644
index 0000000..9119d62
--- /dev/null
+++ b/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2020 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.net.netstats
+
+import android.net.NetworkStats
+import android.net.NetworkStats.DEFAULT_NETWORK_NO
+import android.net.NetworkStats.DEFAULT_NETWORK_YES
+import android.net.NetworkStats.Entry
+import android.net.NetworkStats.IFACE_VT
+import android.net.NetworkStats.METERED_NO
+import android.net.NetworkStats.METERED_YES
+import android.net.NetworkStats.ROAMING_NO
+import android.net.NetworkStats.ROAMING_YES
+import android.net.NetworkStats.SET_DEFAULT
+import android.net.NetworkStats.SET_FOREGROUND
+import android.net.NetworkStats.TAG_NONE
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import com.android.testutils.assertFieldCountEquals
+import com.android.testutils.assertNetworkStatsEquals
+import com.android.testutils.assertParcelingIsLossless
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import kotlin.test.assertEquals
+
+@RunWith(JUnit4::class)
+@SmallTest
+class NetworkStatsApiTest {
+    @Rule
+    @JvmField
+    val ignoreRule = DevSdkIgnoreRule()
+
+    private val testStatsEmpty = NetworkStats(0L, 0)
+
+    // stats1 and stats2 will have some entries with common keys, which are expected to
+    // be merged if performing add on these 2 stats.
+    private val testStats1 = NetworkStats(0L, 0)
+            // Entries which only appear in set1.
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 37, 52, 1, 10, 4))
+            // Entries which are common for set1 and set2.
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 17, 2, 11, 1, 0))
+            .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 40, 1, 0, 0, 8))
+            .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0))
+
+    private val testStats2 = NetworkStats(0L, 0)
+            // Entries which are common for set1 and set2.
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1))
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
+            .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7))
+            .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0))
+            // Entry which only appears in set2.
+            .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
+
+    // This is a result of adding stats1 and stats2, while the merging of common key items is
+    // subject to test later, this should not be initialized with for a loop to add stats1
+    // and stats2 above.
+    private val testStats3 = NetworkStats(0L, 9)
+            // Entries which are unique either in stats1 or stats2.
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
+            .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
+            // Entries which are common for stats1 and stats2 are being merged.
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 20, 17, 13, 32, 1))
+            .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50, 113, 11, 11, 49))
+            .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 51, 3, 3, 4, 15))
+            .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7, 4, 8, 3, 0))
+
+    companion object {
+        private const val TEST_IFACE = "test0"
+        private const val TEST_UID1 = 1001
+        private const val TEST_UID2 = 1002
+    }
+
+    @Before
+    fun setUp() {
+        assertEquals(8, testStats1.size())
+        assertEquals(5, testStats2.size())
+        assertEquals(9, testStats3.size())
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.Q)
+    fun testAddEntry() {
+        val expectedEntriesInStats2 = arrayOf(
+                Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
+                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1),
+                Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45),
+                Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
+                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7),
+                Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0),
+                Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
+                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
+
+        // While testStats* are already initialized with addEntry, verify content added
+        // matches expectation.
+        for (i in expectedEntriesInStats2.indices) {
+            val entry = testStats2.getValues(i, null)
+            assertEquals(expectedEntriesInStats2[i], entry)
+        }
+
+        // Verify entry updated with addEntry.
+        val stats = testStats2.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12, -5, 7, 0, 9))
+        assertEquals(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+                METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16, -2, 9, 1, 9),
+                stats.getValues(3, null))
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.Q)
+    fun testAdd() {
+        var stats = NetworkStats(0L, 0)
+        assertNetworkStatsEquals(testStatsEmpty, stats)
+        stats = stats.add(testStats2)
+        assertNetworkStatsEquals(testStats2, stats)
+        stats = stats.add(testStats1)
+        // EMPTY + STATS2 + STATS1 = STATS3
+        assertNetworkStatsEquals(testStats3, stats)
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.Q)
+    fun testParcelUnparcel() {
+        assertParcelingIsLossless(testStatsEmpty)
+        assertParcelingIsLossless(testStats1)
+        assertParcelingIsLossless(testStats2)
+        assertFieldCountEquals(15, NetworkStats::class.java)
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.Q)
+    fun testDescribeContents() {
+        assertEquals(0, testStatsEmpty.describeContents())
+        assertEquals(0, testStats1.describeContents())
+        assertEquals(0, testStats2.describeContents())
+        assertEquals(0, testStats3.describeContents())
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.Q)
+    fun testSubtract() {
+        // STATS3 - STATS2 = STATS1
+        assertNetworkStatsEquals(testStats1, testStats3.subtract(testStats2))
+        // STATS3 - STATS1 = STATS2
+        assertNetworkStatsEquals(testStats2, testStats3.subtract(testStats1))
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.Q)
+    fun testMethodsDontModifyReceiver() {
+        listOf(testStatsEmpty, testStats1, testStats2, testStats3).forEach {
+            val origStats = it.clone()
+            it.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
+            it.add(testStats3)
+            it.subtract(testStats1)
+            assertNetworkStatsEquals(origStats, it)
+        }
+    }
+}
\ No newline at end of file