From 594b6990fdf73a3640d465a0c6e307be488429dc Mon Sep 17 00:00:00 2001 From: ScottW514 Date: Thu, 10 Sep 2026 10:43:46 -0400 Subject: [PATCH] Stop a finished run's clock Run.snapshot() computed elapsed_s from the current time on every call, whether the run had ended or not. The page shows the last run until the next one starts, and it polls, so a finished run's figure went on counting: the result badge said FAIL beside a number still climbing, and the run read as still going. On the bench reference a test that ended after 5082 s was showing 5242 s and rising. The figure a finished run should carry was already recorded next to it: finished["duration_s"], fixed when the result was written. snapshot() now returns that once the run has ended, and the live count only while it is running. Host-proven: two unit tests - a finished run's clock reads its duration and does not move across a poll, a running one's still climbs. --- forgetest/forgetest/runner.py | 7 ++++++- forgetest/tests/test_queue.py | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/forgetest/forgetest/runner.py b/forgetest/forgetest/runner.py index cba12c6..7f50b82 100644 --- a/forgetest/forgetest/runner.py +++ b/forgetest/forgetest/runner.py @@ -164,7 +164,12 @@ class Run: notice = dict(self.notice) if self.notice else None return { "kind": self.kind, "id": self.id, "title": self.title, - "started": self.started_ts, "elapsed_s": int(time.time() - self.started), + # A finished run's clock stops: the page shows the last run + # until the next one starts, and a live figure there counts + # the time since, not the time it took. + "started": self.started_ts, + "elapsed_s": (self.finished["duration_s"] if self.finished + else int(time.time() - self.started)), "log": lines, "dropped": self.dropped, "prompt": prompt, "notice": notice, "finished": self.finished, "aborting": self.aborted.is_set(), } diff --git a/forgetest/tests/test_queue.py b/forgetest/tests/test_queue.py index fc333d2..591209f 100644 --- a/forgetest/tests/test_queue.py +++ b/forgetest/tests/test_queue.py @@ -84,6 +84,32 @@ class OrderTests(unittest.TestCase): self.assertEqual(sorted(out), ["s.a", "s.b"]) +class RunClockTests(unittest.TestCase): + """The page shows the last run until the next one starts, so a + finished run's elapsed figure must be the time it took, not the time + since. Found on the bench reference, where a failed test went on + counting past 5000 s and read as still running.""" + + def test_a_finished_runs_clock_stops(self): + from forgetest.runner import Run + run = Run("test", "t.x", "t.x") + run.started = time.time() - 30 + self.assertGreaterEqual(run.snapshot()["elapsed_s"], 30) + run.finished = {"result": "FAIL", "message": "", "duration_s": 31} + first = run.snapshot()["elapsed_s"] + time.sleep(1.1) + self.assertEqual(first, 31) + self.assertEqual(run.snapshot()["elapsed_s"], 31) + + def test_a_running_runs_clock_ticks(self): + from forgetest.runner import Run + run = Run("test", "t.x", "t.x") + run.started = time.time() - 5 + first = run.snapshot()["elapsed_s"] + time.sleep(1.1) + self.assertGreater(run.snapshot()["elapsed_s"], first) + + class QueueTests(unittest.TestCase): @classmethod def setUpClass(cls):