From d4c120389b86cb15836617e8fa3ee49a5b326561 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Wed, 12 Apr 2023 11:01:33 -0400 Subject: [Sb refactor] Add local logcat echoing to TableLogBuffer TableLogBuffer is a sibling of LogBuffer, so it needs to reimplement the desirable behaviors of Logbuffer. In this CL, we're adding support for local logcat echoing on every table. The logging happens only in the background and can fail silently so that it never blocks the main thread. This implementation differs from the LogBuffer implementation which was written before the coroutines library was available, so it doesn't use a background thread-per-table like the LogBuffer implementation does. Rather, this implementation uses a Channel + a background CoroutineDispatcher to execute all logging in the background. We do leverage the existing LogcatEchoTracker class, which implements a generic settings listener + settings format for turning logcat echoing on at the buffer or tag level. In our case, the buffer name is the name of the table, and the tags are the column names. Note that all TableLogBuffer logs are considered to be `LogLevel.DEBUG` since the API for `logChange` does not let the caller decide on a log level. Arguably this makes perfect sense since table logs are _not_ meant to be warning or error logs. We could probably make the case that they are `info` or `verbose`, but that would be immaterial to this overall change. Test: existing tests in tests/src/com/android/systemui/statusbar/pipelinestyle Test: TableLogBufferTest Test: manual Bug: 255951648 Change-Id: I930e4c7730117860ab22e8849c84f1f96f786b30 --- .../src/com/android/systemui/log/table/LogProxy.kt | 67 ++++++++++ .../android/systemui/log/table/TableLogBuffer.kt | 47 +++++++ .../systemui/log/table/TableLogBufferFactory.kt | 19 ++- .../DeviceEntryFaceAuthRepositoryTest.kt | 21 ++- .../com/android/systemui/log/table/FakeLogProxy.kt | 56 ++++++++ .../systemui/log/table/LogDiffsForTableTest.kt | 14 +- .../log/table/TableLogBufferFactoryTest.kt | 9 +- .../systemui/log/table/TableLogBufferTest.kt | 145 ++++++++++++++++++++- .../repository/MobileRepositorySwitcherTest.kt | 5 +- .../demo/DemoMobileConnectionParameterizedTest.kt | 11 +- .../demo/DemoMobileConnectionsRepositoryTest.kt | 9 +- .../prod/FullMobileConnectionRepositoryTest.kt | 28 +++- .../domain/interactor/MobileIconsInteractorTest.kt | 20 ++- 13 files changed, 430 insertions(+), 21 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/log/table/LogProxy.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt diff --git a/packages/SystemUI/src/com/android/systemui/log/table/LogProxy.kt b/packages/SystemUI/src/com/android/systemui/log/table/LogProxy.kt new file mode 100644 index 000000000000..53886aabfa72 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/table/LogProxy.kt @@ -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) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt index faaa205b15c2..9d883cc10d6c 100644 --- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt +++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt @@ -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(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) { 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]. * diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt index 06668d33408d..42e742db2842 100644 --- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt @@ -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() @@ -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 } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index fa40fc431b5f..83e357665126 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -65,6 +65,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 @@ -191,8 +192,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) diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt new file mode 100644 index 000000000000..471c4615ef0a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt @@ -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 = 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") + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt index c49337a53970..1d182cfec49c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt @@ -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 tests ---- diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt index af83a560d7d0..8ba76437c725 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt @@ -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() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt index aed830ae0d53..a2b2322899b7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt @@ -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() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt index 3ec96908dac8..bde05b9f499e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt @@ -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) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt index 37fac3458c83..7573b28c8a7f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt @@ -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(null) private val fakeWifiEventFlow = MutableStateFlow(null) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt index 1251dfacddfc..efaf15235b46 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt @@ -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(null) private val fakeWifiEventFlow = MutableStateFlow(null) + private val logFactory = + TableLogBufferFactory( + dumpManager, + FakeSystemClock(), + mock(), + testDispatcher, + testScope.backgroundScope, + ) private lateinit var underTest: DemoMobileConnectionsRepository private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt index 9f77744e1fec..b701fbd66937 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt @@ -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() private val carrierMergedFactory = mock() @@ -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( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index c84c9c032225..6e1ab58db56d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -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()) } } -- cgit v1.2.3-59-g8ed1b