From d92d4c1a14fd282b69dea527789b660905bcefac Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Sat, 4 Jul 2026 21:09:22 -0500 Subject: [PATCH] feat(logging): stragglers -> AppLog (#330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate RestartActivity's one raw Log.w site to AppLog, clearing the final raw android.util.Log site outside the auth/lock, DB/keystore, connectivity/send, and sync-engine migration areas so the codebase is ready for the detekt android.util.Log guard (#331). RestartActivity runs in the separate :restart trampoline process, where LibreMailApplication.onCreate returns early and never calls AppLog.install, so this breadcrumb reaches Logcat only, never a DebugReport. The migration is guard-compliance + Logcat-consistency only; behavior is unchanged since AppLog forwards to Logcat. RestartActivity is DEVICE-ONLY (multi-process kill/relaunch), so a JVM buffer-capture test doesn't apply here. Added RestartActivityLoggingTest, which instead pins the null-buffer shape this call runs under in the trampoline process: it forwards to Logcat and no-ops the buffer cleanly. Closes #330 Part of #324 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 --- .../org/libremail/restart/RestartActivity.kt | 7 ++- .../restart/RestartActivityLoggingTest.kt | 52 +++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 app/src/test/kotlin/org/libremail/restart/RestartActivityLoggingTest.kt diff --git a/app/src/main/kotlin/org/libremail/restart/RestartActivity.kt b/app/src/main/kotlin/org/libremail/restart/RestartActivity.kt index 3144024..c6467ff 100644 --- a/app/src/main/kotlin/org/libremail/restart/RestartActivity.kt +++ b/app/src/main/kotlin/org/libremail/restart/RestartActivity.kt @@ -5,7 +5,7 @@ import android.app.Activity import android.content.Intent import android.os.Bundle import android.os.Process -import android.util.Log +import org.libremail.reporting.AppLog /** * Separate-process trampoline that performs an app relaunch from OUTSIDE the process being killed. @@ -40,7 +40,10 @@ class RestartActivity : Activity() { if (launchIntent != null) { startActivity(launchIntent) } else { - Log.w(TAG, "no launch intent for $packageName; cannot relaunch after restart") + // Logcat-only here: this runs in the ":restart" trampoline process, where + // LibreMailApplication.onCreate returns early and never calls AppLog.install, so the + // buffer is null and this breadcrumb never reaches a DebugReport. + AppLog.w(TAG, "no launch intent for $packageName; cannot relaunch after restart") } finish() diff --git a/app/src/test/kotlin/org/libremail/restart/RestartActivityLoggingTest.kt b/app/src/test/kotlin/org/libremail/restart/RestartActivityLoggingTest.kt new file mode 100644 index 0000000..cbc427d --- /dev/null +++ b/app/src/test/kotlin/org/libremail/restart/RestartActivityLoggingTest.kt @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +package org.libremail.restart + +import android.util.Log +import io.mockk.every +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import io.mockk.verify +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.libremail.reporting.AppLog +import kotlin.test.assertNull + +/** + * Pins the #330 migration of [RestartActivity]'s one log site from raw `Log.w` to [AppLog.w]. + * [RestartActivity] itself is DEVICE-ONLY (multi-process kill/relaunch; see its KDoc) and can't be + * exercised in a JVM test, so this characterizes the call it now makes instead of the class itself. + * + * That call runs in the ":restart" trampoline process, where `LibreMailApplication.onCreate` returns + * early and never reaches `AppLog.install` — so [AppLog]'s buffer is null there, and this breadcrumb + * reaches Logcat only, never a `DebugReport`. This is the one migrated site in the #324 epic whose + * "buffer captured the breadcrumb" assertion intentionally does not apply (see #330); instead this + * asserts the null-buffer shape: the call still forwards to Logcat and no-ops cleanly, matching the + * raw `Log.w` behavior it replaced. + */ +class RestartActivityLoggingTest { + + // Mirrors RestartActivity's private TAG/message exactly (kept private there; duplicated here + // rather than widening its visibility just for this test). + private val tag = "LibreMailRestart" + private val message = "no launch intent for org.libremail.app; cannot relaunch after restart" + + @Before + fun setUp() { + mockkStatic(Log::class) + every { Log.w(any(), any()) } returns 0 + AppLog::class.java.getDeclaredField("buffer").apply { isAccessible = true }.set(AppLog, null) + } + + @After + fun tearDown() = unmockkAll() + + @Test + fun `RestartActivity's no-launch-intent warning forwards to Logcat and no-ops with no buffer installed`() { + AppLog.w(tag, message) + + verify { Log.w(tag, message) } + val bufferField = AppLog::class.java.getDeclaredField("buffer").apply { isAccessible = true } + assertNull(bufferField.get(AppLog), "the :restart process never installs a buffer; AppLog must not create one") + } +}