From cf441d46a9699cdeb35d4500372818e480f3f5d3 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Sat, 11 Feb 2023 15:11:11 -0800 Subject: [PATCH] When a job is disabled only increase it's _next_fire_time value if the job would have run at the current time, eg. the current _next_fire_time == now. --- salt/utils/schedule.py | 7 +- .../pytests/unit/utils/scheduler/test_eval.py | 140 ++++++++++++++++++ 2 files changed, 144 insertions(+), 3 deletions(-) diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py index 5e58cd452c8..07c7b52e387 100644 --- a/salt/utils/schedule.py +++ b/salt/utils/schedule.py @@ -1769,9 +1769,10 @@ class Schedule: seconds=data["_seconds"] ) elif "_skipped" in data and data["_skipped"]: - data["_next_fire_time"] = now + datetime.timedelta( - seconds=data["_seconds"] - ) + if data["_next_fire_time"] == now: + data["_next_fire_time"] = now + datetime.timedelta( + seconds=data["_seconds"] + ) elif run: data["_next_fire_time"] = now + datetime.timedelta( seconds=data["_seconds"] diff --git a/tests/pytests/unit/utils/scheduler/test_eval.py b/tests/pytests/unit/utils/scheduler/test_eval.py index c956940e962..4de2399fb1e 100644 --- a/tests/pytests/unit/utils/scheduler/test_eval.py +++ b/tests/pytests/unit/utils/scheduler/test_eval.py @@ -502,6 +502,146 @@ def test_eval_disabled(schedule): assert ret == job["schedule"][job_name] +def test_eval_disabled_seconds(schedule): + """ + verify that scheduled job does not run + """ + + job_name = "test_eval_disabled_seconds" + job = { + "schedule": { + "enabled": True, + job_name: {"function": "test.ping", "seconds": "30"}, + } + } + + # Add the job to the scheduler + schedule.opts.update(job) + + eval_time1 = dateutil.parser.parse("11/29/2017 4:00pm") + schedule.eval(now=eval_time1) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 29, 16, 0, 30) + + # Disable the job + schedule.opts["schedule"]["enabled"] = False + + # Evaluate 1 second for 29 seconds + # Assert that the _next_fire_time does not change + # until the _next_fire_time is reached + for i in range(1, 30): + eval_time = eval_time1 + datetime.timedelta(seconds=i) + schedule.eval(now=eval_time) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 29, 16, 0, 30) + + eval_time = eval_time1 + datetime.timedelta(seconds=30) + schedule.eval(now=eval_time) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 29, 16, 1, 0) + + +def test_eval_disabled_minutes(schedule): + """ + verify that scheduled job does not run + """ + + job_name = "test_eval_disabled_minutes" + job = { + "schedule": { + "enabled": True, + job_name: {"function": "test.ping", "minutes": "55"}, + } + } + + # Add the job to the scheduler + schedule.opts.update(job) + + eval_time1 = dateutil.parser.parse("11/29/2017 4:00pm") + schedule.eval(now=eval_time1) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 29, 16, 55, 0) + + # Evaluate 1 minute for 50 minutes + # Assert that the _next_fire_time does not change + # until the _next_fire_time is reached + for i in range(1, 50): + eval_time = eval_time1 + datetime.timedelta(minutes=i) + schedule.eval(now=eval_time) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 29, 16, 55, 0) + + # Disable the job + schedule.opts["schedule"]["enabled"] = False + + for i in range(1, 10): + eval_time = eval_time1 + datetime.timedelta(seconds=i) + schedule.eval(now=eval_time) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 29, 16, 55, 0) + + eval_time = dateutil.parser.parse("11/29/2017 4:55pm") + schedule.eval(now=eval_time) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 29, 17, 50, 0) + + +def test_eval_disabled_hours(schedule): + """ + verify that scheduled job does not run + """ + + job_name = "test_eval_disabled_hours" + job = { + "schedule": { + "enabled": True, + job_name: {"function": "test.ping", "hours": "6"}, + } + } + + # Add the job to the scheduler + schedule.opts.update(job) + + eval_time1 = dateutil.parser.parse("11/29/2017 4:00pm") + schedule.eval(now=eval_time1) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 29, 22, 0, 0) + + # Evaluate 1 hour for 5 hours + # Assert that the _next_fire_time does not change + # until the _next_fire_time is reached + for i in range(1, 5): + eval_time = eval_time1 + datetime.timedelta(hours=i) + schedule.eval(now=eval_time) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 29, 22, 0, 0) + + # Disable the job + schedule.opts["schedule"]["enabled"] = False + + for i in range(1, 50): + eval_time = eval_time1 + datetime.timedelta(minutes=i) + schedule.eval(now=eval_time) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 29, 22, 0, 0) + + eval_time = dateutil.parser.parse("11/29/2017 10:00pm") + schedule.eval(now=eval_time) + ret = schedule.job_status(job_name) + assert "_next_fire_time" in ret + assert ret["_next_fire_time"] == datetime.datetime(2017, 11, 30, 4, 0, 0) + + def test_eval_global_disabled_job_enabled(schedule): """ verify that scheduled job does not run