Merge pull request #5132 from element-hq/feature/bma/rageshakeConfig
Let enterprise build store the logs in a dedicated subfolder
This commit is contained in:
commit
04f3f4cb53
13 changed files with 325 additions and 75 deletions
|
|
@ -10,11 +10,10 @@ package io.element.android.x.initializer
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.system.Os
|
import android.system.Os
|
||||||
import androidx.startup.Initializer
|
import androidx.startup.Initializer
|
||||||
import io.element.android.features.rageshake.api.reporter.BugReporter
|
import io.element.android.features.rageshake.api.logs.createWriteToFilesConfiguration
|
||||||
import io.element.android.libraries.architecture.bindings
|
import io.element.android.libraries.architecture.bindings
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||||
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
|
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
|
||||||
import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration
|
|
||||||
import io.element.android.x.di.AppBindings
|
import io.element.android.x.di.AppBindings
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
@ -34,7 +33,7 @@ class PlatformInitializer : Initializer<Unit> {
|
||||||
val logLevel = runBlocking { preferencesStore.getTracingLogLevelFlow().first() }
|
val logLevel = runBlocking { preferencesStore.getTracingLogLevelFlow().first() }
|
||||||
val tracingConfiguration = TracingConfiguration(
|
val tracingConfiguration = TracingConfiguration(
|
||||||
writesToLogcat = runBlocking { featureFlagService.isFeatureEnabled(FeatureFlags.PrintLogsToLogcat) },
|
writesToLogcat = runBlocking { featureFlagService.isFeatureEnabled(FeatureFlags.PrintLogsToLogcat) },
|
||||||
writesToFilesConfiguration = defaultWriteToDiskConfiguration(bugReporter),
|
writesToFilesConfiguration = bugReporter.createWriteToFilesConfiguration(),
|
||||||
logLevel = logLevel,
|
logLevel = logLevel,
|
||||||
extraTargets = listOf(ELEMENT_X_TARGET),
|
extraTargets = listOf(ELEMENT_X_TARGET),
|
||||||
traceLogPacks = runBlocking { preferencesStore.getTracingLogPacksFlow().first() },
|
traceLogPacks = runBlocking { preferencesStore.getTracingLogPacksFlow().first() },
|
||||||
|
|
@ -45,14 +44,5 @@ class PlatformInitializer : Initializer<Unit> {
|
||||||
Os.setenv("RUST_BACKTRACE", "1", true)
|
Os.setenv("RUST_BACKTRACE", "1", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun defaultWriteToDiskConfiguration(bugReporter: BugReporter): WriteToFilesConfiguration.Enabled {
|
|
||||||
return WriteToFilesConfiguration.Enabled(
|
|
||||||
directory = bugReporter.logDirectory().absolutePath,
|
|
||||||
filenamePrefix = "logs",
|
|
||||||
// Keep a maximum of 1 week of log files.
|
|
||||||
numberOfFiles = 7 * 24,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dependencies(): List<Class<out Initializer<*>>> = mutableListOf()
|
override fun dependencies(): List<Class<out Initializer<*>>> = mutableListOf()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import io.element.android.appnav.root.RootView
|
||||||
import io.element.android.features.enterprise.api.EnterpriseService
|
import io.element.android.features.enterprise.api.EnterpriseService
|
||||||
import io.element.android.features.login.api.LoginParams
|
import io.element.android.features.login.api.LoginParams
|
||||||
import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint
|
import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint
|
||||||
|
import io.element.android.features.rageshake.api.reporter.BugReporter
|
||||||
import io.element.android.features.signedout.api.SignedOutEntryPoint
|
import io.element.android.features.signedout.api.SignedOutEntryPoint
|
||||||
import io.element.android.features.viewfolder.api.ViewFolderEntryPoint
|
import io.element.android.features.viewfolder.api.ViewFolderEntryPoint
|
||||||
import io.element.android.libraries.architecture.BackstackView
|
import io.element.android.libraries.architecture.BackstackView
|
||||||
|
|
@ -73,6 +74,7 @@ class RootFlowNode @AssistedInject constructor(
|
||||||
private val signedOutEntryPoint: SignedOutEntryPoint,
|
private val signedOutEntryPoint: SignedOutEntryPoint,
|
||||||
private val intentResolver: IntentResolver,
|
private val intentResolver: IntentResolver,
|
||||||
private val oidcActionFlow: OidcActionFlow,
|
private val oidcActionFlow: OidcActionFlow,
|
||||||
|
private val bugReporter: BugReporter,
|
||||||
) : BaseFlowNode<RootFlowNode.NavTarget>(
|
) : BaseFlowNode<RootFlowNode.NavTarget>(
|
||||||
backstack = BackStack(
|
backstack = BackStack(
|
||||||
initialElement = NavTarget.SplashScreen,
|
initialElement = NavTarget.SplashScreen,
|
||||||
|
|
@ -123,6 +125,7 @@ class RootFlowNode @AssistedInject constructor(
|
||||||
|
|
||||||
private fun switchToNotLoggedInFlow(params: LoginParams?) {
|
private fun switchToNotLoggedInFlow(params: LoginParams?) {
|
||||||
matrixSessionCache.removeAll()
|
matrixSessionCache.removeAll()
|
||||||
|
bugReporter.setLogDirectorySubfolder(null)
|
||||||
backstack.safeRoot(NavTarget.NotLoggedInFlow(params))
|
backstack.safeRoot(NavTarget.NotLoggedInFlow(params))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,7 @@ class MatrixSessionCache @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
authenticationService.listenToNewMatrixClients { matrixClient ->
|
authenticationService.listenToNewMatrixClients { matrixClient ->
|
||||||
val syncOrchestrator = syncOrchestratorFactory.create(matrixClient)
|
onNewMatrixClient(matrixClient)
|
||||||
sessionIdsToMatrixSession[matrixClient.sessionId] = InMemoryMatrixSession(
|
|
||||||
matrixClient = matrixClient,
|
|
||||||
syncOrchestrator = syncOrchestrator,
|
|
||||||
)
|
|
||||||
syncOrchestrator.start()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,17 +100,21 @@ class MatrixSessionCache @Inject constructor(
|
||||||
Timber.d("Restore matrix session: $sessionId")
|
Timber.d("Restore matrix session: $sessionId")
|
||||||
return authenticationService.restoreSession(sessionId)
|
return authenticationService.restoreSession(sessionId)
|
||||||
.onSuccess { matrixClient ->
|
.onSuccess { matrixClient ->
|
||||||
val syncOrchestrator = syncOrchestratorFactory.create(matrixClient)
|
onNewMatrixClient(matrixClient)
|
||||||
sessionIdsToMatrixSession[matrixClient.sessionId] = InMemoryMatrixSession(
|
|
||||||
matrixClient = matrixClient,
|
|
||||||
syncOrchestrator = syncOrchestrator,
|
|
||||||
)
|
|
||||||
syncOrchestrator.start()
|
|
||||||
}
|
}
|
||||||
.onFailure {
|
.onFailure {
|
||||||
Timber.e(it, "Fail to restore session")
|
Timber.e(it, "Fail to restore session")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onNewMatrixClient(matrixClient: MatrixClient) {
|
||||||
|
val syncOrchestrator = syncOrchestratorFactory.create(matrixClient)
|
||||||
|
sessionIdsToMatrixSession[matrixClient.sessionId] = InMemoryMatrixSession(
|
||||||
|
matrixClient = matrixClient,
|
||||||
|
syncOrchestrator = syncOrchestrator,
|
||||||
|
)
|
||||||
|
syncOrchestrator.start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class InMemoryMatrixSession(
|
private data class InMemoryMatrixSession(
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,6 @@ dependencies {
|
||||||
implementation(projects.libraries.architecture)
|
implementation(projects.libraries.architecture)
|
||||||
implementation(projects.libraries.designsystem)
|
implementation(projects.libraries.designsystem)
|
||||||
implementation(projects.libraries.androidutils)
|
implementation(projects.libraries.androidutils)
|
||||||
|
implementation(projects.libraries.matrix.api)
|
||||||
implementation(projects.libraries.uiStrings)
|
implementation(projects.libraries.uiStrings)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.rageshake.api.logs
|
||||||
|
|
||||||
|
import io.element.android.features.rageshake.api.reporter.BugReporter
|
||||||
|
import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration
|
||||||
|
|
||||||
|
fun BugReporter.createWriteToFilesConfiguration(): WriteToFilesConfiguration {
|
||||||
|
return WriteToFilesConfiguration.Enabled(
|
||||||
|
directory = logDirectory().absolutePath,
|
||||||
|
filenamePrefix = "logs",
|
||||||
|
// Keep a maximum of 1 week of log files.
|
||||||
|
numberOfFiles = 7 * 24,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -34,6 +34,14 @@ interface BugReporter {
|
||||||
*/
|
*/
|
||||||
fun logDirectory(): File
|
fun logDirectory(): File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the subfolder name for the log directory.
|
||||||
|
* This will create a subfolder in the log directory with the given name.
|
||||||
|
* It will also configure the Rust SDK to use this subfolder for its logs.
|
||||||
|
* If the name is null, the log files will be stored in the base folder for the logs.
|
||||||
|
*/
|
||||||
|
fun setLogDirectorySubfolder(subfolderName: String?)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the current tracing log level.
|
* Set the current tracing log level.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import androidx.core.net.toFile
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.squareup.anvil.annotations.ContributesBinding
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
import io.element.android.appconfig.RageshakeConfig
|
import io.element.android.appconfig.RageshakeConfig
|
||||||
|
import io.element.android.features.rageshake.api.logs.createWriteToFilesConfiguration
|
||||||
import io.element.android.features.rageshake.api.reporter.BugReporter
|
import io.element.android.features.rageshake.api.reporter.BugReporter
|
||||||
import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
||||||
import io.element.android.features.rageshake.impl.crash.CrashDataStore
|
import io.element.android.features.rageshake.impl.crash.CrashDataStore
|
||||||
|
|
@ -28,11 +29,14 @@ import io.element.android.libraries.di.ApplicationContext
|
||||||
import io.element.android.libraries.di.SingleIn
|
import io.element.android.libraries.di.SingleIn
|
||||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||||
import io.element.android.libraries.matrix.api.SdkMetadata
|
import io.element.android.libraries.matrix.api.SdkMetadata
|
||||||
|
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
import io.element.android.libraries.matrix.api.tracing.TracingService
|
||||||
import io.element.android.libraries.network.useragent.UserAgentProvider
|
import io.element.android.libraries.network.useragent.UserAgentProvider
|
||||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
|
@ -71,6 +75,8 @@ class DefaultBugReporter @Inject constructor(
|
||||||
private val bugReporterUrlProvider: BugReporterUrlProvider,
|
private val bugReporterUrlProvider: BugReporterUrlProvider,
|
||||||
private val sdkMetadata: SdkMetadata,
|
private val sdkMetadata: SdkMetadata,
|
||||||
private val matrixClientProvider: MatrixClientProvider,
|
private val matrixClientProvider: MatrixClientProvider,
|
||||||
|
private val tracingService: TracingService,
|
||||||
|
matrixAuthenticationService: MatrixAuthenticationService,
|
||||||
) : BugReporter {
|
) : BugReporter {
|
||||||
companion object {
|
companion object {
|
||||||
// filenames
|
// filenames
|
||||||
|
|
@ -81,7 +87,24 @@ class DefaultBugReporter @Inject constructor(
|
||||||
private val logcatCommandDebug = arrayOf("logcat", "-d", "-v", "threadtime", "*:*")
|
private val logcatCommandDebug = arrayOf("logcat", "-d", "-v", "threadtime", "*:*")
|
||||||
private var currentTracingLogLevel: String? = null
|
private var currentTracingLogLevel: String? = null
|
||||||
|
|
||||||
private val logCatErrFile = File(logDirectory().absolutePath, LOG_CAT_FILENAME)
|
private val logCatErrFile: File
|
||||||
|
get() = File(logDirectory(), LOG_CAT_FILENAME)
|
||||||
|
private val baseLogDirectory = File(context.cacheDir, LOG_DIRECTORY_NAME)
|
||||||
|
private var currentLogDirectory: File = baseLogDirectory
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (buildMeta.isEnterpriseBuild) {
|
||||||
|
val logSubfolder = runBlocking {
|
||||||
|
sessionStore.getLatestSession()
|
||||||
|
}?.userId?.substringAfter(":")
|
||||||
|
setCurrentLogDirectory(logSubfolder)
|
||||||
|
matrixAuthenticationService.listenToNewMatrixClients {
|
||||||
|
// When a new Matrix client is created, we update the tracing configuration to write
|
||||||
|
// the files in a dedicated subfolders.
|
||||||
|
setLogDirectorySubfolder(it.userIdServerName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun sendBugReport(
|
override suspend fun sendBugReport(
|
||||||
withDevicesLogs: Boolean,
|
withDevicesLogs: Boolean,
|
||||||
|
|
@ -286,16 +309,44 @@ class DefaultBugReporter @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun logDirectory(): File {
|
override fun logDirectory(): File {
|
||||||
return File(context.cacheDir, LOG_DIRECTORY_NAME).apply {
|
return currentLogDirectory.apply {
|
||||||
mkdirs()
|
mkdirs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setLogDirectorySubfolder(subfolderName: String?) {
|
||||||
|
if (buildMeta.isEnterpriseBuild) {
|
||||||
|
setCurrentLogDirectory(subfolderName)
|
||||||
|
tracingService.updateWriteToFilesConfiguration(createWriteToFilesConfiguration())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setCurrentLogDirectory(subfolderName: String?) {
|
||||||
|
currentLogDirectory = if (subfolderName == null) {
|
||||||
|
baseLogDirectory
|
||||||
|
} else {
|
||||||
|
File(baseLogDirectory, subfolderName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun deleteAllFiles(predicate: (File) -> Boolean) {
|
suspend fun deleteAllFiles(predicate: (File) -> Boolean) {
|
||||||
withContext(coroutineDispatchers.io) {
|
withContext(coroutineDispatchers.io) {
|
||||||
getLogFiles()
|
deleteAllFilesRecursive(baseLogDirectory, predicate)
|
||||||
.filter(predicate)
|
}
|
||||||
.forEach { it.safeDelete() }
|
}
|
||||||
|
|
||||||
|
private fun deleteAllFilesRecursive(
|
||||||
|
directory: File,
|
||||||
|
predicate: (File) -> Boolean,
|
||||||
|
) {
|
||||||
|
directory.listFiles()?.forEach { file ->
|
||||||
|
if (file.isDirectory) {
|
||||||
|
deleteAllFilesRecursive(file, predicate)
|
||||||
|
} else {
|
||||||
|
if (predicate(file)) {
|
||||||
|
file.safeDelete()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,11 +376,12 @@ class DefaultBugReporter @Inject constructor(
|
||||||
* @return the file if the operation succeeds
|
* @return the file if the operation succeeds
|
||||||
*/
|
*/
|
||||||
override fun saveLogCat() {
|
override fun saveLogCat() {
|
||||||
if (logCatErrFile.exists()) {
|
val file = logCatErrFile
|
||||||
logCatErrFile.safeDelete()
|
if (file.exists()) {
|
||||||
|
file.safeDelete()
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
logCatErrFile.writer().use {
|
file.writer().use {
|
||||||
getLogCatError(it)
|
getLogCatError(it)
|
||||||
}
|
}
|
||||||
} catch (error: OutOfMemoryError) {
|
} catch (error: OutOfMemoryError) {
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,10 @@ class FakeBugReporter(val mode: Mode = Mode.Success) : BugReporter {
|
||||||
return File("fake")
|
return File("fake")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setLogDirectorySubfolder(subfolderName: String?) {
|
||||||
|
// No op
|
||||||
|
}
|
||||||
|
|
||||||
override fun setCurrentTracingLogLevel(logLevel: String) {
|
override fun setCurrentTracingLogLevel(logLevel: String) {
|
||||||
// No op
|
// No op
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,26 @@ package io.element.android.features.rageshake.impl.reporter
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.appconfig.RageshakeConfig
|
import io.element.android.appconfig.RageshakeConfig
|
||||||
import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
||||||
|
import io.element.android.features.rageshake.impl.crash.CrashDataStore
|
||||||
import io.element.android.features.rageshake.impl.crash.FakeCrashDataStore
|
import io.element.android.features.rageshake.impl.crash.FakeCrashDataStore
|
||||||
import io.element.android.features.rageshake.impl.screenshot.FakeScreenshotHolder
|
import io.element.android.features.rageshake.impl.screenshot.FakeScreenshotHolder
|
||||||
|
import io.element.android.libraries.core.meta.BuildMeta
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||||
|
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||||
|
import io.element.android.libraries.matrix.api.tracing.TracingService
|
||||||
|
import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
||||||
import io.element.android.libraries.matrix.test.FakeSdkMetadata
|
import io.element.android.libraries.matrix.test.FakeSdkMetadata
|
||||||
|
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
||||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||||
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
|
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
|
||||||
|
import io.element.android.libraries.matrix.test.tracing.FakeTracingService
|
||||||
import io.element.android.libraries.network.useragent.DefaultUserAgentProvider
|
import io.element.android.libraries.network.useragent.DefaultUserAgentProvider
|
||||||
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
import io.element.android.libraries.sessionstorage.impl.memory.InMemorySessionStore
|
import io.element.android.libraries.sessionstorage.impl.memory.InMemorySessionStore
|
||||||
import io.element.android.libraries.sessionstorage.test.aSessionData
|
import io.element.android.libraries.sessionstorage.test.aSessionData
|
||||||
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
@ -45,7 +55,7 @@ class DefaultBugReporterTest {
|
||||||
.setResponseCode(200)
|
.setResponseCode(200)
|
||||||
)
|
)
|
||||||
server.start()
|
server.start()
|
||||||
val sut = createDefaultBugReporter(server)
|
val sut = createDefaultBugReporter(server = server)
|
||||||
var onUploadCancelledCalled = false
|
var onUploadCancelledCalled = false
|
||||||
var onUploadFailedCalled = false
|
var onUploadFailedCalled = false
|
||||||
val progressValues = mutableListOf<Int>()
|
val progressValues = mutableListOf<Int>()
|
||||||
|
|
@ -97,22 +107,14 @@ class DefaultBugReporterTest {
|
||||||
storeData(aSessionData(sessionId = "@foo:example.com", deviceId = "ABCDEFGH"))
|
storeData(aSessionData(sessionId = "@foo:example.com", deviceId = "ABCDEFGH"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val buildMeta = aBuildMeta()
|
|
||||||
val fakeEncryptionService = FakeEncryptionService()
|
val fakeEncryptionService = FakeEncryptionService()
|
||||||
val matrixClient = FakeMatrixClient(encryptionService = fakeEncryptionService)
|
val matrixClient = FakeMatrixClient(encryptionService = fakeEncryptionService)
|
||||||
|
|
||||||
fakeEncryptionService.givenDeviceKeys("CURVECURVECURVE", "EDKEYEDKEYEDKY")
|
fakeEncryptionService.givenDeviceKeys("CURVECURVECURVE", "EDKEYEDKEYEDKY")
|
||||||
val sut = DefaultBugReporter(
|
val sut = createDefaultBugReporter(
|
||||||
context = RuntimeEnvironment.getApplication(),
|
server = server,
|
||||||
screenshotHolder = FakeScreenshotHolder(),
|
|
||||||
crashDataStore = FakeCrashDataStore(),
|
crashDataStore = FakeCrashDataStore(),
|
||||||
coroutineDispatchers = testCoroutineDispatchers(),
|
|
||||||
okHttpClient = { OkHttpClient.Builder().build() },
|
|
||||||
userAgentProvider = DefaultUserAgentProvider(buildMeta, FakeSdkMetadata("123456789")),
|
|
||||||
sessionStore = mockSessionStore,
|
sessionStore = mockSessionStore,
|
||||||
buildMeta = buildMeta,
|
|
||||||
bugReporterUrlProvider = { server.url("/") },
|
|
||||||
sdkMetadata = FakeSdkMetadata("123456789"),
|
|
||||||
matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(matrixClient) })
|
matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(matrixClient) })
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -166,22 +168,13 @@ class DefaultBugReporterTest {
|
||||||
storeData(aSessionData("@foo:example.com", "ABCDEFGH"))
|
storeData(aSessionData("@foo:example.com", "ABCDEFGH"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val buildMeta = aBuildMeta()
|
|
||||||
val fakeEncryptionService = FakeEncryptionService()
|
val fakeEncryptionService = FakeEncryptionService()
|
||||||
val matrixClient = FakeMatrixClient(encryptionService = fakeEncryptionService)
|
val matrixClient = FakeMatrixClient(encryptionService = fakeEncryptionService)
|
||||||
|
|
||||||
fakeEncryptionService.givenDeviceKeys(null, null)
|
fakeEncryptionService.givenDeviceKeys(null, null)
|
||||||
val sut = DefaultBugReporter(
|
val sut = createDefaultBugReporter(
|
||||||
context = RuntimeEnvironment.getApplication(),
|
server = server,
|
||||||
screenshotHolder = FakeScreenshotHolder(),
|
|
||||||
crashDataStore = FakeCrashDataStore(),
|
|
||||||
coroutineDispatchers = testCoroutineDispatchers(),
|
|
||||||
okHttpClient = { OkHttpClient.Builder().build() },
|
|
||||||
userAgentProvider = DefaultUserAgentProvider(buildMeta, FakeSdkMetadata("123456789")),
|
|
||||||
sessionStore = mockSessionStore,
|
sessionStore = mockSessionStore,
|
||||||
buildMeta = buildMeta,
|
|
||||||
bugReporterUrlProvider = { server.url("/") },
|
|
||||||
sdkMetadata = FakeSdkMetadata("123456789"),
|
|
||||||
matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(matrixClient) })
|
matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(matrixClient) })
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -209,21 +202,13 @@ class DefaultBugReporterTest {
|
||||||
)
|
)
|
||||||
server.start()
|
server.start()
|
||||||
|
|
||||||
val buildMeta = aBuildMeta()
|
|
||||||
val fakeEncryptionService = FakeEncryptionService()
|
val fakeEncryptionService = FakeEncryptionService()
|
||||||
|
|
||||||
fakeEncryptionService.givenDeviceKeys(null, null)
|
fakeEncryptionService.givenDeviceKeys(null, null)
|
||||||
val sut = DefaultBugReporter(
|
val sut = createDefaultBugReporter(
|
||||||
context = RuntimeEnvironment.getApplication(),
|
server = server,
|
||||||
screenshotHolder = FakeScreenshotHolder(),
|
|
||||||
crashDataStore = FakeCrashDataStore("I did crash", true),
|
crashDataStore = FakeCrashDataStore("I did crash", true),
|
||||||
coroutineDispatchers = testCoroutineDispatchers(),
|
|
||||||
okHttpClient = { OkHttpClient.Builder().build() },
|
|
||||||
userAgentProvider = DefaultUserAgentProvider(buildMeta, FakeSdkMetadata("123456789")),
|
|
||||||
sessionStore = InMemorySessionStore(),
|
sessionStore = InMemorySessionStore(),
|
||||||
buildMeta = buildMeta,
|
|
||||||
bugReporterUrlProvider = { server.url("/") },
|
|
||||||
sdkMetadata = FakeSdkMetadata("123456789"),
|
|
||||||
matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.failure(Exception("Mock no client")) })
|
matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.failure(Exception("Mock no client")) })
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -276,7 +261,7 @@ class DefaultBugReporterTest {
|
||||||
.setBody("""{"error": "An error body"}""")
|
.setBody("""{"error": "An error body"}""")
|
||||||
)
|
)
|
||||||
server.start()
|
server.start()
|
||||||
val sut = createDefaultBugReporter(server)
|
val sut = createDefaultBugReporter(server = server)
|
||||||
var onUploadCancelledCalled = false
|
var onUploadCancelledCalled = false
|
||||||
var onUploadFailedCalled = false
|
var onUploadFailedCalled = false
|
||||||
var onUploadFailedReason: String? = null
|
var onUploadFailedReason: String? = null
|
||||||
|
|
@ -318,22 +303,172 @@ class DefaultBugReporterTest {
|
||||||
assertThat(onUploadSucceedCalled).isFalse()
|
assertThat(onUploadSucceedCalled).isFalse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `the log directory is initialized using the last session store data`() = runTest {
|
||||||
|
val sut = createDefaultBugReporter(
|
||||||
|
buildMeta = aBuildMeta(isEnterpriseBuild = true),
|
||||||
|
sessionStore = InMemorySessionStore().apply {
|
||||||
|
storeData(aSessionData(sessionId = "@alice:domain.com"))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
assertThat(sut.logDirectory().absolutePath).endsWith("/cache/logs/domain.com")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `foss build - the log directory is initialized to the root log directory`() = runTest {
|
||||||
|
val sut = createDefaultBugReporter(
|
||||||
|
sessionStore = InMemorySessionStore().apply {
|
||||||
|
storeData(aSessionData(sessionId = "@alice:domain.com"))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
assertThat(sut.logDirectory().absolutePath).endsWith("/cache/logs")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when the log directory is updated, the tracing service is invoked`() = runTest {
|
||||||
|
var param: WriteToFilesConfiguration? = null
|
||||||
|
val updateWriteToFilesConfigurationResult = lambdaRecorder<WriteToFilesConfiguration, Unit> {
|
||||||
|
param = it
|
||||||
|
}
|
||||||
|
val sut = createDefaultBugReporter(
|
||||||
|
buildMeta = aBuildMeta(isEnterpriseBuild = true),
|
||||||
|
tracingService = FakeTracingService(
|
||||||
|
updateWriteToFilesConfigurationResult = updateWriteToFilesConfigurationResult,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
sut.setLogDirectorySubfolder("my.sub.folder")
|
||||||
|
updateWriteToFilesConfigurationResult.assertions().isCalledOnce()
|
||||||
|
assertThat(param).isNotNull()
|
||||||
|
assertThat(param).isInstanceOf(WriteToFilesConfiguration.Enabled::class.java)
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).directory).endsWith("/cache/logs/my.sub.folder")
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).filenamePrefix).isEqualTo("logs")
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).numberOfFiles).isEqualTo(168)
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).filenameSuffix).isEqualTo("log")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `foss build - when the log directory is updated, the tracing service is not invoked`() = runTest {
|
||||||
|
val updateWriteToFilesConfigurationResult = lambdaRecorder<WriteToFilesConfiguration, Unit> {}
|
||||||
|
val sut = createDefaultBugReporter(
|
||||||
|
tracingService = FakeTracingService(
|
||||||
|
updateWriteToFilesConfigurationResult = updateWriteToFilesConfigurationResult,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
sut.setLogDirectorySubfolder("my.sub.folder")
|
||||||
|
updateWriteToFilesConfigurationResult.assertions().isNeverCalled()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when the log directory is reset, the tracing service is invoked`() = runTest {
|
||||||
|
var param: WriteToFilesConfiguration? = null
|
||||||
|
val updateWriteToFilesConfigurationResult = lambdaRecorder<WriteToFilesConfiguration, Unit> {
|
||||||
|
param = it
|
||||||
|
}
|
||||||
|
val sut = createDefaultBugReporter(
|
||||||
|
buildMeta = aBuildMeta(isEnterpriseBuild = true),
|
||||||
|
tracingService = FakeTracingService(
|
||||||
|
updateWriteToFilesConfigurationResult = updateWriteToFilesConfigurationResult,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
sut.setLogDirectorySubfolder(null)
|
||||||
|
updateWriteToFilesConfigurationResult.assertions().isCalledOnce()
|
||||||
|
assertThat(param).isNotNull()
|
||||||
|
assertThat(param).isInstanceOf(WriteToFilesConfiguration.Enabled::class.java)
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).directory).endsWith("/cache/logs")
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).filenamePrefix).isEqualTo("logs")
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).numberOfFiles).isEqualTo(168)
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).filenameSuffix).isEqualTo("log")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `foss build - when the log directory is reset, the tracing service is not invoked`() = runTest {
|
||||||
|
val updateWriteToFilesConfigurationResult = lambdaRecorder<WriteToFilesConfiguration, Unit> {}
|
||||||
|
val sut = createDefaultBugReporter(
|
||||||
|
tracingService = FakeTracingService(
|
||||||
|
updateWriteToFilesConfigurationResult = updateWriteToFilesConfigurationResult,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
sut.setLogDirectorySubfolder(null)
|
||||||
|
updateWriteToFilesConfigurationResult.assertions().isNeverCalled()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when a new MatrixClient is created the logs folder is updated`() = runTest {
|
||||||
|
var param: WriteToFilesConfiguration? = null
|
||||||
|
val updateWriteToFilesConfigurationResult = lambdaRecorder<WriteToFilesConfiguration, Unit> {
|
||||||
|
param = it
|
||||||
|
}
|
||||||
|
val matrixAuthenticationService = FakeMatrixAuthenticationService().apply {
|
||||||
|
givenMatrixClient(
|
||||||
|
FakeMatrixClient(
|
||||||
|
userIdServerNameLambda = { "domain.foo.org" },
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val sut = createDefaultBugReporter(
|
||||||
|
buildMeta = aBuildMeta(isEnterpriseBuild = true),
|
||||||
|
matrixAuthenticationService = matrixAuthenticationService,
|
||||||
|
tracingService = FakeTracingService(
|
||||||
|
updateWriteToFilesConfigurationResult = updateWriteToFilesConfigurationResult,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertThat(sut.logDirectory().absolutePath).endsWith("/cache/logs")
|
||||||
|
matrixAuthenticationService.login("alice", "password")
|
||||||
|
assertThat(sut.logDirectory().absolutePath).endsWith("/cache/logs/domain.foo.org")
|
||||||
|
updateWriteToFilesConfigurationResult.assertions().isCalledOnce()
|
||||||
|
assertThat(param).isNotNull()
|
||||||
|
assertThat(param).isInstanceOf(WriteToFilesConfiguration.Enabled::class.java)
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).directory).endsWith("/cache/logs/domain.foo.org")
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).filenamePrefix).isEqualTo("logs")
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).numberOfFiles).isEqualTo(168)
|
||||||
|
assertThat((param as WriteToFilesConfiguration.Enabled).filenameSuffix).isEqualTo("log")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `foss build - when a new MatrixClient is created the logs folder is not updated`() = runTest {
|
||||||
|
val updateWriteToFilesConfigurationResult = lambdaRecorder<WriteToFilesConfiguration, Unit> {}
|
||||||
|
val matrixAuthenticationService = FakeMatrixAuthenticationService().apply {
|
||||||
|
givenMatrixClient(
|
||||||
|
FakeMatrixClient(
|
||||||
|
userIdServerNameLambda = { "domain.foo.org" },
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val sut = createDefaultBugReporter(
|
||||||
|
matrixAuthenticationService = matrixAuthenticationService,
|
||||||
|
tracingService = FakeTracingService(
|
||||||
|
updateWriteToFilesConfigurationResult = updateWriteToFilesConfigurationResult,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertThat(sut.logDirectory().absolutePath).endsWith("/cache/logs")
|
||||||
|
matrixAuthenticationService.login("alice", "password")
|
||||||
|
assertThat(sut.logDirectory().absolutePath).endsWith("/cache/logs")
|
||||||
|
updateWriteToFilesConfigurationResult.assertions().isNeverCalled()
|
||||||
|
}
|
||||||
|
|
||||||
private fun TestScope.createDefaultBugReporter(
|
private fun TestScope.createDefaultBugReporter(
|
||||||
server: MockWebServer
|
buildMeta: BuildMeta = aBuildMeta(),
|
||||||
|
sessionStore: SessionStore = InMemorySessionStore(),
|
||||||
|
matrixClientProvider: MatrixClientProvider = FakeMatrixClientProvider(),
|
||||||
|
crashDataStore: CrashDataStore = FakeCrashDataStore(),
|
||||||
|
server: MockWebServer = MockWebServer(),
|
||||||
|
tracingService: TracingService = FakeTracingService(),
|
||||||
|
matrixAuthenticationService: MatrixAuthenticationService = FakeMatrixAuthenticationService(),
|
||||||
): DefaultBugReporter {
|
): DefaultBugReporter {
|
||||||
val buildMeta = aBuildMeta()
|
|
||||||
return DefaultBugReporter(
|
return DefaultBugReporter(
|
||||||
context = RuntimeEnvironment.getApplication(),
|
context = RuntimeEnvironment.getApplication(),
|
||||||
screenshotHolder = FakeScreenshotHolder(),
|
screenshotHolder = FakeScreenshotHolder(),
|
||||||
crashDataStore = FakeCrashDataStore(),
|
crashDataStore = crashDataStore,
|
||||||
coroutineDispatchers = testCoroutineDispatchers(),
|
coroutineDispatchers = testCoroutineDispatchers(),
|
||||||
okHttpClient = { OkHttpClient.Builder().build() },
|
okHttpClient = { OkHttpClient.Builder().build() },
|
||||||
userAgentProvider = DefaultUserAgentProvider(buildMeta, FakeSdkMetadata("123456789")),
|
userAgentProvider = DefaultUserAgentProvider(buildMeta, FakeSdkMetadata("123456789")),
|
||||||
sessionStore = InMemorySessionStore(),
|
sessionStore = sessionStore,
|
||||||
buildMeta = buildMeta,
|
buildMeta = buildMeta,
|
||||||
bugReporterUrlProvider = { server.url("/") },
|
bugReporterUrlProvider = { server.url("/") },
|
||||||
sdkMetadata = FakeSdkMetadata("123456789"),
|
sdkMetadata = FakeSdkMetadata("123456789"),
|
||||||
matrixClientProvider = FakeMatrixClientProvider()
|
matrixClientProvider = matrixClientProvider,
|
||||||
|
tracingService = tracingService,
|
||||||
|
matrixAuthenticationService = matrixAuthenticationService,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,4 +11,6 @@ import timber.log.Timber
|
||||||
|
|
||||||
interface TracingService {
|
interface TracingService {
|
||||||
fun createTimberTree(target: String): Timber.Tree
|
fun createTimberTree(target: String): Timber.Tree
|
||||||
|
|
||||||
|
fun updateWriteToFilesConfiguration(config: WriteToFilesConfiguration)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,9 +71,9 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||||
private var currentClient: Client? = null
|
private var currentClient: Client? = null
|
||||||
private var currentHomeserver = MutableStateFlow<MatrixHomeServerDetails?>(null)
|
private var currentHomeserver = MutableStateFlow<MatrixHomeServerDetails?>(null)
|
||||||
|
|
||||||
private var newMatrixClientObserver: ((MatrixClient) -> Unit)? = null
|
private val newMatrixClientObservers = mutableListOf<(MatrixClient) -> Unit>()
|
||||||
override fun listenToNewMatrixClients(lambda: (MatrixClient) -> Unit) {
|
override fun listenToNewMatrixClients(lambda: (MatrixClient) -> Unit) {
|
||||||
newMatrixClientObserver = lambda
|
newMatrixClientObservers.add(lambda)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun rotateSessionPath(): SessionPaths {
|
private fun rotateSessionPath(): SessionPaths {
|
||||||
|
|
@ -155,7 +155,8 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||||
passphrase = pendingPassphrase,
|
passphrase = pendingPassphrase,
|
||||||
sessionPaths = currentSessionPaths,
|
sessionPaths = currentSessionPaths,
|
||||||
)
|
)
|
||||||
newMatrixClientObserver?.invoke(rustMatrixClientFactory.create(client))
|
val matrixClient = rustMatrixClientFactory.create(client)
|
||||||
|
newMatrixClientObservers.forEach { it.invoke(matrixClient) }
|
||||||
sessionStore.storeData(sessionData)
|
sessionStore.storeData(sessionData)
|
||||||
|
|
||||||
// Clean up the strong reference held here since it's no longer necessary
|
// Clean up the strong reference held here since it's no longer necessary
|
||||||
|
|
@ -246,7 +247,8 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||||
pendingOAuthAuthorizationData?.close()
|
pendingOAuthAuthorizationData?.close()
|
||||||
pendingOAuthAuthorizationData = null
|
pendingOAuthAuthorizationData = null
|
||||||
|
|
||||||
newMatrixClientObserver?.invoke(rustMatrixClientFactory.create(client))
|
val matrixClient = rustMatrixClientFactory.create(client)
|
||||||
|
newMatrixClientObservers.forEach { it.invoke(matrixClient) }
|
||||||
sessionStore.storeData(sessionData)
|
sessionStore.storeData(sessionData)
|
||||||
|
|
||||||
// Clean up the strong reference held here since it's no longer necessary
|
// Clean up the strong reference held here since it's no longer necessary
|
||||||
|
|
@ -290,7 +292,8 @@ class RustMatrixAuthenticationService @Inject constructor(
|
||||||
passphrase = pendingPassphrase,
|
passphrase = pendingPassphrase,
|
||||||
sessionPaths = emptySessionPaths,
|
sessionPaths = emptySessionPaths,
|
||||||
)
|
)
|
||||||
newMatrixClientObserver?.invoke(rustMatrixClientFactory.create(client))
|
val matrixClient = rustMatrixClientFactory.create(client)
|
||||||
|
newMatrixClientObservers.forEach { it.invoke(matrixClient) }
|
||||||
sessionStore.storeData(sessionData)
|
sessionStore.storeData(sessionData)
|
||||||
|
|
||||||
// Clean up the strong reference held here since it's no longer necessary
|
// Clean up the strong reference held here since it's no longer necessary
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
|
||||||
import io.element.android.libraries.matrix.api.tracing.TracingService
|
import io.element.android.libraries.matrix.api.tracing.TracingService
|
||||||
import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration
|
import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration
|
||||||
import org.matrix.rustcomponents.sdk.TracingFileConfiguration
|
import org.matrix.rustcomponents.sdk.TracingFileConfiguration
|
||||||
|
import org.matrix.rustcomponents.sdk.reloadTracingFileWriter
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -23,6 +24,12 @@ class RustTracingService @Inject constructor(private val buildMeta: BuildMeta) :
|
||||||
override fun createTimberTree(target: String): Timber.Tree {
|
override fun createTimberTree(target: String): Timber.Tree {
|
||||||
return RustTracingTree(target = target, retrieveFromStackTrace = buildMeta.isDebuggable)
|
return RustTracingTree(target = target, retrieveFromStackTrace = buildMeta.isDebuggable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateWriteToFilesConfiguration(config: WriteToFilesConfiguration) {
|
||||||
|
config.toTracingFileConfiguration()?.let {
|
||||||
|
reloadTracingFileWriter(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun LogLevel.toRustLogLevel(): org.matrix.rustcomponents.sdk.LogLevel {
|
private fun LogLevel.toRustLogLevel(): org.matrix.rustcomponents.sdk.LogLevel {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.test.tracing
|
||||||
|
|
||||||
|
import io.element.android.libraries.matrix.api.tracing.TracingService
|
||||||
|
import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration
|
||||||
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class FakeTracingService(
|
||||||
|
private val createTimberTreeResult: (String) -> Timber.Tree = { lambdaError() },
|
||||||
|
private val updateWriteToFilesConfigurationResult: (WriteToFilesConfiguration) -> Unit = { lambdaError() }
|
||||||
|
) : TracingService {
|
||||||
|
override fun createTimberTree(target: String): Timber.Tree {
|
||||||
|
return createTimberTreeResult(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateWriteToFilesConfiguration(config: WriteToFilesConfiguration) {
|
||||||
|
updateWriteToFilesConfigurationResult(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue