Skip to content

Commit

Permalink
Merge 2860318 into df813c4
Browse files Browse the repository at this point in the history
  • Loading branch information
Ambro17 committed Mar 2, 2019
2 parents df813c4 + 2860318 commit e7a350f
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 100 deletions.
1 change: 1 addition & 0 deletions requirements-dev.txt
Expand Up @@ -8,3 +8,4 @@ beautifulsoup4
pytest==4.2.0
pytest-timeout
wheel
freezegun
256 changes: 156 additions & 100 deletions tests/test_jobqueue.py
Expand Up @@ -17,30 +17,41 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import datetime
import os
import sys
import time
import sys
from queue import Queue
from time import sleep

import pytest
from flaky import flaky
from freezegun import freeze_time

from telegram.ext import JobQueue, Updater, Job, CallbackContext
from telegram.utils.deprecate import TelegramDeprecationWarning


DAY = 24 * 60 * 60


@pytest.fixture(scope='function')
def job_queue(bot, _dp):
jq = JobQueue()
jq.set_dispatcher(_dp)
jq.start()
yield jq
jq.stop()
def frozen_job_queue(bot):
"""Yields a job_queue with frozen time that can be manualy advanced to fake time travelling"""
with freeze_time(datetime.datetime.now()) as frozen_time:
job_queue = JobQueue(bot)
job_queue.start()
yield job_queue, frozen_time
job_queue.stop()


def tick_seconds(frozen_time, seconds):
"""Simulate that we have traveled `seconds` in time."""
frozen_time.tick(delta=datetime.timedelta(seconds=seconds))


def time_travel(job_queue, frozen_time, seconds):
"""Travel in time to execute future jobs, due in `seconds`"""
tick_seconds(frozen_time, seconds)
job_queue.tick()


@pytest.mark.skipif(os.getenv('APPVEYOR'), reason="On Appveyor precise timings are not accurate.")
@flaky(10, 1) # Timings aren't quite perfect
class TestJobQueue(object):
result = 0
job_time = 0
Expand All @@ -65,6 +76,7 @@ def job_run_once_with_context(self, bot, job):

def job_datetime_tests(self, bot, job):
self.job_time = time.time()
self.result += 1

def job_context_based_callback(self, context):
if (isinstance(context, CallbackContext)
Expand All @@ -76,159 +88,200 @@ def job_context_based_callback(self, context):
and context.job_queue is context.job.job_queue):
self.result += 1

def test_run_once(self, job_queue):
job_queue.run_once(self.job_run_once, 0.01)
sleep(0.02)
def test_run_once(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_run_once, 10)

time_travel(job_queue, fz_time, 11)
assert self.result == 1

def test_job_with_context(self, job_queue):
job_queue.run_once(self.job_run_once_with_context, 0.01, context=5)
sleep(0.02)
def test_job_with_context(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_run_once_with_context, 10, context=5)

time_travel(job_queue, fz_time, 11)

assert self.result == 5

def test_run_repeating(self, job_queue):
job_queue.run_repeating(self.job_run_once, 0.02)
sleep(0.05)
def test_run_repeating(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
job_queue.run_repeating(self.job_run_once, 2)

time_travel(job_queue, fz_time, 5)

assert self.result == 2

def test_run_repeating_first(self, job_queue):
job_queue.run_repeating(self.job_run_once, 0.05, first=0.2)
sleep(0.15)
def test_run_repeating_first(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
job_queue.run_repeating(self.job_run_once, 10, first=20)

time_travel(job_queue, fz_time, 15)
assert self.result == 0
sleep(0.07)

time_travel(job_queue, fz_time, 10)
assert self.result == 1

def test_multiple(self, job_queue):
job_queue.run_once(self.job_run_once, 0.01)
job_queue.run_once(self.job_run_once, 0.02)
job_queue.run_repeating(self.job_run_once, 0.02)
sleep(0.055)
assert self.result == 4
def test_multiple(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_run_once, 10)
job_queue.run_once(self.job_run_once, 20)
job_queue.run_repeating(self.job_run_once, 20)

def test_disabled(self, job_queue):
j1 = job_queue.run_once(self.job_run_once, 0.1)
j2 = job_queue.run_repeating(self.job_run_once, 0.05)
time_travel(job_queue, fz_time, 50)

j1.enabled = False
j2.enabled = False
assert self.result == 4

sleep(0.06)
def test_disabled(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
once_job = job_queue.run_once(self.job_run_once, 10)
repeating_job = job_queue.run_repeating(self.job_run_once, 5)

once_job.enabled = False
repeating_job.enabled = False

time_travel(job_queue, fz_time, 13)
assert self.result == 0

j1.enabled = True
repeating_job.enabled = True

sleep(0.2)
time_travel(job_queue, fz_time, 6)

assert len(job_queue.jobs()) == 1
assert self.result == 1

def test_schedule_removal(self, job_queue):
j1 = job_queue.run_once(self.job_run_once, 0.03)
j2 = job_queue.run_repeating(self.job_run_once, 0.02)
def test_schedule_removal(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
j1 = job_queue.run_once(self.job_run_once, 50)
j2 = job_queue.run_repeating(self.job_run_once, 30)

sleep(0.025)
time_travel(job_queue, fz_time, 35)
assert self.result == 1

j1.schedule_removal()
j2.schedule_removal()

sleep(0.04)

time_travel(job_queue, fz_time, 30)
assert self.result == 1

def test_schedule_removal_from_within(self, job_queue):
job_queue.run_repeating(self.job_remove_self, 0.01)
def test_schedule_removal_from_within(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
job_queue.run_repeating(self.job_remove_self, 1)

sleep(0.05)
time_travel(job_queue, fz_time, 5)

assert self.result == 1

def test_longer_first(self, job_queue):
job_queue.run_once(self.job_run_once, 0.02)
job_queue.run_once(self.job_run_once, 0.01)
def test_longer_first(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_run_once, 100)
job_queue.run_once(self.job_run_once, 50)

sleep(0.015)
time_travel(job_queue, fz_time, 60)

assert self.result == 1

def test_error(self, job_queue):
job_queue.run_repeating(self.job_with_exception, 0.01)
job_queue.run_repeating(self.job_run_once, 0.02)
sleep(0.03)
def test_error(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_with_exception, 20)
job_queue.run_once(self.job_run_once, 20)

time_travel(job_queue, fz_time, 25)

assert self.result == 1

def test_in_updater(self, bot):
u = Updater(bot=bot)
u.job_queue.start()
try:
u.job_queue.run_repeating(self.job_run_once, 0.02)
sleep(0.03)
assert self.result == 1
u.stop()
sleep(1)
assert self.result == 1
finally:
u.stop()

def test_time_unit_int(self, job_queue):
# Testing seconds in int
delta = 0.05
with freeze_time(datetime.datetime.now()) as fz_time:
u = Updater(bot=bot)
u.job_queue.start()
try:
u.job_queue.run_repeating(self.job_run_once, 20)
time_travel(u.job_queue, fz_time, 25)
assert self.result == 1

u.stop()
assert u.job_queue._running is False

time_travel(u.job_queue, fz_time, 5)
assert self.result == 1

finally:
u.stop()

def test_time_unit_float(self, frozen_job_queue):
# Testing seconds in float
delta = 5.0
expected_time = time.time() + delta

job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_datetime_tests, delta)
sleep(0.06)

time_travel(job_queue, fz_time, 6.0)

assert pytest.approx(self.job_time) == expected_time

def test_time_unit_dt_timedelta(self, job_queue):
def test_time_unit_dt_timedelta(self, frozen_job_queue):
# Testing seconds, minutes and hours as datetime.timedelta object
# This is sufficient to test that it actually works.
interval = datetime.timedelta(seconds=0.05)
interval = datetime.timedelta(seconds=5)
expected_time = time.time() + interval.total_seconds()

job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_datetime_tests, interval)
sleep(0.06)

time_travel(job_queue, fz_time, 6)

assert pytest.approx(self.job_time) == expected_time

def test_time_unit_dt_datetime(self, job_queue):
def test_time_unit_dt_datetime(self, frozen_job_queue):
# Testing running at a specific datetime
delta = datetime.timedelta(seconds=0.05)
delta = datetime.timedelta(seconds=5)

when = datetime.datetime.now() + delta
expected_time = time.time() + delta.total_seconds()

job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_datetime_tests, when)
sleep(0.06)

time_travel(job_queue, fz_time, 6)

assert pytest.approx(self.job_time) == expected_time

def test_time_unit_dt_time_today(self, job_queue):
def test_time_unit_dt_time_today(self, frozen_job_queue):
# Testing running at a specific time today
delta = 0.05
when = (datetime.datetime.now() + datetime.timedelta(seconds=delta)).time()
delta = 5
when = (datetime.datetime.now() + datetime.timedelta(seconds=5)).time()
expected_time = time.time() + delta

job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_datetime_tests, when)
sleep(0.06)

time_travel(job_queue, fz_time, 6)

assert pytest.approx(self.job_time) == expected_time

def test_time_unit_dt_time_tomorrow(self, job_queue):
# Testing running at a specific time that has passed today. Since we can't wait a day, we
# test if the jobs next_t has been calculated correctly
def test_time_unit_dt_time_tomorrow(self, frozen_job_queue):
delta = -2
when = (datetime.datetime.now() + datetime.timedelta(seconds=delta)).time()
expected_time = time.time() + delta + 60 * 60 * 24
expected_time = time.time() + delta + DAY

job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_datetime_tests, when)
assert pytest.approx(job_queue._queue.get(False)[0]) == expected_time

def test_run_daily(self, job_queue):
delta = 0.5
time_of_day = (datetime.datetime.now() + datetime.timedelta(seconds=delta)).time()
expected_time = time.time() + 60 * 60 * 24 + delta
time_travel(job_queue, fz_time, DAY)

assert pytest.approx(self.job_time) == expected_time

def test_run_daily(self, frozen_job_queue):
time_of_day = (datetime.datetime.now() + datetime.timedelta(seconds=-1)).time()

job_queue, fz_time = frozen_job_queue
job_queue.run_daily(self.job_run_once, time_of_day)
sleep(0.6)
assert self.result == 1
assert pytest.approx(job_queue._queue.get(False)[0]) == expected_time

def test_warnings(self, job_queue):
time_travel(job_queue, fz_time, 7 * DAY)

assert self.result == 7

def test_warnings(self):
j = Job(self.job_run_once, repeat=False)
with pytest.raises(ValueError, match='can not be set to'):
j.repeat = True
Expand All @@ -250,7 +303,8 @@ def test_warnings(self, job_queue):
with pytest.raises(ValueError, match='from 0 up to and'):
j.days = (0, 6, 12, 14)

def test_get_jobs(self, job_queue):
def test_get_jobs(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
job1 = job_queue.run_once(self.job_run_once, 10, name='name1')
job2 = job_queue.run_once(self.job_run_once, 10, name='name1')
job3 = job_queue.run_once(self.job_run_once, 10, name='name2')
Expand All @@ -259,14 +313,16 @@ def test_get_jobs(self, job_queue):
assert job_queue.get_jobs_by_name('name1') == (job1, job2)
assert job_queue.get_jobs_by_name('name2') == (job3,)

@staticmethod
@pytest.mark.skipif(sys.version_info < (3, 0), reason='pytest fails this for no reason')
def test_bot_in_init_deprecation(self, bot):
def test_bot_in_init_deprecation(bot):
with pytest.warns(TelegramDeprecationWarning):
JobQueue(bot)

def test_context_based_callback(self, job_queue):
job_queue.run_once(self.job_context_based_callback, 0.01, context=2)
def test_context_based_callback(self, frozen_job_queue):
job_queue, fz_time = frozen_job_queue
job_queue.run_once(self.job_context_based_callback, 1, context=2)

sleep(0.03)
time_travel(job_queue, fz_time, 3)

assert self.result == 0

0 comments on commit e7a350f

Please sign in to comment.