diff --git a/app/src/main/java/com/m57/hermescontrol/notification/NotificationReplyReceiver.kt b/app/src/main/java/com/m57/hermescontrol/notification/NotificationReplyReceiver.kt index 12407c10..d7cac71b 100644 --- a/app/src/main/java/com/m57/hermescontrol/notification/NotificationReplyReceiver.kt +++ b/app/src/main/java/com/m57/hermescontrol/notification/NotificationReplyReceiver.kt @@ -53,22 +53,24 @@ open class NotificationReplyReceiver : BroadcastReceiver() { val pendingResult = goAsyncCompat() kotlinx.coroutines.CoroutineScope(kotlinx.coroutines.Dispatchers.IO).launch { try { - val db = - com.m57.hermescontrol.data.local.HermesDatabase - .get(context) - val dao = db.chatMessageDao() - val entity = - com.m57.hermescontrol.data.local.ChatMessageEntity( - id = - java.util.UUID - .randomUUID() - .toString(), - sessionId = sessionId, - role = "USER", - content = replyText, - timestamp = System.currentTimeMillis(), - ) - dao.upsert(entity) + kotlinx.coroutines.withTimeout(5000L) { + val db = + com.m57.hermescontrol.data.local.HermesDatabase + .get(context) + val dao = db.chatMessageDao() + val entity = + com.m57.hermescontrol.data.local.ChatMessageEntity( + id = + java.util.UUID + .randomUUID() + .toString(), + sessionId = sessionId, + role = "USER", + content = replyText, + timestamp = System.currentTimeMillis(), + ) + dao.upsert(entity) + } } catch (e: Exception) { android.util.Log.e("NotificationReply", "Failed to save replied message to Room DB", e) } finally { diff --git a/app/src/test/java/com/m57/hermescontrol/notification/NotificationReplyReceiverTest.kt b/app/src/test/java/com/m57/hermescontrol/notification/NotificationReplyReceiverTest.kt index 4d197d45..8d17930b 100644 --- a/app/src/test/java/com/m57/hermescontrol/notification/NotificationReplyReceiverTest.kt +++ b/app/src/test/java/com/m57/hermescontrol/notification/NotificationReplyReceiverTest.kt @@ -252,6 +252,27 @@ class NotificationReplyReceiverTest { verify { mockPendingResult.finish() } } + @Test + fun `Room hang triggers timeout and finishes pending result`() { + givenValidReply("session-abc", "Hello") + + // Make upsert hang indefinitely + coEvery { mockDao.upsert(any()) } coAnswers { + kotlinx.coroutines.delay(10000) + } + + receiver.onReceive(mockContext, mockIntent) + + // Wait longer than the 5-second timeout, but less than the 10-second delay + Thread.sleep(6000) + + // Timeout should be caught in catch block and logged + verify { android.util.Log.e("NotificationReply", any(), any()) } + + // Pending result must still finish after timeout + verify { mockPendingResult.finish() } + } + // ── Helpers ──────────────────────────────────────────────────────────── private fun givenValidReply(