@@ -22,6 +22,10 @@ static constexpr kj::Date twoMs = 2 * kj::MILLISECONDS + kj::UNIX_EPOCH;
2222static constexpr kj::Date threeMs = 3 * kj::MILLISECONDS + kj::UNIX_EPOCH;
2323static constexpr kj::Date fourMs = 4 * kj::MILLISECONDS + kj::UNIX_EPOCH;
2424static constexpr kj::Date fiveMs = 5 * kj::MILLISECONDS + kj::UNIX_EPOCH;
25+ // Used as the "current time" parameter for armAlarmHandler in tests.
26+ // Set to epoch (before all test alarm times) so existing tests aren't affected by
27+ // the overdue alarm check.
28+ static constexpr kj::Date testCurrentTime = kj::UNIX_EPOCH;
2529
2630template <typename T>
2731kj::Promise<T> eagerlyReportExceptions (kj::Promise<T> promise, kj::SourceLocation location = {}) {
@@ -588,7 +592,7 @@ KJ_TEST("tells alarm handler to cancel when committed alarm is empty") {
588592 ActorSqliteTest test;
589593
590594 {
591- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
595+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
592596 // We expect armAlarmHandler() to tell us to cancel the alarm.
593597 KJ_ASSERT (armResult.is <ActorCache::CancelAlarmHandler>());
594598 auto waitPromise = kj::mv (armResult.get <ActorCache::CancelAlarmHandler>().waitBeforeCancel );
@@ -614,7 +618,7 @@ KJ_TEST("tells alarm handler to reschedule when handler alarm is later than comm
614618 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
615619
616620 // Request handler run at 2ms. Expect cancellation with rescheduling.
617- auto armResult = test.actor .armAlarmHandler (twoMs, nullptr );
621+ auto armResult = test.actor .armAlarmHandler (twoMs, nullptr , testCurrentTime );
618622 KJ_ASSERT (armResult.is <ActorSqlite::CancelAlarmHandler>());
619623 auto cancelResult = kj::mv (armResult.get <ActorSqlite::CancelAlarmHandler>());
620624
@@ -638,7 +642,7 @@ KJ_TEST("tells alarm handler to reschedule when handler alarm is earlier than co
638642 KJ_ASSERT (expectSync (test.getAlarm ()) == twoMs);
639643
640644 // Expect that armAlarmHandler() tells caller to cancel after rescheduling completes.
641- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
645+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
642646 KJ_ASSERT (armResult.is <ActorSqlite::CancelAlarmHandler>());
643647 auto cancelResult = kj::mv (armResult.get <ActorSqlite::CancelAlarmHandler>());
644648
@@ -651,6 +655,32 @@ KJ_TEST("tells alarm handler to reschedule when handler alarm is earlier than co
651655 waitBeforeCancel.wait (test.ws );
652656}
653657
658+ KJ_TEST (" runs overdue alarm immediately when local alarm time is in the past" ) {
659+ ActorSqliteTest test;
660+
661+ // Initialize alarm state to 2ms.
662+ test.setAlarm (twoMs);
663+ test.pollAndExpectCalls ({" scheduleRun(2ms)" })[0 ]->fulfill ();
664+ test.pollAndExpectCalls ({" commit" })[0 ]->fulfill ();
665+ test.pollAndExpectCalls ({});
666+ KJ_ASSERT (expectSync (test.getAlarm ()) == twoMs);
667+
668+ // The local state says the alarm is due to fire at 2ms, but we're saying the AlarmManager has 1ms,
669+ // usually this would result in a rescheduling of the alarm, but since our currentTime is 5ms, we
670+ // will just run the alarm now since it's already overdue.
671+ {
672+ auto overdueCurrentTime = fiveMs;
673+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , overdueCurrentTime);
674+
675+ // Should run the handler immediately instead of canceling/rescheduling.
676+ KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
677+ }
678+
679+ // commit and delete the alarm after we drop the alarm handler (this is a deferred delete).
680+ test.pollAndExpectCalls ({" commit" })[0 ]->fulfill ();
681+ test.pollAndExpectCalls ({" scheduleRun(none)" })[0 ]->fulfill ();
682+ }
683+
654684KJ_TEST (" does not cancel handler when local db alarm state is later than scheduled alarm" ) {
655685 ActorSqliteTest test;
656686
@@ -663,7 +693,7 @@ KJ_TEST("does not cancel handler when local db alarm state is later than schedul
663693
664694 test.setAlarm (twoMs);
665695 {
666- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
696+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
667697 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
668698 }
669699 test.pollAndExpectCalls ({" commit" })[0 ]->fulfill ();
@@ -682,7 +712,7 @@ KJ_TEST("does not cancel handler when local db alarm state is earlier than sched
682712
683713 test.setAlarm (oneMs);
684714 {
685- auto armResult = test.actor .armAlarmHandler (twoMs, nullptr );
715+ auto armResult = test.actor .armAlarmHandler (twoMs, nullptr , testCurrentTime );
686716 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
687717 }
688718 test.pollAndExpectCalls ({" scheduleRun(1ms)" })[0 ]->fulfill ();
@@ -700,7 +730,7 @@ KJ_TEST("getAlarm() returns null during handler") {
700730 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
701731
702732 {
703- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
733+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
704734 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
705735 test.pollAndExpectCalls ({});
706736
@@ -721,7 +751,7 @@ KJ_TEST("alarm handler handle clears alarm when dropped with no writes") {
721751 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
722752
723753 {
724- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
754+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
725755 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
726756 }
727757 test.pollAndExpectCalls ({" commit" })[0 ]->fulfill ();
@@ -740,7 +770,7 @@ KJ_TEST("alarm deleter does not clear alarm when dropped with writes") {
740770 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
741771
742772 {
743- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
773+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
744774 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
745775 test.setAlarm (twoMs);
746776 }
@@ -761,7 +791,7 @@ KJ_TEST("can cancel deferred alarm deletion during handler") {
761791 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
762792
763793 {
764- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
794+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
765795 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
766796 test.actor .cancelDeferredAlarmDeletion ();
767797 }
@@ -780,7 +810,7 @@ KJ_TEST("canceling deferred alarm deletion outside handler has no effect") {
780810 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
781811
782812 {
783- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
813+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
784814 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
785815 }
786816 test.pollAndExpectCalls ({" commit" })[0 ]->fulfill ();
@@ -805,7 +835,7 @@ KJ_TEST("canceling deferred alarm deletion outside handler edge case") {
805835 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
806836
807837 {
808- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
838+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
809839 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
810840 }
811841 test.actor .cancelDeferredAlarmDeletion ();
@@ -827,7 +857,7 @@ KJ_TEST("canceling deferred alarm deletion is idempotent") {
827857 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
828858
829859 {
830- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
860+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
831861 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
832862 test.actor .cancelDeferredAlarmDeletion ();
833863 test.actor .cancelDeferredAlarmDeletion ();
@@ -848,7 +878,7 @@ KJ_TEST("alarm handler cleanup succeeds when output gate is broken") {
848878 test.pollAndExpectCalls ({});
849879 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
850880
851- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
881+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
852882 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
853883 auto deferredDelete = kj::mv (armResult.get <ActorSqlite::RunAlarmHandler>().deferredDelete );
854884
@@ -895,7 +925,7 @@ KJ_TEST("handler alarm is not deleted when commit fails") {
895925 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
896926
897927 {
898- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
928+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
899929 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
900930
901931 KJ_ASSERT (expectSync (test.getAlarm ()) == kj::none);
@@ -1342,7 +1372,7 @@ KJ_TEST("rolling back transaction leaves deferred alarm deletion in expected sta
13421372 KJ_ASSERT (expectSync (test.getAlarm ()) == twoMs);
13431373
13441374 {
1345- auto armResult = test.actor .armAlarmHandler (twoMs, nullptr );
1375+ auto armResult = test.actor .armAlarmHandler (twoMs, nullptr , testCurrentTime );
13461376 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
13471377
13481378 auto txn = test.actor .startTransaction ();
@@ -1375,7 +1405,7 @@ KJ_TEST("committing transaction leaves deferred alarm deletion in expected state
13751405 KJ_ASSERT (expectSync (test.getAlarm ()) == twoMs);
13761406
13771407 {
1378- auto armResult = test.actor .armAlarmHandler (twoMs, nullptr );
1408+ auto armResult = test.actor .armAlarmHandler (twoMs, nullptr , testCurrentTime );
13791409 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
13801410
13811411 auto txn = test.actor .startTransaction ();
@@ -1406,7 +1436,7 @@ KJ_TEST("rolling back nested transaction leaves deferred alarm deletion in expec
14061436 KJ_ASSERT (expectSync (test.getAlarm ()) == twoMs);
14071437
14081438 {
1409- auto armResult = test.actor .armAlarmHandler (twoMs, nullptr );
1439+ auto armResult = test.actor .armAlarmHandler (twoMs, nullptr , testCurrentTime );
14101440 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
14111441
14121442 auto txn1 = test.actor .startTransaction ();
0 commit comments