mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-16 11:16:12 -04:00
test(debug): Stop leaked recorders in the recorder-module test harness
The realtime harness cancelled its module scope but never stopped the recorder, and cancelling a scope does not uninstall a running recorder's globally installed FileLogger. A test that started a recording therefore left one writing into every test that followed, and an assertion failing before the explicit stop did the same. The harness now stops the module in a nested finally and fails its own test if a file logger survived, removing the straggler afterwards so a single leak cannot cascade. The tracked-recording test gets the same finally treatment.
This commit is contained in:
+28
-8
@@ -39,6 +39,7 @@ import org.robolectric.annotation.Config
|
|||||||
import testhelpers.BaseTest
|
import testhelpers.BaseTest
|
||||||
import testhelpers.TestApplication
|
import testhelpers.TestApplication
|
||||||
import testhelpers.coroutine.TestDispatcherProvider
|
import testhelpers.coroutine.TestDispatcherProvider
|
||||||
|
import java.io.File
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
@@ -95,12 +96,25 @@ class RecorderModuleDiagnosticsTest : BaseTest() {
|
|||||||
block: suspend (RecorderModule) -> Unit,
|
block: suspend (RecorderModule) -> Unit,
|
||||||
) {
|
) {
|
||||||
val moduleScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
val moduleScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||||
|
val fileLoggersBefore = Logging.loggers.filterIsInstance<FileLogger>()
|
||||||
|
var module: RecorderModule? = null
|
||||||
try {
|
try {
|
||||||
val module = buildModule(moduleScope, upgradeDiagnostics, TestDispatcherProvider(Dispatchers.IO))
|
try {
|
||||||
module.headerReadTimeoutMs = headerTimeoutMs
|
module = buildModule(moduleScope, upgradeDiagnostics, TestDispatcherProvider(Dispatchers.IO))
|
||||||
runBlocking { block(module) }
|
.apply { headerReadTimeoutMs = headerTimeoutMs }
|
||||||
|
runBlocking { block(module) }
|
||||||
|
} finally {
|
||||||
|
// Stop before cancelling: scope cancellation does NOT uninstall a running
|
||||||
|
// recorder's global FileLogger.
|
||||||
|
module?.let { runBlocking { it.stopRecorder() } }
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
moduleScope.cancel()
|
moduleScope.cancel()
|
||||||
|
// A leaked logger must fail THIS test, not poison later ones. Remove stragglers after
|
||||||
|
// asserting so one failure can't cascade.
|
||||||
|
val leaked = Logging.loggers.filterIsInstance<FileLogger>() - fileLoggersBefore.toSet()
|
||||||
|
leaked.forEach { Logging.remove(it) }
|
||||||
|
leaked shouldBe emptyList<FileLogger>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,11 +125,17 @@ class RecorderModuleDiagnosticsTest : BaseTest() {
|
|||||||
|
|
||||||
val module = buildModule(backgroundScope, diagnostics)
|
val module = buildModule(backgroundScope, diagnostics)
|
||||||
|
|
||||||
val logDir = module.startRecorder()
|
// Stopped in a finally: an assertion failing mid-test must not leave a live recorder whose
|
||||||
logDir.exists() shouldBe true
|
// globally installed FileLogger then writes into every later test.
|
||||||
module.state.first { it.isRecording }.currentLogDir shouldBe logDir
|
var stopped: File? = null
|
||||||
|
try {
|
||||||
module.stopRecorder().shouldNotBeNull()
|
val logDir = module.startRecorder()
|
||||||
|
logDir.exists() shouldBe true
|
||||||
|
module.state.first { it.isRecording }.currentLogDir shouldBe logDir
|
||||||
|
} finally {
|
||||||
|
stopped = module.stopRecorder()
|
||||||
|
}
|
||||||
|
stopped.shouldNotBeNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user