Merge "Add test for benchmarking NetworkStatsRecorder" into main

This commit is contained in:
Junyu Lai
2023-07-26 07:43:14 +00:00
committed by Gerrit Code Review
3 changed files with 143 additions and 87 deletions

View File

@@ -31,6 +31,7 @@ android_test {
],
static_libs: [
"androidx.test.rules",
"mockito-target-minus-junit4",
"net-tests-utils",
"service-connectivity-pre-jarjar",
"service-connectivity-tiramisu-pre-jarjar",

View File

@@ -1,87 +0,0 @@
/*
* Copyright (C) 2023 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 com.android.server.net.benchmarktests
import android.net.NetworkStatsCollection
import androidx.test.InstrumentationRegistry
import com.android.internal.util.FileRotator.Reader
import com.android.server.connectivity.benchmarktests.R
import java.io.BufferedInputStream
import java.io.DataInputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.file.Files
import java.util.concurrent.TimeUnit
import java.util.zip.ZipInputStream
import kotlin.test.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
class NetworkStatsCollectionTest {
private val DEFAULT_BUFFER_SIZE = 8192
private val UID_COLLECTION_BUCKET_DURATION_MS = TimeUnit.HOURS.toMillis(2)
private val uidTestFiles: List<File> by lazy {
// These file generated by using real user dataset which has many uid records and agreed to
// share the dataset for testing purpose. These dataset can be extracted from rooted
// devices by using "adb pull /data/misc/apexdata/com.android.tethering/netstats" command.
val zipInputStream = ZipInputStream(getInputStreamForResource(R.raw.netstats_many_uids_zip))
getSortedListForPrefix(unzipToTempDir(zipInputStream), "uid")
}
@Test
fun testReadCollection_manyUids() {
val collection = NetworkStatsCollection(UID_COLLECTION_BUCKET_DURATION_MS)
for (file in uidTestFiles) {
readFile(file, collection)
}
}
private fun getInputStreamForResource(resourceId: Int): DataInputStream {
return DataInputStream(
InstrumentationRegistry.getContext()
.getResources().openRawResource(resourceId)
)
}
private fun unzipToTempDir(zis: ZipInputStream): File {
val statsDir =
Files.createTempDirectory(NetworkStatsCollectionTest::class.simpleName).toFile()
while (true) {
val entryName = zis.nextEntry?.name ?: break
val file = File(statsDir, entryName)
FileOutputStream(file).use { zis.copyTo(it, DEFAULT_BUFFER_SIZE) }
}
return statsDir
}
// List [xt|uid|uid_tag].<start>-<end> files under the given directory.
private fun getSortedListForPrefix(statsDir: File, prefix: String): List<File> {
assertTrue(statsDir.exists())
return (statsDir.list() ?: arrayOf()).mapNotNull {
if (it.startsWith("$prefix.")) File(statsDir, it) else null
}.sorted()
}
private fun readFile(file: File, reader: Reader) =
BufferedInputStream(FileInputStream(file)).use {
reader.read(it)
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2023 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 com.android.server.net.benchmarktests
import android.net.NetworkStats.NonMonotonicObserver
import android.net.NetworkStatsCollection
import android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID
import android.os.DropBoxManager
import androidx.test.InstrumentationRegistry
import com.android.internal.util.FileRotator
import com.android.internal.util.FileRotator.Reader
import com.android.server.connectivity.benchmarktests.R
import com.android.server.net.NetworkStatsRecorder
import java.io.BufferedInputStream
import java.io.DataInputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.file.Files
import java.util.concurrent.TimeUnit
import java.util.zip.ZipInputStream
import kotlin.test.assertTrue
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mockito.mock
@RunWith(JUnit4::class)
class NetworkStatsTest {
companion object {
private val DEFAULT_BUFFER_SIZE = 8192
private val UID_COLLECTION_BUCKET_DURATION_MS = TimeUnit.HOURS.toMillis(2)
private val UID_RECORDER_ROTATE_AGE_MS = TimeUnit.DAYS.toMillis(15)
private val UID_RECORDER_DELETE_AGE_MS = TimeUnit.DAYS.toMillis(90)
private val testFilesDir by lazy {
// These file generated by using real user dataset which has many uid records
// and agreed to share the dataset for testing purpose. These dataset can be
// extracted from rooted devices by using
// "adb pull /data/misc/apexdata/com.android.tethering/netstats" command.
val zipInputStream =
ZipInputStream(getInputStreamForResource(R.raw.netstats_many_uids_zip))
unzipToTempDir(zipInputStream)
}
private val uidTestFiles: List<File> by lazy {
getSortedListForPrefix(testFilesDir, "uid")
}
// Test results shows the test cases who read the file first will take longer time to
// execute, and reading time getting shorter each time. Read files several times prior to
// tests to minimize the impact. This cannot live in setUp() since the time
// spent on the file reading will be attributed to the time spent on the individual
// test case.
@JvmStatic
@BeforeClass
fun setUpOnce() {
for (i in 1..10) {
val collection = NetworkStatsCollection(UID_COLLECTION_BUCKET_DURATION_MS)
for (file in uidTestFiles) {
readFile(file, collection)
}
}
}
private fun getInputStreamForResource(resourceId: Int): DataInputStream {
return DataInputStream(
InstrumentationRegistry.getContext()
.getResources().openRawResource(resourceId)
)
}
private fun unzipToTempDir(zis: ZipInputStream): File {
val statsDir =
Files.createTempDirectory(NetworkStatsTest::class.simpleName).toFile()
while (true) {
val entryName = zis.nextEntry?.name ?: break
val file = File(statsDir, entryName)
FileOutputStream(file).use { zis.copyTo(it, DEFAULT_BUFFER_SIZE) }
}
return statsDir
}
// List [xt|uid|uid_tag].<start>-<end> files under the given directory.
private fun getSortedListForPrefix(statsDir: File, prefix: String): List<File> {
assertTrue(statsDir.exists())
return (statsDir.list() ?: arrayOf()).mapNotNull {
if (it.startsWith("$prefix.")) File(statsDir, it) else null
}.sorted()
}
private fun readFile(file: File, reader: Reader) =
BufferedInputStream(FileInputStream(file)).use {
reader.read(it)
}
}
@Test
fun testReadCollection_manyUids() {
for (i in 1..10) {
val collection = NetworkStatsCollection(UID_COLLECTION_BUCKET_DURATION_MS)
for (file in uidTestFiles) {
readFile(file, collection)
}
}
}
@Test
fun testReadFromRecorder_manyUids() {
for (i in 1..10) {
val recorder = NetworkStatsRecorder(
FileRotator(
testFilesDir, PREFIX_UID, UID_RECORDER_ROTATE_AGE_MS, UID_RECORDER_DELETE_AGE_MS
),
mock<NonMonotonicObserver<String>>(),
mock(DropBoxManager::class.java),
PREFIX_UID,
UID_COLLECTION_BUCKET_DURATION_MS,
false /* includeTags */,
false /* wipeOnError */
)
recorder.orLoadCompleteLocked
}
}
inline fun <reified T : Any> mock(): T = mock(T::class.java)
}