@@ -20,6 +20,10 @@ static constexpr kj::Date twoMs = 2 * kj::MILLISECONDS + kj::UNIX_EPOCH;
2020static constexpr kj::Date threeMs = 3 * kj::MILLISECONDS + kj::UNIX_EPOCH;
2121static constexpr kj::Date fourMs = 4 * kj::MILLISECONDS + kj::UNIX_EPOCH;
2222static constexpr kj::Date fiveMs = 5 * kj::MILLISECONDS + kj::UNIX_EPOCH;
23+ // Used as the "current time" parameter for armAlarmHandler in tests.
24+ // Set to epoch (before all test alarm times) so existing tests aren't affected by
25+ // the overdue alarm check.
26+ static constexpr kj::Date testCurrentTime = kj::UNIX_EPOCH;
2327
2428template <typename T>
2529kj::Promise<T> eagerlyReportExceptions (kj::Promise<T> promise, kj::SourceLocation location = {}) {
@@ -586,7 +590,7 @@ KJ_TEST("tells alarm handler to cancel when committed alarm is empty") {
586590 ActorSqliteTest test;
587591
588592 {
589- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
593+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
590594 // We expect armAlarmHandler() to tell us to cancel the alarm.
591595 KJ_ASSERT (armResult.is <ActorCache::CancelAlarmHandler>());
592596 auto waitPromise = kj::mv (armResult.get <ActorCache::CancelAlarmHandler>().waitBeforeCancel );
@@ -612,7 +616,7 @@ KJ_TEST("tells alarm handler to reschedule when handler alarm is later than comm
612616 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
613617
614618 // Request handler run at 2ms. Expect cancellation with rescheduling.
615- auto armResult = test.actor .armAlarmHandler (twoMs, nullptr );
619+ auto armResult = test.actor .armAlarmHandler (twoMs, nullptr , testCurrentTime );
616620 KJ_ASSERT (armResult.is <ActorSqlite::CancelAlarmHandler>());
617621 auto cancelResult = kj::mv (armResult.get <ActorSqlite::CancelAlarmHandler>());
618622
@@ -636,7 +640,7 @@ KJ_TEST("tells alarm handler to reschedule when handler alarm is earlier than co
636640 KJ_ASSERT (expectSync (test.getAlarm ()) == twoMs);
637641
638642 // Expect that armAlarmHandler() tells caller to cancel after rescheduling completes.
639- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
643+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
640644 KJ_ASSERT (armResult.is <ActorSqlite::CancelAlarmHandler>());
641645 auto cancelResult = kj::mv (armResult.get <ActorSqlite::CancelAlarmHandler>());
642646
@@ -649,6 +653,32 @@ KJ_TEST("tells alarm handler to reschedule when handler alarm is earlier than co
649653 waitBeforeCancel.wait (test.ws );
650654}
651655
656+ KJ_TEST (" runs overdue alarm immediately when local alarm time is in the past" ) {
657+ ActorSqliteTest test;
658+
659+ // Initialize alarm state to 2ms.
660+ test.setAlarm (twoMs);
661+ test.pollAndExpectCalls ({" scheduleRun(2ms)" })[0 ]->fulfill ();
662+ test.pollAndExpectCalls ({" commit" })[0 ]->fulfill ();
663+ test.pollAndExpectCalls ({});
664+ KJ_ASSERT (expectSync (test.getAlarm ()) == twoMs);
665+
666+ // The local state says the alarm is due to fire at 2ms, but we're saying the AlarmManager has 1ms,
667+ // usually this would result in a rescheduling of the alarm, but since our currentTime is 5ms, we
668+ // will just run the alarm now since it's already overdue.
669+ {
670+ auto overdueCurrentTime = fiveMs;
671+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , overdueCurrentTime);
672+
673+ // Should run the handler immediately instead of canceling/rescheduling.
674+ KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
675+ }
676+
677+ // commit and delete the alarm after we drop the alarm handler (this is a deferred delete).
678+ test.pollAndExpectCalls ({" commit" })[0 ]->fulfill ();
679+ test.pollAndExpectCalls ({" scheduleRun(none)" })[0 ]->fulfill ();
680+ }
681+
652682KJ_TEST (" does not cancel handler when local db alarm state is later than scheduled alarm" ) {
653683 ActorSqliteTest test;
654684
@@ -661,7 +691,7 @@ KJ_TEST("does not cancel handler when local db alarm state is later than schedul
661691
662692 test.setAlarm (twoMs);
663693 {
664- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
694+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
665695 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
666696 }
667697 test.pollAndExpectCalls ({" commit" })[0 ]->fulfill ();
@@ -680,7 +710,7 @@ KJ_TEST("does not cancel handler when local db alarm state is earlier than sched
680710
681711 test.setAlarm (oneMs);
682712 {
683- auto armResult = test.actor .armAlarmHandler (twoMs, nullptr );
713+ auto armResult = test.actor .armAlarmHandler (twoMs, nullptr , testCurrentTime );
684714 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
685715 }
686716 test.pollAndExpectCalls ({" scheduleRun(1ms)" })[0 ]->fulfill ();
@@ -698,7 +728,7 @@ KJ_TEST("getAlarm() returns null during handler") {
698728 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
699729
700730 {
701- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
731+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
702732 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
703733 test.pollAndExpectCalls ({});
704734
@@ -719,7 +749,7 @@ KJ_TEST("alarm handler handle clears alarm when dropped with no writes") {
719749 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
720750
721751 {
722- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
752+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
723753 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
724754 }
725755 test.pollAndExpectCalls ({" commit" })[0 ]->fulfill ();
@@ -738,7 +768,7 @@ KJ_TEST("alarm deleter does not clear alarm when dropped with writes") {
738768 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
739769
740770 {
741- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
771+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
742772 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
743773 test.setAlarm (twoMs);
744774 }
@@ -759,7 +789,7 @@ KJ_TEST("can cancel deferred alarm deletion during handler") {
759789 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
760790
761791 {
762- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
792+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
763793 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
764794 test.actor .cancelDeferredAlarmDeletion ();
765795 }
@@ -778,7 +808,7 @@ KJ_TEST("canceling deferred alarm deletion outside handler has no effect") {
778808 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
779809
780810 {
781- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
811+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
782812 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
783813 }
784814 test.pollAndExpectCalls ({" commit" })[0 ]->fulfill ();
@@ -803,7 +833,7 @@ KJ_TEST("canceling deferred alarm deletion outside handler edge case") {
803833 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
804834
805835 {
806- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
836+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
807837 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
808838 }
809839 test.actor .cancelDeferredAlarmDeletion ();
@@ -825,7 +855,7 @@ KJ_TEST("canceling deferred alarm deletion is idempotent") {
825855 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
826856
827857 {
828- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
858+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
829859 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
830860 test.actor .cancelDeferredAlarmDeletion ();
831861 test.actor .cancelDeferredAlarmDeletion ();
@@ -846,7 +876,7 @@ KJ_TEST("alarm handler cleanup succeeds when output gate is broken") {
846876 test.pollAndExpectCalls ({});
847877 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
848878
849- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
879+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
850880 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
851881 auto deferredDelete = kj::mv (armResult.get <ActorSqlite::RunAlarmHandler>().deferredDelete );
852882
@@ -893,7 +923,7 @@ KJ_TEST("handler alarm is not deleted when commit fails") {
893923 KJ_ASSERT (expectSync (test.getAlarm ()) == oneMs);
894924
895925 {
896- auto armResult = test.actor .armAlarmHandler (oneMs, nullptr );
926+ auto armResult = test.actor .armAlarmHandler (oneMs, nullptr , testCurrentTime );
897927 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
898928
899929 KJ_ASSERT (expectSync (test.getAlarm ()) == kj::none);
@@ -1340,7 +1370,7 @@ KJ_TEST("rolling back transaction leaves deferred alarm deletion in expected sta
13401370 KJ_ASSERT (expectSync (test.getAlarm ()) == twoMs);
13411371
13421372 {
1343- auto armResult = test.actor .armAlarmHandler (twoMs, nullptr );
1373+ auto armResult = test.actor .armAlarmHandler (twoMs, nullptr , testCurrentTime );
13441374 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
13451375
13461376 auto txn = test.actor .startTransaction ();
@@ -1373,7 +1403,7 @@ KJ_TEST("committing transaction leaves deferred alarm deletion in expected state
13731403 KJ_ASSERT (expectSync (test.getAlarm ()) == twoMs);
13741404
13751405 {
1376- auto armResult = test.actor .armAlarmHandler (twoMs, nullptr );
1406+ auto armResult = test.actor .armAlarmHandler (twoMs, nullptr , testCurrentTime );
13771407 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
13781408
13791409 auto txn = test.actor .startTransaction ();
@@ -1404,7 +1434,7 @@ KJ_TEST("rolling back nested transaction leaves deferred alarm deletion in expec
14041434 KJ_ASSERT (expectSync (test.getAlarm ()) == twoMs);
14051435
14061436 {
1407- auto armResult = test.actor .armAlarmHandler (twoMs, nullptr );
1437+ auto armResult = test.actor .armAlarmHandler (twoMs, nullptr , testCurrentTime );
14081438 KJ_ASSERT (armResult.is <ActorSqlite::RunAlarmHandler>());
14091439
14101440 auto txn1 = test.actor .startTransaction ();
0 commit comments