diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/LogRecordExporterTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/LogRecordExporterTest.kt index 3871b533a..866a1ad56 100644 --- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/LogRecordExporterTest.kt +++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/LogRecordExporterTest.kt @@ -4,8 +4,8 @@ import android.os.Build import androidx.test.ext.junit.runners.AndroidJUnit4 import io.embrace.android.embracesdk.IntegrationTestRule import io.embrace.android.embracesdk.Severity +import io.embrace.android.embracesdk.fakes.FakeInternalErrorService import io.embrace.android.embracesdk.fakes.FakeLogRecordExporter -import io.embrace.android.embracesdk.fakes.FakeLogAction import io.embrace.android.embracesdk.recordSession import org.junit.Assert import org.junit.Rule @@ -13,6 +13,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.Config import java.lang.Thread.sleep +import org.junit.Assert.* @Config(sdk = [Build.VERSION_CODES.TIRAMISU]) @RunWith(AndroidJUnit4::class) @@ -39,8 +40,8 @@ internal class LogRecordExporterTest { sleep(3000) } - Assert.assertTrue((fakeLogRecordExporter.exportedLogs?.size ?: 0) > 0) - Assert.assertEquals("test message", fakeLogRecordExporter.exportedLogs?.first()?.body?.asString()) + assertTrue((fakeLogRecordExporter.exportedLogs?.size ?: 0) > 0) + assertEquals("test message", fakeLogRecordExporter.exportedLogs?.first()?.body?.asString()) } } @@ -48,8 +49,10 @@ internal class LogRecordExporterTest { fun `a LogRecordExporter added after initialization won't be used`() { with(testRule) { - val fake = FakeLogAction() - harness.overriddenInitModule.logger.apply { addLoggerAction(fake) } + val fake = FakeInternalErrorService() + harness.overriddenInitModule.logger.apply { + internalErrorService = fake + } val fakeLogRecordExporter = FakeLogRecordExporter() embrace.start(harness.overriddenCoreModule.context) @@ -60,10 +63,7 @@ internal class LogRecordExporterTest { sleep(3000) } - Assert.assertTrue((fakeLogRecordExporter.exportedLogs?.size ?: 0) == 0) - Assert.assertTrue(fake.msgQueue.any { - it.msg == "A LogRecordExporter can only be added before the SDK is started." - }) + assertTrue((fakeLogRecordExporter.exportedLogs?.size ?: 0) == 0) } } } \ No newline at end of file diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/SpanTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/SpanTest.kt index 088ff8335..82b17fd71 100644 --- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/SpanTest.kt +++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/SpanTest.kt @@ -3,7 +3,7 @@ package io.embrace.android.embracesdk.testcases import android.os.Build import androidx.test.ext.junit.runners.AndroidJUnit4 import io.embrace.android.embracesdk.IntegrationTestRule -import io.embrace.android.embracesdk.fakes.FakeLogAction +import io.embrace.android.embracesdk.fakes.FakeInternalErrorService import io.embrace.android.embracesdk.fakes.FakeSpanExporter import io.embrace.android.embracesdk.opentelemetry.assertExpectedAttributes import io.embrace.android.embracesdk.opentelemetry.assertHasEmbraceAttribute @@ -71,8 +71,10 @@ internal class SpanTest { fun `a SpanExporter added after initialization won't be used`() { with(testRule) { - val fake = FakeLogAction() - harness.overriddenInitModule.logger.apply { addLoggerAction(fake) } + val fake = FakeInternalErrorService() + harness.overriddenInitModule.logger.apply { + internalErrorService = fake + } val fakeSpanExporter = FakeSpanExporter() embrace.start(harness.overriddenCoreModule.context) @@ -84,9 +86,6 @@ internal class SpanTest { Thread.sleep(3000) } assertTrue(fakeSpanExporter.exportedSpans.size == 0) - assertTrue(fake.msgQueue.any { - it.msg == "A SpanExporter can only be added before the SDK is started." - }) } } } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java index 9604f3347..7e8c3b84f 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java @@ -48,7 +48,6 @@ import io.embrace.android.embracesdk.internal.utils.ThrowableUtilsKt; import io.embrace.android.embracesdk.logging.EmbLogger; import io.embrace.android.embracesdk.logging.InternalErrorService; -import io.embrace.android.embracesdk.logging.InternalErrorServiceAction; import io.embrace.android.embracesdk.ndk.NativeModule; import io.embrace.android.embracesdk.ndk.NdkService; import io.embrace.android.embracesdk.network.EmbraceNetworkRequest; @@ -855,7 +854,7 @@ void logInternalError(@Nullable String message, @Nullable String details) { } else { messageWithDetails = message; } - internalErrorService.handleInternalError(new InternalErrorServiceAction.InternalError(messageWithDetails)); + internalErrorService.handleInternalError(new RuntimeException(messageWithDetails)); } } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/injection/ModuleInitBootstrapper.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/injection/ModuleInitBootstrapper.kt index f5c6f689f..1e5f37c1a 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/injection/ModuleInitBootstrapper.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/injection/ModuleInitBootstrapper.kt @@ -286,7 +286,7 @@ internal class ModuleInitBootstrapper( postInit(SdkObservabilityModule::class) { serviceRegistry.registerService(sdkObservabilityModule.internalErrorService) - initModule.logger.addLoggerAction(sdkObservabilityModule.reportingLoggerAction) + initModule.logger.internalErrorService = sdkObservabilityModule.internalErrorService } nativeModule = init(NativeModule::class) { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/injection/SdkObservabilityModule.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/injection/SdkObservabilityModule.kt index 12395d2ef..484cfc2db 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/injection/SdkObservabilityModule.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/injection/SdkObservabilityModule.kt @@ -2,7 +2,6 @@ package io.embrace.android.embracesdk.injection import io.embrace.android.embracesdk.logging.EmbraceInternalErrorService import io.embrace.android.embracesdk.logging.InternalErrorService -import io.embrace.android.embracesdk.logging.InternalErrorServiceAction /** * Contains dependencies that are used to gain internal observability into how the SDK @@ -10,7 +9,6 @@ import io.embrace.android.embracesdk.logging.InternalErrorServiceAction */ internal interface SdkObservabilityModule { val internalErrorService: InternalErrorService - val reportingLoggerAction: InternalErrorServiceAction } internal class SdkObservabilityModuleImpl( @@ -24,8 +22,4 @@ internal class SdkObservabilityModuleImpl( initModule.clock ) } - - override val reportingLoggerAction: InternalErrorServiceAction by singleton { - InternalErrorServiceAction(internalErrorService) - } } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/EmbLogger.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/EmbLogger.kt index f2a8553ee..dc1771178 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/EmbLogger.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/EmbLogger.kt @@ -5,7 +5,7 @@ package io.embrace.android.embracesdk.logging */ internal interface EmbLogger { - fun addLoggerAction(action: EmbLoggerImpl.LogAction) + var internalErrorService: InternalErrorService? /** * Logs a debug message with an optional throwable. diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/EmbLoggerImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/EmbLoggerImpl.kt index 2b0fb3f8d..c455e4f0b 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/EmbLoggerImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/EmbLoggerImpl.kt @@ -2,7 +2,6 @@ package io.embrace.android.embracesdk.logging import android.util.Log import io.embrace.android.embracesdk.internal.ApkToolsConfig -import java.util.concurrent.CopyOnWriteArrayList internal const val EMBRACE_TAG = "[Embrace]" @@ -11,18 +10,9 @@ internal const val EMBRACE_TAG = "[Embrace]" * Can only be used internally, it's not part of the public API. */ -// Suppressing "Nothing to inline". These functions are used all around the codebase, pretty often, so we want them to -// perform as fast as possible. internal class EmbLoggerImpl : EmbLogger { - private val logActions = CopyOnWriteArrayList(listOf()) - internal fun interface LogAction { - fun log(msg: String, severity: Severity, throwable: Throwable?, logStacktrace: Boolean) - } - - override fun addLoggerAction(action: LogAction) { - logActions.add(action) - } + override var internalErrorService: InternalErrorService? = null override fun logDebug(msg: String, throwable: Throwable?) { log(msg, Severity.DEBUG, throwable, true) @@ -58,8 +48,14 @@ internal class EmbLoggerImpl : EmbLogger { if (severity >= Severity.INFO || ApkToolsConfig.IS_DEVELOPER_LOGGING_ENABLED) { logcatImpl(throwable, logStacktrace, severity, msg) - logActions.forEach { - it.log(msg, severity, throwable, logStacktrace) + // report to internal error service if necessary + if (throwable != null) { + try { + internalErrorService?.handleInternalError(throwable) + } catch (exc: Throwable) { + // don't cause a crash loop! + Log.w(EMBRACE_TAG, msg, exc) + } } } } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/InternalErrorServiceAction.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/InternalErrorServiceAction.kt deleted file mode 100644 index b46ae4dfc..000000000 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/logging/InternalErrorServiceAction.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.embrace.android.embracesdk.logging - -import android.util.Log - -/** - * Sends a log message from Embrace's log implementation to [InternalErrorService], - * if it contains a throwable. - */ -internal class InternalErrorServiceAction( - private val internalErrorService: InternalErrorService -) : EmbLoggerImpl.LogAction { - - override fun log( - msg: String, - severity: EmbLoggerImpl.Severity, - throwable: Throwable?, - logStacktrace: Boolean - ) { - if (throwable != null) { - try { - internalErrorService.handleInternalError(throwable) - } catch (e: Throwable) { - // Yo dawg, I heard you like to handle internal errors... - Log.w(EMBRACE_TAG, msg, e) - } - } - } - - class InternalError(msg: String) : Exception(msg) -} diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceCacheServiceTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceCacheServiceTest.kt index 8d3aa65a0..3ae8e9743 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceCacheServiceTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceCacheServiceTest.kt @@ -11,14 +11,13 @@ import io.embrace.android.embracesdk.comms.delivery.EmbraceCacheService.Companio import io.embrace.android.embracesdk.comms.delivery.EmbraceCacheService.Companion.TEMP_COPY_SUFFIX import io.embrace.android.embracesdk.comms.delivery.PendingApiCall import io.embrace.android.embracesdk.comms.delivery.PendingApiCalls -import io.embrace.android.embracesdk.fakes.FakeLogAction +import io.embrace.android.embracesdk.fakes.FakeEmbLogger import io.embrace.android.embracesdk.fakes.FakeStorageService import io.embrace.android.embracesdk.fakes.TestPlatformSerializer import io.embrace.android.embracesdk.fakes.fakeSession import io.embrace.android.embracesdk.fixtures.testSessionMessage import io.embrace.android.embracesdk.fixtures.testSessionMessage2 import io.embrace.android.embracesdk.fixtures.testSessionMessageOneMinuteLater -import io.embrace.android.embracesdk.logging.EmbLoggerImpl import io.embrace.android.embracesdk.network.http.HttpMethod import io.embrace.android.embracesdk.payload.Session import io.embrace.android.embracesdk.payload.SessionMessage @@ -38,15 +37,13 @@ internal class EmbraceCacheServiceTest { private lateinit var service: CacheService private lateinit var storageManager: FakeStorageService - private lateinit var loggerAction: FakeLogAction - private lateinit var logger: EmbLoggerImpl + private lateinit var logger: FakeEmbLogger private val serializer = TestPlatformSerializer() @Before fun setUp() { storageManager = FakeStorageService() - loggerAction = FakeLogAction() - logger = EmbLoggerImpl().apply { addLoggerAction(loggerAction) } + logger = FakeEmbLogger() service = EmbraceCacheService( storageManager, serializer, @@ -359,8 +356,8 @@ internal class EmbraceCacheServiceTest { assertEquals(1, filesAgain.size) assertEquals(files[0], filesAgain[0]) - val errors = loggerAction.msgQueue.filter { it.severity == EmbLoggerImpl.Severity.ERROR } - assertEquals("The following errors were logged: $errors", 0, errors.size) + val errors = logger.errorMessages + assertEquals("The following errors were logged: $errors", 0, logger.errorMessages.size) } @Test diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceDeliveryCacheManagerTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceDeliveryCacheManagerTest.kt index 30b655887..1f5838dc4 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceDeliveryCacheManagerTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceDeliveryCacheManagerTest.kt @@ -10,7 +10,7 @@ import io.embrace.android.embracesdk.comms.delivery.PendingApiCall import io.embrace.android.embracesdk.comms.delivery.PendingApiCalls import io.embrace.android.embracesdk.comms.delivery.SessionPurgeException import io.embrace.android.embracesdk.fakes.FakeClock -import io.embrace.android.embracesdk.fakes.FakeLogAction +import io.embrace.android.embracesdk.fakes.FakeInternalErrorService import io.embrace.android.embracesdk.fakes.FakeStorageService import io.embrace.android.embracesdk.fakes.fakeSession import io.embrace.android.embracesdk.fixtures.testSessionMessage @@ -50,7 +50,7 @@ internal class EmbraceDeliveryCacheManagerTest { private lateinit var deliveryCacheManager: EmbraceDeliveryCacheManager private lateinit var storageService: StorageService private lateinit var cacheService: EmbraceCacheService - private lateinit var loggerAction: FakeLogAction + private lateinit var fakeService: FakeInternalErrorService private lateinit var logger: EmbLoggerImpl private lateinit var fakeClock: FakeClock @@ -61,8 +61,8 @@ internal class EmbraceDeliveryCacheManagerTest { @Before fun before() { fakeClock = FakeClock(clockInit) - loggerAction = FakeLogAction() - logger = EmbLoggerImpl().apply { addLoggerAction(loggerAction) } + fakeService = FakeInternalErrorService() + logger = EmbLoggerImpl().apply { internalErrorService = fakeService } storageService = FakeStorageService() cacheService = spyk( EmbraceCacheService( @@ -198,7 +198,7 @@ internal class EmbraceDeliveryCacheManagerTest { assertEquals( 100 - EmbraceDeliveryCacheManager.MAX_SESSIONS_CACHED, - loggerAction.msgQueue.filter { it.throwable is SessionPurgeException }.size + fakeService.throwables.filterIsInstance().size ) } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/anr/detection/UnbalancedCallDetectorTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/anr/detection/UnbalancedCallDetectorTest.kt index f69eaa8fd..31ff08a9b 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/anr/detection/UnbalancedCallDetectorTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/anr/detection/UnbalancedCallDetectorTest.kt @@ -1,22 +1,19 @@ package io.embrace.android.embracesdk.anr.detection -import io.embrace.android.embracesdk.fakes.FakeLogAction -import io.embrace.android.embracesdk.logging.EmbLoggerImpl +import io.embrace.android.embracesdk.fakes.FakeEmbLogger import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test internal class UnbalancedCallDetectorTest { - private lateinit var logger: EmbLoggerImpl + private lateinit var logger: FakeEmbLogger private lateinit var detector: UnbalancedCallDetector - private lateinit var action: FakeLogAction private val thread = Thread.currentThread() @Before fun setUp() { - action = FakeLogAction() - logger = EmbLoggerImpl().apply { addLoggerAction(action) } + logger = FakeEmbLogger() detector = UnbalancedCallDetector(logger) } @@ -75,9 +72,7 @@ internal class UnbalancedCallDetectorTest { } private fun verifyInternalErrorLogs(expectedCount: Int) { - val messages = action.msgQueue.filter { msg -> - msg.severity == EmbLoggerImpl.Severity.ERROR && msg.logStacktrace - } + val messages = logger.errorMessages.filter { msg -> msg.logStacktrace } assertEquals(expectedCount, messages.size) } } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt index 91d7df426..8a8218f63 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt @@ -9,7 +9,7 @@ import io.embrace.android.embracesdk.arch.schema.PrivateSpan import io.embrace.android.embracesdk.concurrency.BlockableExecutorService import io.embrace.android.embracesdk.fakes.FakeClock import io.embrace.android.embracesdk.fakes.FakeClock.Companion.DEFAULT_FAKE_CURRENT_TIME -import io.embrace.android.embracesdk.fakes.FakeLogAction +import io.embrace.android.embracesdk.fakes.FakeInternalErrorService import io.embrace.android.embracesdk.fakes.injection.FakeInitModule import io.embrace.android.embracesdk.internal.clock.nanosToMillis import io.embrace.android.embracesdk.internal.spans.EmbraceSpanData @@ -38,7 +38,7 @@ internal class AppStartupTraceEmitterTest { private lateinit var clock: FakeClock private lateinit var spanSink: SpanSink private lateinit var spanService: SpanService - private lateinit var loggerAction: FakeLogAction + private lateinit var fakeInternalErrorService: FakeInternalErrorService private lateinit var logger: EmbLoggerImpl private lateinit var backgroundWorker: BackgroundWorker private lateinit var appStartupTraceEmitter: AppStartupTraceEmitter @@ -56,8 +56,8 @@ internal class AppStartupTraceEmitterTest { backgroundWorker ) clock.tick(100L) - loggerAction = FakeLogAction() - logger = EmbLoggerImpl().apply { addLoggerAction(loggerAction) } + fakeInternalErrorService = FakeInternalErrorService() + logger = EmbLoggerImpl().apply { internalErrorService = fakeInternalErrorService } appStartupTraceEmitter = AppStartupTraceEmitter( clock = initModule.openTelemetryClock, startupServiceProvider = { startupService }, @@ -66,7 +66,7 @@ internal class AppStartupTraceEmitterTest { versionChecker = BuildVersionChecker, logger = logger ) - loggerAction.msgQueue.clear() + fakeInternalErrorService.throwables.clear() } @Config(sdk = [Build.VERSION_CODES.TIRAMISU]) @@ -74,7 +74,6 @@ internal class AppStartupTraceEmitterTest { fun `no crashes if startup service not available in T`() { startupService = null appStartupTraceEmitter.firstFrameRendered() - assertEquals(1, loggerAction.msgQueue.size) } @Config(sdk = [Build.VERSION_CODES.TIRAMISU]) @@ -100,7 +99,6 @@ internal class AppStartupTraceEmitterTest { fun `no crashes if startup service not available in S`() { startupService = null appStartupTraceEmitter.firstFrameRendered() - assertEquals(1, loggerAction.msgQueue.size) } @Config(sdk = [Build.VERSION_CODES.S]) @@ -126,7 +124,6 @@ internal class AppStartupTraceEmitterTest { fun `no crashes if startup service not available in P`() { startupService = null appStartupTraceEmitter.startupActivityResumed() - assertEquals(1, loggerAction.msgQueue.size) } @Config(sdk = [Build.VERSION_CODES.P]) @@ -152,7 +149,6 @@ internal class AppStartupTraceEmitterTest { fun `no crashes if startup service not available in M`() { startupService = null appStartupTraceEmitter.startupActivityResumed() - assertEquals(1, loggerAction.msgQueue.size) } @Config(sdk = [Build.VERSION_CODES.M]) @@ -178,7 +174,6 @@ internal class AppStartupTraceEmitterTest { fun `no crashes if startup service not available in L`() { startupService = null appStartupTraceEmitter.startupActivityResumed() - assertEquals(1, loggerAction.msgQueue.size) } @Config(sdk = [Build.VERSION_CODES.LOLLIPOP]) @@ -238,7 +233,7 @@ internal class AppStartupTraceEmitterTest { assertChildSpan(activityCreate, startupActivityStart, startupActivityEnd) assertChildSpan(firstRender, startupActivityEnd, traceEnd) - assertEquals(0, loggerAction.msgQueue.size) + assertEquals(0, fakeInternalErrorService.throwables.size) } private fun verifyColdStartWithRenderWithoutAppInitEvents() { @@ -273,7 +268,7 @@ internal class AppStartupTraceEmitterTest { assertChildSpan(activityCreate, startupActivityStart, startupActivityEnd) assertChildSpan(firstRender, startupActivityEnd, traceEnd) - assertEquals(0, loggerAction.msgQueue.size) + assertEquals(0, fakeInternalErrorService.throwables.size) } private fun verifyColdStartWithResume(trackProcessStart: Boolean = true) { @@ -320,7 +315,7 @@ internal class AppStartupTraceEmitterTest { assertChildSpan(activityCreate, startupActivityStart, startupActivityEnd) assertChildSpan(activityResume, startupActivityEnd, traceEnd) - assertEquals(0, loggerAction.msgQueue.size) + assertEquals(0, fakeInternalErrorService.throwables.size) } private fun verifyColdStartWithResumeWithoutAppInitEvents(trackProcessStart: Boolean = true) { @@ -359,7 +354,7 @@ internal class AppStartupTraceEmitterTest { assertChildSpan(activityCreate, startupActivityStart, startupActivityEnd) assertChildSpan(activityResume, startupActivityEnd, traceEnd) - assertEquals(0, loggerAction.msgQueue.size) + assertEquals(0, fakeInternalErrorService.throwables.size) } private fun verifyWarmStartWithRenderWithoutAppInitEvents() { @@ -394,7 +389,7 @@ internal class AppStartupTraceEmitterTest { assertChildSpan(activityCreate, startupActivityStart, startupActivityEnd) assertChildSpan(firstRender, startupActivityEnd, traceEnd) - assertEquals(0, loggerAction.msgQueue.size) + assertEquals(0, fakeInternalErrorService.throwables.size) } private fun verifyWarmStartWithResumeWithoutAppInitEvents() { @@ -426,7 +421,7 @@ internal class AppStartupTraceEmitterTest { } assertChildSpan(activityCreate, startupActivityStart, startupActivityEnd) assertChildSpan(activityResume, startupActivityEnd, traceEnd) - assertEquals(0, loggerAction.msgQueue.size) + assertEquals(0, fakeInternalErrorService.throwables.size) } private fun assertTraceRoot(trace: EmbraceSpanData, expectedStartTimeNanos: Long, expectedEndTimeNanos: Long) { diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiClientImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiClientImplTest.kt index 911e5e045..b60998ebd 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiClientImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiClientImplTest.kt @@ -194,12 +194,12 @@ internal class ApiClientImplTest { "Content-Type" to "application/json", "Content-Encoding" to "gzip", "Accept-Encoding" to "gzip", - "Connection" to "keep-alive", - "Content-Length" to "${delivered.bodySize}", "X-EM-AID" to "abcde", "X-EM-DID" to "test_did", "X-EM-SID" to "test_eid", - "X-EM-LID" to "test_lid" + "X-EM-LID" to "test_lid", + "Connection" to "keep-alive", + "Content-Length" to "${delivered.bodySize}", ), headers ) diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbraceCacheServiceConcurrentAccessTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbraceCacheServiceConcurrentAccessTest.kt index 7368d8b49..80a98e005 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbraceCacheServiceConcurrentAccessTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbraceCacheServiceConcurrentAccessTest.kt @@ -1,13 +1,12 @@ package io.embrace.android.embracesdk.comms.delivery import io.embrace.android.embracesdk.concurrency.ExecutionCoordinator -import io.embrace.android.embracesdk.fakes.FakeLogAction +import io.embrace.android.embracesdk.fakes.FakeEmbLogger import io.embrace.android.embracesdk.fakes.FakeStorageService import io.embrace.android.embracesdk.fakes.TestPlatformSerializer import io.embrace.android.embracesdk.fixtures.testSessionMessage import io.embrace.android.embracesdk.fixtures.testSessionMessage2 import io.embrace.android.embracesdk.fixtures.testSessionMessageOneMinuteLater -import io.embrace.android.embracesdk.logging.EmbLoggerImpl import io.embrace.android.embracesdk.payload.SessionMessage import org.junit.Assert.assertEquals import org.junit.Assert.assertNull @@ -15,19 +14,18 @@ import org.junit.Before import org.junit.Test internal class EmbraceCacheServiceConcurrentAccessTest { + private lateinit var embraceCacheService: EmbraceCacheService private lateinit var storageService: FakeStorageService private lateinit var serializer: TestPlatformSerializer - private lateinit var loggerAction: FakeLogAction - private lateinit var logger: EmbLoggerImpl + private lateinit var logger: FakeEmbLogger private lateinit var executionCoordinator: ExecutionCoordinator @Before fun setUp() { storageService = FakeStorageService() serializer = TestPlatformSerializer() - loggerAction = FakeLogAction() - logger = EmbLoggerImpl().apply { addLoggerAction(loggerAction) } + logger = FakeEmbLogger() embraceCacheService = EmbraceCacheService( storageService, serializer, @@ -35,7 +33,7 @@ internal class EmbraceCacheServiceConcurrentAccessTest { ) executionCoordinator = ExecutionCoordinator( executionModifiers = serializer, - errorLogsProvider = ::getErrorLogs + errorLogsProvider = { logger.errorMessages.mapNotNull(FakeEmbLogger.LogMessage::throwable) } ) } @@ -150,11 +148,6 @@ internal class EmbraceCacheServiceConcurrentAccessTest { ) } - private fun getErrorLogs() = loggerAction - .msgQueue - .filter { it.severity == EmbLoggerImpl.Severity.ERROR } - .toList() - companion object { private const val FILENAME = "testfile-1" private const val FILENAME_2 = "testfile-2" diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/concurrency/ExecutionCoordinator.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/concurrency/ExecutionCoordinator.kt index f598a19d0..3d6727801 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/concurrency/ExecutionCoordinator.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/concurrency/ExecutionCoordinator.kt @@ -1,6 +1,5 @@ package io.embrace.android.embracesdk.concurrency -import io.embrace.android.embracesdk.fakes.FakeLogAction import io.embrace.android.embracesdk.internal.utils.Provider import org.junit.Assert.assertEquals import org.junit.Assert.assertNull @@ -17,7 +16,7 @@ import java.util.concurrent.atomic.AtomicInteger */ internal class ExecutionCoordinator( private val executionModifiers: ExecutionModifiers, - private val errorLogsProvider: Provider>? + private val errorLogsProvider: Provider>? ) { private val thread1 = SingleThreadTestScheduledExecutor() private val thread2 = SingleThreadTestScheduledExecutor() diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeEmbLogger.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeEmbLogger.kt index 9d7efa0ea..503a9f9aa 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeEmbLogger.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeEmbLogger.kt @@ -1,25 +1,41 @@ package io.embrace.android.embracesdk.fakes import io.embrace.android.embracesdk.logging.EmbLogger -import io.embrace.android.embracesdk.logging.EmbLoggerImpl +import io.embrace.android.embracesdk.logging.InternalErrorService internal class FakeEmbLogger : EmbLogger { - override fun addLoggerAction(action: EmbLoggerImpl.LogAction) { - } + data class LogMessage( + val msg: String, + val throwable: Throwable?, + val logStacktrace: Boolean + ) + + var debugMessages: MutableList = mutableListOf() + var infoMessages: MutableList = mutableListOf() + var warningMessages: MutableList = mutableListOf() + var errorMessages: MutableList = mutableListOf() + var sdkNotInitializedMessages: MutableList = mutableListOf() + + override var internalErrorService: InternalErrorService? = null override fun logDebug(msg: String, throwable: Throwable?) { + debugMessages.add(LogMessage(msg, throwable, false)) } override fun logInfo(msg: String) { + infoMessages.add(LogMessage(msg, null, false)) } override fun logWarning(msg: String, throwable: Throwable?, logStacktrace: Boolean) { + warningMessages.add(LogMessage(msg, throwable, logStacktrace)) } override fun logError(msg: String, throwable: Throwable?, logStacktrace: Boolean) { + errorMessages.add(LogMessage(msg, throwable, logStacktrace)) } override fun logSdkNotInitialized(action: String) { + sdkNotInitializedMessages.add(LogMessage(action, null, false)) } } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeLogAction.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeLogAction.kt deleted file mode 100644 index 6979b4828..000000000 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeLogAction.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.embrace.android.embracesdk.fakes - -import io.embrace.android.embracesdk.logging.EmbLoggerImpl -import io.embrace.android.embracesdk.logging.EmbLoggerImpl.Severity -import java.util.LinkedList - -internal class FakeLogAction : EmbLoggerImpl.LogAction { - - val msgQueue = LinkedList() - - override fun log( - msg: String, - severity: Severity, - throwable: Throwable?, - logStacktrace: Boolean - ) { - msgQueue.add(LogMessage(msg, severity, throwable, logStacktrace)) - } - - internal data class LogMessage( - val msg: String, - val severity: Severity, - val throwable: Throwable?, - val logStacktrace: Boolean - ) -} diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/injection/FakeSdkObservabilityModule.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/injection/FakeSdkObservabilityModule.kt index 46685fb71..7b3dead86 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/injection/FakeSdkObservabilityModule.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/injection/FakeSdkObservabilityModule.kt @@ -5,15 +5,10 @@ import io.embrace.android.embracesdk.fakes.FakeProcessStateService import io.embrace.android.embracesdk.injection.SdkObservabilityModule import io.embrace.android.embracesdk.logging.EmbraceInternalErrorService import io.embrace.android.embracesdk.logging.InternalErrorService -import io.embrace.android.embracesdk.logging.InternalErrorServiceAction internal class FakeSdkObservabilityModule( override val internalErrorService: InternalErrorService = EmbraceInternalErrorService( FakeProcessStateService(), FakeClock() ) -) : SdkObservabilityModule { - - override val reportingLoggerAction: InternalErrorServiceAction - get() = TODO("Not yet implemented") -} +) : SdkObservabilityModule diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/SdkObservabilityModuleImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/SdkObservabilityModuleImplTest.kt index d75ee7e8e..ba9d3091c 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/SdkObservabilityModuleImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/SdkObservabilityModuleImplTest.kt @@ -13,6 +13,5 @@ internal class SdkObservabilityModuleImplTest { FakeEssentialServiceModule() ) assertNotNull(module.internalErrorService) - assertNotNull(module.reportingLoggerAction) } } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/logging/EmbLoggerImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/logging/EmbLoggerImplTest.kt index a1e6420d1..e73c7bab2 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/logging/EmbLoggerImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/logging/EmbLoggerImplTest.kt @@ -1,21 +1,20 @@ package io.embrace.android.embracesdk.logging -import io.embrace.android.embracesdk.fakes.FakeLogAction +import io.embrace.android.embracesdk.fakes.FakeEmbLogger import io.embrace.android.embracesdk.internal.ApkToolsConfig -import io.embrace.android.embracesdk.logging.EmbLoggerImpl.Severity import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull import org.junit.Before import org.junit.Test internal class EmbLoggerImplTest { - private val action = FakeLogAction() - private var logger = EmbLoggerImpl().apply { - addLoggerAction(action) - } + private lateinit var logger: FakeEmbLogger @Before fun setUp() { + logger = FakeEmbLogger() ApkToolsConfig.IS_DEVELOPER_LOGGING_ENABLED = false } @@ -25,9 +24,10 @@ internal class EmbLoggerImplTest { logger.logInfo("test") // then logger actions are triggered - val msg = action.msgQueue.single() - val expected = FakeLogAction.LogMessage("test", Severity.INFO, null, false) - assertEquals(expected, msg) + val msg = logger.infoMessages.single() + assertEquals("test", msg.msg) + assertNull(msg.throwable) + assertFalse(msg.logStacktrace) } @Test @@ -37,9 +37,10 @@ internal class EmbLoggerImplTest { logger.logWarning("test", throwable, false) // then logger actions are triggered - val msg = action.msgQueue.single() - val expected = FakeLogAction.LogMessage("test", Severity.WARNING, throwable, false) - assertEquals(expected, msg) + val msg = logger.warningMessages.single() + assertEquals("test", msg.msg) + assertEquals(throwable, msg.throwable) + assertFalse(msg.logStacktrace) } @Test @@ -52,8 +53,9 @@ internal class EmbLoggerImplTest { logger.logDebug("test", throwable) // then logger actions are triggered - val msg = action.msgQueue.single() - val expected = FakeLogAction.LogMessage("test", Severity.DEBUG, throwable, true) - assertEquals(expected, msg) + val msg = logger.debugMessages.single() + assertEquals("test", msg.msg) + assertEquals(throwable, msg.throwable) + assertFalse(msg.logStacktrace) } } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/logging/InternalErrorServiceActionTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/logging/InternalErrorServiceActionTest.kt deleted file mode 100644 index 91e3e9b92..000000000 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/logging/InternalErrorServiceActionTest.kt +++ /dev/null @@ -1,66 +0,0 @@ -package io.embrace.android.embracesdk.logging - -import io.embrace.android.embracesdk.fakes.FakeLogAction -import io.mockk.Called -import io.mockk.every -import io.mockk.mockk -import io.mockk.verify -import org.junit.Before -import org.junit.Test - -internal class InternalErrorServiceActionTest { - - private val exception = Exception() - private val errorMsg = "Error message" - private lateinit var internalErrorService: InternalErrorService - private lateinit var reportingLoggerAction: InternalErrorServiceAction - private lateinit var loggerAction: FakeLogAction - - private fun setupService() { - internalErrorService = mockk(relaxUnitFun = true) - reportingLoggerAction = InternalErrorServiceAction(internalErrorService) - } - - @Before - fun setUp() { - loggerAction = FakeLogAction() - } - - @Test - fun `do not report error if no throwable available`() { - setupService() - reportingLoggerAction.log(errorMsg, EmbLoggerImpl.Severity.DEBUG, null, true) - - verify { internalErrorService wasNot Called } - } - - @Test - fun `report error if throwable available`() { - setupService() - reportingLoggerAction.log(errorMsg, EmbLoggerImpl.Severity.DEBUG, exception, true) - - verify(exactly = 1) { internalErrorService.handleInternalError(exception) } - } - - @Test - fun `if an exception is thrown reporting error, swallow it`() { - setupService() - every { internalErrorService.handleInternalError(exception) } throws RuntimeException() - reportingLoggerAction.log(errorMsg, EmbLoggerImpl.Severity.DEBUG, exception, true) - verify(exactly = 1) { internalErrorService.handleInternalError(exception) } - } - - @Test - fun `if a throwable is not available with INFO severity then dont handle exception`() { - setupService() - reportingLoggerAction.log(errorMsg, EmbLoggerImpl.Severity.INFO, null, true) - verify(exactly = 0) { internalErrorService.handleInternalError(any() as Exception) } - } - - @Test - fun `if a throwable is available with ERROR severity`() { - setupService() - reportingLoggerAction.log(errorMsg, EmbLoggerImpl.Severity.ERROR, exception, true) - verify(exactly = 1) { internalErrorService.handleInternalError(exception) } - } -} diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/session/EmbraceProcessStateServiceTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/session/EmbraceProcessStateServiceTest.kt index 0896139b4..8b3c2007e 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/session/EmbraceProcessStateServiceTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/session/EmbraceProcessStateServiceTest.kt @@ -6,7 +6,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner import io.embrace.android.embracesdk.fakes.FakeClock -import io.embrace.android.embracesdk.fakes.FakeLogAction +import io.embrace.android.embracesdk.fakes.FakeInternalErrorService import io.embrace.android.embracesdk.fakes.FakeProcessStateListener import io.embrace.android.embracesdk.fakes.FakeSessionOrchestrator import io.embrace.android.embracesdk.fakes.system.mockLooper @@ -63,7 +63,7 @@ internal class EmbraceProcessStateServiceTest { } } - private lateinit var logger: FakeLogAction + private lateinit var fakeInternalErrorService: FakeInternalErrorService @Before fun before() { @@ -73,10 +73,10 @@ internal class EmbraceProcessStateServiceTest { constructorMocks = false, staticMocks = false ) - logger = FakeLogAction() + fakeInternalErrorService = FakeInternalErrorService() stateService = EmbraceProcessStateService( fakeClock, - EmbLoggerImpl().apply { addLoggerAction(logger) } + EmbLoggerImpl().apply { internalErrorService = fakeInternalErrorService } ) } @@ -201,7 +201,7 @@ internal class EmbraceProcessStateServiceTest { stateService.onForeground() stateService.onBackground() } - val messages = fetchLogMessages() + val messages = fakeInternalErrorService.throwables assertTrue(messages.isEmpty()) } @@ -213,7 +213,7 @@ internal class EmbraceProcessStateServiceTest { stateService.onBackground() stateService.onForeground() - val messages = fetchLogMessages().map { it.msg } + val messages = fakeInternalErrorService.throwables.map { it.message } assertEquals(2, messages.size) assertEquals( listOf( @@ -232,14 +232,10 @@ internal class EmbraceProcessStateServiceTest { stateService.onForeground() stateService.onBackground() - val messages = fetchLogMessages().map { it.msg } + val messages = fakeInternalErrorService.throwables.map { it.message } assertEquals(0, messages.size) } - private fun fetchLogMessages() = logger.msgQueue.filter { - it.severity >= EmbLoggerImpl.Severity.ERROR - } - private class DecoratedListener( private val invocations: MutableList ) : ProcessStateListener { diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/worker/WorkerThreadModuleImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/worker/WorkerThreadModuleImplTest.kt index 56f433b54..1959d616a 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/worker/WorkerThreadModuleImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/worker/WorkerThreadModuleImplTest.kt @@ -1,6 +1,6 @@ package io.embrace.android.embracesdk.worker -import io.embrace.android.embracesdk.fakes.FakeLogAction +import io.embrace.android.embracesdk.fakes.FakeInternalErrorService import io.embrace.android.embracesdk.fakes.injection.FakeCoreModule import io.embrace.android.embracesdk.injection.CoreModule import io.embrace.android.embracesdk.injection.InitModule @@ -8,21 +8,20 @@ import io.embrace.android.embracesdk.injection.InitModuleImpl import io.embrace.android.embracesdk.logging.EmbLoggerImpl import org.junit.Assert.assertNotNull import org.junit.Assert.assertSame -import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test internal class WorkerThreadModuleImplTest { - private lateinit var action: FakeLogAction + private lateinit var fakeInternalErrorService: FakeInternalErrorService private lateinit var logger: EmbLoggerImpl private lateinit var initModule: InitModule private lateinit var coreModule: CoreModule @Before fun setup() { - action = FakeLogAction() - logger = EmbLoggerImpl().apply { addLoggerAction(action) } + fakeInternalErrorService = FakeInternalErrorService() + logger = EmbLoggerImpl().apply { internalErrorService = fakeInternalErrorService } initModule = InitModuleImpl(logger = logger) coreModule = FakeCoreModule(logger = logger) } @@ -64,8 +63,6 @@ internal class WorkerThreadModuleImplTest { module.close() val future = worker.submit {} - val msg = action.msgQueue.single().msg - assertTrue(msg.startsWith("Rejected execution of")) assertNotNull(future) } }