From 5f4d8ba747dee47f30c509cbe9d41dd4532df397 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 6 May 2026 00:42:14 +0000 Subject: [PATCH] test(quartz): widen NIP-40 expiration buffer to outlive insert race The reject_expired_events trigger checks NEW.expiration <= unixepoch() at insert time, so signing/insert latency on a slow runner could push unixepoch() to time+1 before the row was committed, raising SQLiteException at runBlocking entry. Bumping the short event to time+5 with a matching delay(6000) mirrors ExpirationTest.testDeletingExpiredEvents and gives the trigger room to breathe without changing the behavior under test. --- .../cache/projection/EventStoreProjectionTest.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/cache/projection/EventStoreProjectionTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/cache/projection/EventStoreProjectionTest.kt index 126cac4d8..7d97d35af 100644 --- a/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/cache/projection/EventStoreProjectionTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/cache/projection/EventStoreProjectionTest.kt @@ -401,7 +401,11 @@ class EventStoreProjectionTest { val time = TimeUtils.now() val safe = signer.sign(TextNoteEvent.build("safe", createdAt = time) { expiration(time + 100) }) observable.insert(safe) - val short = signer.sign(TextNoteEvent.build("short", createdAt = time) { expiration(time + 1) }) + // The SQL trigger rejects an insert whose expiration is + // already <= unixepoch(), so this buffer must comfortably + // outlive any signing/insert latency. Mirrors the pattern + // in ExpirationTest.testDeletingExpiredEvents. + val short = signer.sign(TextNoteEvent.build("short", createdAt = time) { expiration(time + 5) }) observable.insert(short) val projection = @@ -412,7 +416,7 @@ class EventStoreProjectionTest { // Let the short expiration lapse, then ask the store to // sweep — the projection drops the expired slot in // response to the resulting StoreChange.Delete(Expired). - delay(2000) + delay(6000) observable.deleteExpiredEvents() val after = projection.awaitItems { it.size == 1 }