[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
This commit is contained in:
Evan Laird
2023-04-12 11:01:33 -04:00
parent 66c3f03673
commit d4c120389b
13 changed files with 430 additions and 21 deletions

View File

@@ -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)
}
}

View File

@@ -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].
*

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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")
}
}

View File

@@ -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 ----

View File

@@ -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() {

View File

@@ -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()

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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(

View File

@@ -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())
}
}