mirror of
https://github.com/ZwareBear/awx.git
synced 2026-04-12 19:11:49 -05:00
this commit allows schedule `rrule` strings to include local timezone information via TZID=NNNNN; occurrences are _generated_ in the local time specific by the user (or UTC, if e.g., DTSTART:YYYYMMDDTHHMMSSZ) while Schedule.next_run, Schedule.dtstart, and Schedule.dtend will be stored in the UTC equivalent (i.e., the scheduler will still do math on "what to run next" based on UTC datetimes). in addition to this change, there is now a new API endpoint, `/api/v2/schedules/preview/`, which takes an rrule and shows the next 10 occurrences in local and UTC time. see: https://github.com/ansible/ansible-tower/issues/823 related: https://github.com/dateutil/dateutil/issues/614
169 lines
5.2 KiB
Python
169 lines
5.2 KiB
Python
from awx.main.models import JobTemplate, Schedule
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
def job_template(inventory, project):
|
|
# need related resources set for these tests
|
|
return JobTemplate.objects.create(
|
|
name='test-job_template',
|
|
inventory=inventory,
|
|
project=project
|
|
)
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_repeats_forever(job_template):
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule='DTSTART:20300112T210000Z RRULE:FREQ=DAILY;INTERVAL=1',
|
|
unified_job_template=job_template
|
|
)
|
|
s.save()
|
|
assert str(s.next_run) == str(s.dtstart) == '2030-01-12 21:00:00+00:00'
|
|
assert s.dtend is None
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_no_recurrence_utc(job_template):
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule='DTSTART:20300112T210000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1',
|
|
unified_job_template=job_template
|
|
)
|
|
s.save()
|
|
assert str(s.next_run) == str(s.dtstart) == str(s.dtend) == '2030-01-12 21:00:00+00:00'
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_no_recurrence_est(job_template):
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule='DTSTART;TZID=America/New_York:20300112T210000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1',
|
|
unified_job_template=job_template
|
|
)
|
|
s.save()
|
|
assert str(s.next_run) == str(s.dtstart) == str(s.dtend) == '2030-01-13 02:00:00+00:00'
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_next_run_utc(job_template):
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule='DTSTART:20300112T210000Z RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=SA;BYSETPOS=1;COUNT=4',
|
|
unified_job_template=job_template
|
|
)
|
|
s.save()
|
|
assert str(s.next_run) == '2030-02-02 21:00:00+00:00'
|
|
assert str(s.next_run) == str(s.dtstart)
|
|
assert str(s.dtend) == '2030-05-04 21:00:00+00:00'
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_next_run_est(job_template):
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule='DTSTART;TZID=America/New_York:20300112T210000 RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=SA;BYSETPOS=1;COUNT=4',
|
|
unified_job_template=job_template
|
|
)
|
|
s.save()
|
|
|
|
assert str(s.next_run) == '2030-02-03 02:00:00+00:00'
|
|
assert str(s.next_run) == str(s.dtstart)
|
|
|
|
# March 10, 2030 is when DST takes effect in NYC
|
|
assert str(s.dtend) == '2030-05-05 01:00:00+00:00'
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_year_boundary(job_template):
|
|
rrule = 'DTSTART;TZID=America/New_York:20301231T230000 RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=12;BYMONTHDAY=31;COUNT=4' # noqa
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule=rrule,
|
|
unified_job_template=job_template
|
|
)
|
|
s.save()
|
|
|
|
assert str(s.next_run) == '2031-01-01 04:00:00+00:00' # UTC = +5 EST
|
|
assert str(s.next_run) == str(s.dtstart)
|
|
assert str(s.dtend) == '2034-01-01 04:00:00+00:00' # UTC = +5 EST
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_leap_year_day(job_template):
|
|
rrule = 'DTSTART;TZID=America/New_York:20320229T050000 RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=02;BYMONTHDAY=29;COUNT=2' # noqa
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule=rrule,
|
|
unified_job_template=job_template
|
|
)
|
|
s.save()
|
|
|
|
assert str(s.next_run) == '2032-02-29 10:00:00+00:00' # UTC = +5 EST
|
|
assert str(s.next_run) == str(s.dtstart)
|
|
assert str(s.dtend) == '2036-02-29 10:00:00+00:00' # UTC = +5 EST
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@pytest.mark.parametrize('until, dtend', [
|
|
['20180602T170000Z', '2018-06-02 12:00:00+00:00'],
|
|
['20180602T000000Z', '2018-06-01 12:00:00+00:00'],
|
|
])
|
|
def test_utc_until(job_template, until, dtend):
|
|
rrule = 'DTSTART:20180601T120000Z RRULE:FREQ=DAILY;INTERVAL=1;UNTIL={}'.format(until)
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule=rrule,
|
|
unified_job_template=job_template
|
|
)
|
|
s.save()
|
|
|
|
assert str(s.next_run) == '2018-06-01 12:00:00+00:00'
|
|
assert str(s.next_run) == str(s.dtstart)
|
|
assert str(s.dtend) == dtend
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@pytest.mark.parametrize('until, dtend', [
|
|
['20180602T170000', '2018-06-02 16:00:00+00:00'],
|
|
['20180602T000000', '2018-06-01 16:00:00+00:00'],
|
|
])
|
|
def test_tzinfo_until(job_template, until, dtend):
|
|
rrule = 'DTSTART;TZID=America/New_York:20180601T120000 RRULE:FREQ=DAILY;INTERVAL=1;UNTIL={}'.format(until) # noqa
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule=rrule,
|
|
unified_job_template=job_template
|
|
)
|
|
s.save()
|
|
|
|
assert str(s.next_run) == '2018-06-01 16:00:00+00:00' # UTC = +4 EST
|
|
assert str(s.next_run) == str(s.dtstart)
|
|
assert str(s.dtend) == dtend
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_mismatched_until_timezone(job_template):
|
|
rrule = 'DTSTART;TZID=America/New_York:20180601T120000 RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20180602T000000' + 'Z' # noqa the Z isn't allowed, because we have a TZID=America/New_York
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule=rrule,
|
|
unified_job_template=job_template
|
|
)
|
|
with pytest.raises(ValueError):
|
|
s.save()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_utc_until_in_the_past(job_template):
|
|
rrule = 'DTSTART:20180601T120000Z RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20150101T100000Z'
|
|
s = Schedule(
|
|
name='Some Schedule',
|
|
rrule=rrule,
|
|
unified_job_template=job_template
|
|
)
|
|
s.save()
|
|
|
|
assert s.next_run is s.dtstart is s.dtend is None
|