Merge "[Sb refactor] Add local logcat echoing to TableLogBuffer" into udc-dev
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.systemui.log.table
|
||||
|
||||
import android.util.Log
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Dagger-friendly interface so we can inject a fake [android.util.Log] in tests */
|
||||
interface LogProxy {
|
||||
/** verbose log */
|
||||
fun v(tag: String, message: String)
|
||||
|
||||
/** debug log */
|
||||
fun d(tag: String, message: String)
|
||||
|
||||
/** info log */
|
||||
fun i(tag: String, message: String)
|
||||
|
||||
/** warning log */
|
||||
fun w(tag: String, message: String)
|
||||
|
||||
/** error log */
|
||||
fun e(tag: String, message: String)
|
||||
|
||||
/** wtf log */
|
||||
fun wtf(tag: String, message: String)
|
||||
}
|
||||
|
||||
class LogProxyDefault @Inject constructor() : LogProxy {
|
||||
override fun v(tag: String, message: String) {
|
||||
Log.v(tag, message)
|
||||
}
|
||||
|
||||
override fun d(tag: String, message: String) {
|
||||
Log.d(tag, message)
|
||||
}
|
||||
|
||||
override fun i(tag: String, message: String) {
|
||||
Log.i(tag, message)
|
||||
}
|
||||
|
||||
override fun w(tag: String, message: String) {
|
||||
Log.w(tag, message)
|
||||
}
|
||||
|
||||
override fun e(tag: String, message: String) {
|
||||
Log.e(tag, message)
|
||||
}
|
||||
|
||||
override fun wtf(tag: String, message: String) {
|
||||
Log.wtf(tag, message)
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,17 @@ package com.android.systemui.log.table
|
||||
import android.os.Trace
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.common.buffer.RingBuffer
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.plugins.log.LogLevel
|
||||
import com.android.systemui.plugins.log.LogcatEchoTracker
|
||||
import com.android.systemui.util.time.SystemClock
|
||||
import java.io.PrintWriter
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* A logger that logs changes in table format.
|
||||
@@ -73,12 +80,18 @@ class TableLogBuffer(
|
||||
maxSize: Int,
|
||||
private val name: String,
|
||||
private val systemClock: SystemClock,
|
||||
private val logcatEchoTracker: LogcatEchoTracker,
|
||||
@Background private val bgDispatcher: CoroutineDispatcher,
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val localLogcat: LogProxy = LogProxyDefault(),
|
||||
) : Dumpable {
|
||||
init {
|
||||
if (maxSize <= 0) {
|
||||
throw IllegalArgumentException("maxSize must be > 0")
|
||||
}
|
||||
}
|
||||
// For local logcat, send messages across this channel so the background job can process them
|
||||
private val logMessageChannel = Channel<TableChange>(capacity = 10)
|
||||
|
||||
private val buffer = RingBuffer(maxSize) { TableChange() }
|
||||
|
||||
@@ -105,6 +118,16 @@ class TableLogBuffer(
|
||||
tableLogBuffer = this,
|
||||
)
|
||||
|
||||
/** Start this log buffer logging in the background */
|
||||
internal fun init() {
|
||||
coroutineScope.launch(bgDispatcher) {
|
||||
while (!logMessageChannel.isClosedForReceive) {
|
||||
val log = logMessageChannel.receive()
|
||||
echoToDesiredEndpoints(log)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the differences between [prevVal] and [newVal].
|
||||
*
|
||||
@@ -189,6 +212,7 @@ class TableLogBuffer(
|
||||
Trace.beginSection("TableLogBuffer#logChange(string)")
|
||||
val change = obtain(timestamp, prefix, columnName, isInitial)
|
||||
change.set(value)
|
||||
tryAddMessage(change)
|
||||
Trace.endSection()
|
||||
}
|
||||
|
||||
@@ -202,6 +226,7 @@ class TableLogBuffer(
|
||||
Trace.beginSection("TableLogBuffer#logChange(boolean)")
|
||||
val change = obtain(timestamp, prefix, columnName, isInitial)
|
||||
change.set(value)
|
||||
tryAddMessage(change)
|
||||
Trace.endSection()
|
||||
}
|
||||
|
||||
@@ -215,9 +240,14 @@ class TableLogBuffer(
|
||||
Trace.beginSection("TableLogBuffer#logChange(int)")
|
||||
val change = obtain(timestamp, prefix, columnName, isInitial)
|
||||
change.set(value)
|
||||
tryAddMessage(change)
|
||||
Trace.endSection()
|
||||
}
|
||||
|
||||
private fun tryAddMessage(change: TableChange) {
|
||||
logMessageChannel.trySend(change)
|
||||
}
|
||||
|
||||
// TODO(b/259454430): Add additional change types here.
|
||||
|
||||
@Synchronized
|
||||
@@ -258,6 +288,17 @@ class TableLogBuffer(
|
||||
Trace.endSection()
|
||||
}
|
||||
|
||||
private fun echoToDesiredEndpoints(change: TableChange) {
|
||||
if (
|
||||
logcatEchoTracker.isBufferLoggable(bufferName = name, LogLevel.DEBUG) ||
|
||||
logcatEchoTracker.isTagLoggable(change.columnName, LogLevel.DEBUG)
|
||||
) {
|
||||
if (change.hasData()) {
|
||||
localLogcat.d(name, change.logcatRepresentation())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
pw.println(HEADER_PREFIX + name)
|
||||
@@ -284,6 +325,12 @@ class TableLogBuffer(
|
||||
pw.println()
|
||||
}
|
||||
|
||||
/** Transforms an individual [TableChange] into a String for logcat */
|
||||
private fun TableChange.logcatRepresentation(): String {
|
||||
val formattedTimestamp = TABLE_LOG_DATE_FORMAT.format(timestamp)
|
||||
return "$formattedTimestamp$SEPARATOR${getName()}$SEPARATOR${getVal()}"
|
||||
}
|
||||
|
||||
/**
|
||||
* A private implementation of [TableRowLogger].
|
||||
*
|
||||
|
||||
@@ -17,10 +17,15 @@
|
||||
package com.android.systemui.log.table
|
||||
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.log.LogBufferHelper.Companion.adjustMaxSize
|
||||
import com.android.systemui.plugins.log.LogcatEchoTracker
|
||||
import com.android.systemui.util.time.SystemClock
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
@SysUISingleton
|
||||
class TableLogBufferFactory
|
||||
@@ -28,6 +33,9 @@ class TableLogBufferFactory
|
||||
constructor(
|
||||
private val dumpManager: DumpManager,
|
||||
private val systemClock: SystemClock,
|
||||
private val logcatEchoTracker: LogcatEchoTracker,
|
||||
@Background private val bgDispatcher: CoroutineDispatcher,
|
||||
@Application private val coroutineScope: CoroutineScope,
|
||||
) {
|
||||
private val existingBuffers = mutableMapOf<String, TableLogBuffer>()
|
||||
|
||||
@@ -44,8 +52,17 @@ constructor(
|
||||
name: String,
|
||||
maxSize: Int,
|
||||
): TableLogBuffer {
|
||||
val tableBuffer = TableLogBuffer(adjustMaxSize(maxSize), name, systemClock)
|
||||
val tableBuffer =
|
||||
TableLogBuffer(
|
||||
adjustMaxSize(maxSize),
|
||||
name,
|
||||
systemClock,
|
||||
logcatEchoTracker,
|
||||
bgDispatcher,
|
||||
coroutineScope,
|
||||
)
|
||||
dumpManager.registerNormalDumpable(name, tableBuffer)
|
||||
tableBuffer.init()
|
||||
return tableBuffer
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import com.android.systemui.user.data.repository.FakeUserRepository
|
||||
import com.android.systemui.util.mockito.KotlinArgumentCaptor
|
||||
import com.android.systemui.util.mockito.captureMany
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.android.systemui.util.time.SystemClock
|
||||
@@ -193,8 +194,24 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
|
||||
bypassControllerOverride: KeyguardBypassController? = bypassController
|
||||
): DeviceEntryFaceAuthRepositoryImpl {
|
||||
val systemClock = FakeSystemClock()
|
||||
val faceAuthBuffer = TableLogBuffer(10, "face auth", systemClock)
|
||||
val faceDetectBuffer = TableLogBuffer(10, "face detect", systemClock)
|
||||
val faceAuthBuffer =
|
||||
TableLogBuffer(
|
||||
10,
|
||||
"face auth",
|
||||
systemClock,
|
||||
mock(),
|
||||
testDispatcher,
|
||||
testScope.backgroundScope
|
||||
)
|
||||
val faceDetectBuffer =
|
||||
TableLogBuffer(
|
||||
10,
|
||||
"face detect",
|
||||
systemClock,
|
||||
mock(),
|
||||
testDispatcher,
|
||||
testScope.backgroundScope
|
||||
)
|
||||
keyguardTransitionRepository = FakeKeyguardTransitionRepository()
|
||||
val keyguardTransitionInteractor =
|
||||
KeyguardTransitionInteractor(keyguardTransitionRepository)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.systemui.log.table
|
||||
|
||||
/**
|
||||
* Fake [LogProxy] that collects all lines sent to it. Mimics the ADB logcat format without the
|
||||
* timestamp. [FakeLogProxy.d] will write a log like so:
|
||||
* ```
|
||||
* logger.d("TAG", "message here")
|
||||
* // writes this to the [logs] field
|
||||
* "D TAG: message here"
|
||||
* ```
|
||||
*
|
||||
* Logs sent to this class are collected as a list of strings for simple test assertions.
|
||||
*/
|
||||
class FakeLogProxy : LogProxy {
|
||||
val logs: MutableList<String> = mutableListOf()
|
||||
|
||||
override fun v(tag: String, message: String) {
|
||||
logs.add("V $tag: $message")
|
||||
}
|
||||
|
||||
override fun d(tag: String, message: String) {
|
||||
logs.add("D $tag: $message")
|
||||
}
|
||||
|
||||
override fun i(tag: String, message: String) {
|
||||
logs.add("I $tag: $message")
|
||||
}
|
||||
|
||||
override fun w(tag: String, message: String) {
|
||||
logs.add("W $tag: $message")
|
||||
}
|
||||
|
||||
override fun e(tag: String, message: String) {
|
||||
logs.add("E $tag: $message")
|
||||
}
|
||||
|
||||
override fun wtf(tag: String, message: String) {
|
||||
logs.add("WTF $tag: $message")
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.log.table
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.io.PrintWriter
|
||||
@@ -39,7 +40,8 @@ import org.junit.Test
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class LogDiffsForTableTest : SysuiTestCase() {
|
||||
|
||||
private val testScope = TestScope(UnconfinedTestDispatcher())
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
private lateinit var systemClock: FakeSystemClock
|
||||
private lateinit var tableLogBuffer: TableLogBuffer
|
||||
@@ -47,7 +49,15 @@ class LogDiffsForTableTest : SysuiTestCase() {
|
||||
@Before
|
||||
fun setUp() {
|
||||
systemClock = FakeSystemClock()
|
||||
tableLogBuffer = TableLogBuffer(MAX_SIZE, BUFFER_NAME, systemClock)
|
||||
tableLogBuffer =
|
||||
TableLogBuffer(
|
||||
MAX_SIZE,
|
||||
BUFFER_NAME,
|
||||
systemClock,
|
||||
mock(),
|
||||
testDispatcher,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
}
|
||||
|
||||
// ---- Flow<Boolean> tests ----
|
||||
|
||||
@@ -22,13 +22,20 @@ import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import org.junit.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class TableLogBufferFactoryTest : SysuiTestCase() {
|
||||
private val dumpManager: DumpManager = mock()
|
||||
private val systemClock = FakeSystemClock()
|
||||
private val underTest = TableLogBufferFactory(dumpManager, systemClock)
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
private val underTest =
|
||||
TableLogBufferFactory(dumpManager, systemClock, mock(), testDispatcher, testScope)
|
||||
|
||||
@Test
|
||||
fun create_alwaysCreatesNewInstance() {
|
||||
|
||||
@@ -19,31 +19,66 @@ package com.android.systemui.log.table
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
|
||||
import com.android.systemui.plugins.log.LogLevel
|
||||
import com.android.systemui.plugins.log.LogcatEchoTracker
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class TableLogBufferTest : SysuiTestCase() {
|
||||
private lateinit var underTest: TableLogBuffer
|
||||
|
||||
private lateinit var systemClock: FakeSystemClock
|
||||
private lateinit var outputWriter: StringWriter
|
||||
private lateinit var logcatEchoTracker: LogcatEchoTracker
|
||||
private lateinit var localLogcat: FakeLogProxy
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
localLogcat = FakeLogProxy()
|
||||
logcatEchoTracker = mock()
|
||||
systemClock = FakeSystemClock()
|
||||
outputWriter = StringWriter()
|
||||
|
||||
underTest = TableLogBuffer(MAX_SIZE, NAME, systemClock)
|
||||
underTest =
|
||||
TableLogBuffer(
|
||||
MAX_SIZE,
|
||||
NAME,
|
||||
systemClock,
|
||||
logcatEchoTracker,
|
||||
testDispatcher,
|
||||
testScope.backgroundScope,
|
||||
localLogcat = localLogcat,
|
||||
)
|
||||
underTest.init()
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun maxSizeZero_throwsException() {
|
||||
TableLogBuffer(maxSize = 0, "name", systemClock)
|
||||
TableLogBuffer(
|
||||
maxSize = 0,
|
||||
"name",
|
||||
systemClock,
|
||||
logcatEchoTracker,
|
||||
testDispatcher,
|
||||
testScope.backgroundScope,
|
||||
localLogcat = localLogcat,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -791,6 +826,112 @@ class TableLogBufferTest : SysuiTestCase() {
|
||||
assertThat(dumpedString).contains(evictedColumnLog3)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logcat_bufferNotLoggable_tagNotLoggable_noEcho() {
|
||||
whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(false)
|
||||
whenever(logcatEchoTracker.isTagLoggable(eq("columnName"), any())).thenReturn(false)
|
||||
|
||||
underTest.logChange("prefix", "columnName", true)
|
||||
|
||||
assertThat(localLogcat.logs).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logcat_bufferIsLoggable_tagNotLoggable_echoes() {
|
||||
whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(true)
|
||||
whenever(logcatEchoTracker.isTagLoggable(eq("columnName"), any())).thenReturn(false)
|
||||
|
||||
underTest.logChange("prefix", "columnName", true)
|
||||
|
||||
assertThat(localLogcat.logs).hasSize(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logcat_bufferNotLoggable_tagIsLoggable_echoes() {
|
||||
whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(false)
|
||||
whenever(logcatEchoTracker.isTagLoggable(eq("columnName"), any())).thenReturn(true)
|
||||
|
||||
underTest.logChange("prefix", "columnName", true)
|
||||
|
||||
assertThat(localLogcat.logs).hasSize(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logcat_echoesDebugLogs_debugDisabled_noEcho() {
|
||||
// Allow any log other than debug
|
||||
whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenAnswer { invocation ->
|
||||
(invocation.getArgument(1) as LogLevel) != LogLevel.DEBUG
|
||||
}
|
||||
|
||||
underTest.logChange("prefix", "columnName", true)
|
||||
|
||||
assertThat(localLogcat.logs).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logcat_echoesDebugLogs_debugEnabled_echoes() {
|
||||
// Only allow debug logs
|
||||
whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), eq(LogLevel.DEBUG))).thenReturn(true)
|
||||
|
||||
underTest.logChange("prefix", "columnName", true)
|
||||
|
||||
assertThat(localLogcat.logs).hasSize(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logcat_bufferNotLoggable_tagIsLoggable_usesColNameForTagCheck() {
|
||||
systemClock.setCurrentTimeMillis(1000L)
|
||||
|
||||
val nonLoggingTag = "nonLoggingColName"
|
||||
val loggingTag = "loggingColName"
|
||||
|
||||
whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(false)
|
||||
whenever(logcatEchoTracker.isTagLoggable(eq(loggingTag), eq(LogLevel.DEBUG)))
|
||||
.thenReturn(true)
|
||||
whenever(logcatEchoTracker.isTagLoggable(eq(nonLoggingTag), eq(LogLevel.DEBUG)))
|
||||
.thenReturn(false)
|
||||
|
||||
underTest.logChange("", nonLoggingTag, true)
|
||||
underTest.logChange("", loggingTag, true)
|
||||
|
||||
assertThat(localLogcat.logs).hasSize(1)
|
||||
|
||||
val timestamp = TABLE_LOG_DATE_FORMAT.format(1000L)
|
||||
val expectedMessage = "${timestamp}${SEPARATOR}${loggingTag}${SEPARATOR}true"
|
||||
val expectedLine = "D $NAME: $expectedMessage"
|
||||
|
||||
assertThat(localLogcat.logs[0]).isEqualTo(expectedLine)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logcat_bufferLoggable_multipleMessagesAreEchoed() {
|
||||
systemClock.setCurrentTimeMillis(1000L)
|
||||
whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(true)
|
||||
|
||||
val col1 = "column1"
|
||||
val col2 = "column2"
|
||||
|
||||
// Log a couple of columns that flip bits
|
||||
underTest.logChange("", col1, true)
|
||||
underTest.logChange("", col2, false)
|
||||
underTest.logChange("", col1, false)
|
||||
underTest.logChange("", col2, true)
|
||||
|
||||
assertThat(localLogcat.logs).hasSize(4)
|
||||
|
||||
val timestamp = TABLE_LOG_DATE_FORMAT.format(1000L)
|
||||
val msg1 = "${timestamp}${SEPARATOR}${col1}${SEPARATOR}true"
|
||||
val msg2 = "${timestamp}${SEPARATOR}${col2}${SEPARATOR}false"
|
||||
val msg3 = "${timestamp}${SEPARATOR}${col1}${SEPARATOR}false"
|
||||
val msg4 = "${timestamp}${SEPARATOR}${col2}${SEPARATOR}true"
|
||||
val expected = listOf(msg1, msg2, msg3, msg4).map { "D $NAME: $it" }
|
||||
|
||||
// Logs use the same bg dispatcher for writing to logcat, they should be in order
|
||||
for ((msg, logLine) in expected zip localLogcat.logs) {
|
||||
assertThat(logLine).isEqualTo(msg)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dumpChanges(): String {
|
||||
underTest.dump(PrintWriter(outputWriter), arrayOf())
|
||||
return outputWriter.toString()
|
||||
|
||||
@@ -53,6 +53,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -92,13 +93,15 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
||||
private val mobileMappings = FakeMobileMappingsProxy()
|
||||
private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val scope = CoroutineScope(IMMEDIATE)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
logFactory = TableLogBufferFactory(dumpManager, FakeSystemClock())
|
||||
logFactory =
|
||||
TableLogBufferFactory(dumpManager, FakeSystemClock(), mock(), testDispatcher, scope)
|
||||
|
||||
// Never start in demo mode
|
||||
whenever(demoModeController.isInDemoMode).thenReturn(false)
|
||||
|
||||
@@ -61,11 +61,18 @@ import org.junit.runners.Parameterized.Parameters
|
||||
internal class DemoMobileConnectionParameterizedTest(private val testCase: TestCase) :
|
||||
SysuiTestCase() {
|
||||
|
||||
private val logFactory = TableLogBufferFactory(mock(), FakeSystemClock())
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
private val logFactory =
|
||||
TableLogBufferFactory(
|
||||
mock(),
|
||||
FakeSystemClock(),
|
||||
mock(),
|
||||
testDispatcher,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
|
||||
private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
|
||||
private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
|
||||
|
||||
|
||||
@@ -54,13 +54,20 @@ import org.junit.Test
|
||||
@SmallTest
|
||||
class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
||||
private val dumpManager: DumpManager = mock()
|
||||
private val logFactory = TableLogBufferFactory(dumpManager, FakeSystemClock())
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
|
||||
private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
|
||||
private val logFactory =
|
||||
TableLogBufferFactory(
|
||||
dumpManager,
|
||||
FakeSystemClock(),
|
||||
mock(),
|
||||
testDispatcher,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
|
||||
private lateinit var underTest: DemoMobileConnectionsRepository
|
||||
private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource
|
||||
|
||||
@@ -66,7 +66,15 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
||||
private val systemClock = FakeSystemClock()
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
private val tableLogBuffer = TableLogBuffer(maxSize = 100, name = "TestName", systemClock)
|
||||
private val tableLogBuffer =
|
||||
TableLogBuffer(
|
||||
maxSize = 100,
|
||||
name = "TestName",
|
||||
systemClock,
|
||||
mock(),
|
||||
testDispatcher,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
|
||||
private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
|
||||
|
||||
@@ -294,7 +302,14 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun factory_reusesLogBuffersForSameConnection() =
|
||||
testScope.runTest {
|
||||
val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
|
||||
val realLoggerFactory =
|
||||
TableLogBufferFactory(
|
||||
mock(),
|
||||
FakeSystemClock(),
|
||||
mock(),
|
||||
testDispatcher,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
|
||||
val factory =
|
||||
FullMobileConnectionRepository.Factory(
|
||||
@@ -329,7 +344,14 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun factory_reusesLogBuffersForSameSubIDevenIfCarrierMerged() =
|
||||
testScope.runTest {
|
||||
val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
|
||||
val realLoggerFactory =
|
||||
TableLogBufferFactory(
|
||||
mock(),
|
||||
FakeSystemClock(),
|
||||
mock(),
|
||||
testDispatcher,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
|
||||
val factory =
|
||||
FullMobileConnectionRepository.Factory(
|
||||
|
||||
@@ -61,6 +61,16 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
private val tableLogBuffer =
|
||||
TableLogBuffer(
|
||||
8,
|
||||
"MobileIconsInteractorTest",
|
||||
FakeSystemClock(),
|
||||
mock(),
|
||||
testDispatcher,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
|
||||
@Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
|
||||
|
||||
@Before
|
||||
@@ -687,16 +697,14 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val tableLogBuffer =
|
||||
TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock())
|
||||
|
||||
private const val SUB_1_ID = 1
|
||||
private val SUB_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
|
||||
private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer)
|
||||
private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, mock())
|
||||
|
||||
private const val SUB_2_ID = 2
|
||||
private val SUB_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
|
||||
private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, tableLogBuffer)
|
||||
private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, mock())
|
||||
|
||||
private const val SUB_3_ID = 3
|
||||
private val SUB_3_OPP =
|
||||
@@ -705,7 +713,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
||||
isOpportunistic = true,
|
||||
groupUuid = ParcelUuid(UUID.randomUUID()),
|
||||
)
|
||||
private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, tableLogBuffer)
|
||||
private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, mock())
|
||||
|
||||
private const val SUB_4_ID = 4
|
||||
private val SUB_4_OPP =
|
||||
@@ -714,6 +722,6 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
||||
isOpportunistic = true,
|
||||
groupUuid = ParcelUuid(UUID.randomUUID()),
|
||||
)
|
||||
private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, tableLogBuffer)
|
||||
private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, mock())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user