import datetime
import queue
import pytest
import time

from dateutil.tz import gettz
from mock import patch

test_timeout = 10
cron_queue = queue.Queue()


class MockDatetime(datetime.datetime):
    timedelta = datetime.timedelta()

    @classmethod
    def now(cls):
        return super().now(tz=gettz()) + cls.timedelta


def _test_cron_queue(expected_msg: str):
    msg = None
    test_start = time.time()
    while time.time() - test_start <= test_timeout and msg != expected_msg:
        try:
            msg = cron_queue.get(block=True, timeout=test_timeout)
        except queue.Empty:
            break

    assert msg == expected_msg, 'The expected cronjob has not been executed'


def test_cron_execution():
    """
    Test that the cronjob in ``../etc/scripts/test_cron.py`` runs successfully.
    """
    _test_cron_queue('cron_test')


def test_cron_execution_upon_system_clock_change():
    """
    Test that the cronjob runs at the right time even upon DST or other
    system clock changes.
    """
    # Mock datetime.datetime with a class that has overridable timedelta
    patcher = patch('datetime.datetime', MockDatetime)

    try:
        patcher.start()
        time.sleep(1)
        # Simulate a +1hr shift on the system clock
        MockDatetime.timedelta = datetime.timedelta(hours=1)
        time.sleep(1)
    finally:
        patcher.stop()

    # Ensure that the cronjob that was supposed to run in an hour is now running
    _test_cron_queue('cron_1hr_test')


if __name__ == '__main__':
    pytest.main()


# vim:sw=4:ts=4:et: