Exercise camera teardown despite RX or captured-image cleanup errors

This commit is contained in:
evgeny committed 2026-10-29 13:34:24 +01:00
1 parent ea121ac4e7
commit e9fa7ebb45
1 file changed
+22
@@ -21,6 +21,7 @@ class CallVideoEngineLifecycleTest {
private val engines = mutableListOf<CallVideoEngine>()
private val uncaught = CopyOnWriteArrayList<Throwable>()
private val gates = mutableListOf<CountDownLatch>()
private val images = mutableListOf<android.media.Image>()
private val manager get() = CameraManager.shared
private val main get() = Looper.getMainLooper()
@Before fun prepare() {
@@ -56,6 +57,7 @@ class CallVideoEngineLifecycleTest {
Handler.rejectDelayed = false; Handler.rejectImmediate = false
OrientationEventListener.failures = emptySet(); ChatApplication.instance.configProvider.failures = emptySet()
CallVideoNative.failures = emptySet(); CallVideoNative.onOpen = {}; CallVideoNative.onClose = {}
images.forEach { it.failures = emptySet() }
CallVideoCodec.onProbe = {}; CallVideoCodec.created.forEach { it.failures = emptySet() }
manager.failures = emptySet(); manager.autoClosed = true
manager.opened.forEachIndexed { index, open ->
@@ -110,6 +112,26 @@ class CallVideoEngineLifecycleTest {
encoder.failures = emptySet(); await("encoder release retries") { engine.stop() }
}
@Test fun rxReleaseFailureDoesNotKeepTheCameraOrEncoderRunning() {
val engine = capture(); CallVideoNative.failures = setOf("destroy")
assertThrows(IllegalStateException::class.java) { engine.stop() }
await("TX camera and encoder close despite RX error") {
manager.opened.single().device.closed && CallVideoCodec.created.all { it.closed }
}
assertTrue(7L in CallVideoNative.ports)
CallVideoNative.failures = emptySet(); await("RX retry allows final native close") { engine.stop() }
}
@Test fun cameraImageReleaseFailureIsContainedAndRetainedUntilRetry() {
val engine = capture(); val image = android.media.Image().also { images.add(it); it.failures = setOf("close") }
ImageReader.created.single().push(image)
await("image failure disables capture") { !engine.state.value.settings.enabled }
await("image failure closes camera independently") { manager.opened.single().device.closed }
assertTrue(thread(engine).isAlive); assertFalse(engine.stop()); assertFalse(image.closed)
image.failures = emptySet(); await("image retry allows acknowledged stop") { engine.stop() }
assertTrue(image.closed)
}
@Test fun settingsSaveFailureIsContainedAndDoesNotApplyAnUncommittedSelection() {
val engine = engine(); val previous = engine.state.value.settings
ChatApplication.instance.configProvider.failures = setOf("settings save")