예제 #1
0
    def test_cancel_can_be_called_multiple_times(self):
        timer = _PeriodicTimer(timedelta(seconds=1), lambda: None)

        timer.start()

        timer.cancel()
        timer.cancel()
예제 #2
0
    def test_timer_calls_background_thread_at_regular_intervals(self) -> None:
        timer_begin_time: float

        # Call our function every 200ms.
        call_interval = 0.2

        # Keep the log of intervals between each consecutive call.
        actual_call_intervals: List[float] = []

        # Keep the number of times the function was called.
        call_count = 0

        # In order to prevent a flaky test instead of asserting that the
        # function was called an exact number of times we use a lower bound
        # that is guaranteed to be true for a correct implementation.
        min_required_call_count = 4

        timer_stop_event = threading.Event()

        def log_call(self):
            nonlocal timer_begin_time, call_count

            actual_call_intervals.append(time.monotonic() - timer_begin_time)

            call_count += 1
            if call_count == min_required_call_count:
                timer_stop_event.set()

            timer_begin_time = time.monotonic()

        timer = _PeriodicTimer(timedelta(seconds=call_interval), log_call, self)

        timer_begin_time = time.monotonic()

        timer.start()

        # Although this is theoretically non-deterministic, if our timer, which
        # has a 200ms call interval, does not get called 4 times in 60 seconds,
        # there is very likely something else going on.
        timer_stop_event.wait(60)

        timer.cancel()

        self.longMessage = False

        self.assertGreaterEqual(
            call_count,
            min_required_call_count,
            f"The function has been called {call_count} time(s) but expected to be called at least "
            f"{min_required_call_count} time(s).",
        )

        for actual_call_interval in actual_call_intervals:
            self.assertGreaterEqual(
                actual_call_interval,
                call_interval,
                f"The interval between two function calls was {actual_call_interval} second(s) but "
                f"expected to be at least {call_interval} second(s).",
            )
예제 #3
0
    def test_set_name_cannot_be_called_after_start(self) -> None:
        timer = _PeriodicTimer(timedelta(seconds=1), lambda: None)

        timer.start()

        with self.assertRaisesRegex(RuntimeError, r"^The timer has already started.$"):
            timer.set_name("dummy_name")

        timer.cancel()
예제 #4
0
    def test_start_can_be_called_only_once(self) -> None:
        timer = _PeriodicTimer(timedelta(seconds=1), lambda: None)

        timer.start()

        with self.assertRaisesRegex(RuntimeError, r"^The timer has already started.$"):
            timer.start()

        timer.cancel()
예제 #5
0
    def test_delete_stops_background_thread(self):
        timer = _PeriodicTimer(timedelta(seconds=1), lambda: None)

        timer.start()

        self.assertTrue(any(t.name == "PeriodicTimer" for t in threading.enumerate()))

        del timer

        self.assertTrue(all(t.name != "PeriodicTimer" for t in threading.enumerate()))
예제 #6
0
    def test_delete_stops_background_thread(self) -> None:
        name = "PeriodicTimer_DeleteStopsBackgroundThreadTest"

        timer = _PeriodicTimer(timedelta(seconds=1), lambda: None)

        timer.set_name(name)

        timer.start()

        self.assertTrue(any(t.name == name for t in threading.enumerate()))

        del timer

        self.assertTrue(all(t.name != name for t in threading.enumerate()))