test_skip.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import
  3. import logging
  4. import pytest
  5. from tests.unit.utils.scheduler.base import SchedulerTestsBase
  6. try:
  7. import dateutil.parser
  8. HAS_DATEUTIL_PARSER = True
  9. except ImportError:
  10. HAS_DATEUTIL_PARSER = False
  11. log = logging.getLogger(__name__)
  12. @pytest.mark.skipif(
  13. HAS_DATEUTIL_PARSER is False,
  14. reason="The 'dateutil.parser' library is not available",
  15. )
  16. class SchedulerSkipTest(SchedulerTestsBase):
  17. """
  18. Validate the pkg module
  19. """
  20. def setUp(self):
  21. super(SchedulerSkipTest, self).setUp()
  22. self.schedule.opts["loop_interval"] = 1
  23. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  24. def test_skip(self):
  25. """
  26. verify that scheduled job is skipped at the specified time
  27. """
  28. job_name = "test_skip"
  29. job = {
  30. "schedule": {
  31. job_name: {
  32. "function": "test.ping",
  33. "when": ["11/29/2017 4pm", "11/29/2017 5pm"],
  34. }
  35. }
  36. }
  37. # Add job to schedule
  38. self.schedule.opts.update(job)
  39. run_time = dateutil.parser.parse("11/29/2017 4:00pm")
  40. self.schedule.skip_job(
  41. job_name,
  42. {
  43. "time": run_time.strftime("%Y-%m-%dT%H:%M:%S"),
  44. "time_fmt": "%Y-%m-%dT%H:%M:%S",
  45. },
  46. )
  47. # Run 11/29/2017 at 4pm
  48. self.schedule.eval(now=run_time)
  49. ret = self.schedule.job_status(job_name)
  50. self.assertNotIn("_last_run", ret)
  51. self.assertEqual(ret["_skip_reason"], "skip_explicit")
  52. self.assertEqual(ret["_skipped_time"], run_time)
  53. # Run 11/29/2017 at 5pm
  54. run_time = dateutil.parser.parse("11/29/2017 5:00pm")
  55. self.schedule.eval(now=run_time)
  56. ret = self.schedule.job_status(job_name)
  57. self.assertEqual(ret["_last_run"], run_time)
  58. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  59. def test_skip_during_range(self):
  60. """
  61. verify that scheduled job is skipped during the specified range
  62. """
  63. job_name = "test_skip_during_range"
  64. job = {
  65. "schedule": {
  66. job_name: {
  67. "function": "test.ping",
  68. "hours": "1",
  69. "skip_during_range": {
  70. "start": "11/29/2017 2pm",
  71. "end": "11/29/2017 3pm",
  72. },
  73. }
  74. }
  75. }
  76. # Add job to schedule
  77. self.schedule.opts.update(job)
  78. # eval at 1:30pm to prime.
  79. run_time = dateutil.parser.parse("11/29/2017 1:30pm")
  80. self.schedule.eval(now=run_time)
  81. ret = self.schedule.job_status(job_name)
  82. # eval at 2:30pm, will not run during range.
  83. run_time = dateutil.parser.parse("11/29/2017 2:30pm")
  84. self.schedule.eval(now=run_time)
  85. ret = self.schedule.job_status(job_name)
  86. self.assertNotIn("_last_run", ret)
  87. self.assertEqual(ret["_skip_reason"], "in_skip_range")
  88. self.assertEqual(ret["_skipped_time"], run_time)
  89. # eval at 3:30pm, will run.
  90. run_time = dateutil.parser.parse("11/29/2017 3:30pm")
  91. self.schedule.eval(now=run_time)
  92. ret = self.schedule.job_status(job_name)
  93. self.assertEqual(ret["_last_run"], run_time)
  94. def test_skip_during_range_invalid_datestring(self):
  95. """
  96. verify that scheduled job is not not and returns the right error string
  97. """
  98. run_time = dateutil.parser.parse("11/29/2017 2:30pm")
  99. job_name1 = "skip_during_range_invalid_datestring1"
  100. job1 = {
  101. "schedule": {
  102. job_name1: {
  103. "function": "test.ping",
  104. "hours": "1",
  105. "_next_fire_time": run_time,
  106. "skip_during_range": {"start": "25pm", "end": "3pm"},
  107. }
  108. }
  109. }
  110. job_name2 = "skip_during_range_invalid_datestring2"
  111. job2 = {
  112. "schedule": {
  113. job_name2: {
  114. "function": "test.ping",
  115. "hours": "1",
  116. "_next_fire_time": run_time,
  117. "skip_during_range": {"start": "2pm", "end": "25pm"},
  118. }
  119. }
  120. }
  121. # Add job1 to schedule
  122. self.schedule.opts.update(job1)
  123. # Eval
  124. self.schedule.eval(now=run_time)
  125. # Check the first job
  126. ret = self.schedule.job_status(job_name1)
  127. _expected = (
  128. "Invalid date string for start in "
  129. "skip_during_range. Ignoring "
  130. "job {0}."
  131. ).format(job_name1)
  132. self.assertEqual(ret["_error"], _expected)
  133. # Clear out schedule
  134. self.schedule.opts["schedule"] = {}
  135. # Add job2 to schedule
  136. self.schedule.opts.update(job2)
  137. # Eval
  138. self.schedule.eval(now=run_time)
  139. # Check the second job
  140. ret = self.schedule.job_status(job_name2)
  141. _expected = (
  142. "Invalid date string for end in " "skip_during_range. Ignoring " "job {0}."
  143. ).format(job_name2)
  144. self.assertEqual(ret["_error"], _expected)
  145. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  146. def test_skip_during_range_global(self):
  147. """
  148. verify that scheduled job is skipped during the specified range
  149. """
  150. job_name = "skip_during_range_global"
  151. job = {
  152. "schedule": {
  153. "skip_during_range": {
  154. "start": "11/29/2017 2:00pm",
  155. "end": "11/29/2017 3:00pm",
  156. },
  157. job_name: {"function": "test.ping", "hours": "1"},
  158. }
  159. }
  160. # Add job to schedule
  161. self.schedule.opts.update(job)
  162. # eval at 1:30pm to prime.
  163. run_time = dateutil.parser.parse("11/29/2017 1:30pm")
  164. self.schedule.eval(now=run_time)
  165. ret = self.schedule.job_status(job_name)
  166. # eval at 2:30pm, will not run during range.
  167. run_time = dateutil.parser.parse("11/29/2017 2:30pm")
  168. self.schedule.eval(now=run_time)
  169. ret = self.schedule.job_status(job_name)
  170. self.assertNotIn("_last_run", ret)
  171. self.assertEqual(ret["_skip_reason"], "in_skip_range")
  172. self.assertEqual(ret["_skipped_time"], run_time)
  173. # eval at 3:30pm, will run.
  174. run_time = dateutil.parser.parse("11/29/2017 3:30pm")
  175. self.schedule.eval(now=run_time)
  176. ret = self.schedule.job_status(job_name)
  177. self.assertEqual(ret["_last_run"], run_time)
  178. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  179. def test_run_after_skip_range(self):
  180. """
  181. verify that scheduled job is skipped during the specified range
  182. """
  183. job_name = "skip_run_after_skip_range"
  184. job = {
  185. "schedule": {
  186. job_name: {
  187. "function": "test.ping",
  188. "when": "11/29/2017 2:30pm",
  189. "run_after_skip_range": True,
  190. "skip_during_range": {
  191. "start": "11/29/2017 2pm",
  192. "end": "11/29/2017 3pm",
  193. },
  194. }
  195. }
  196. }
  197. # Add job to schedule
  198. self.schedule.opts.update(job)
  199. # eval at 2:30pm, will not run during range.
  200. run_time = dateutil.parser.parse("11/29/2017 2:30pm")
  201. self.schedule.eval(now=run_time)
  202. ret = self.schedule.job_status(job_name)
  203. self.assertNotIn("_last_run", ret)
  204. self.assertEqual(ret["_skip_reason"], "in_skip_range")
  205. self.assertEqual(ret["_skipped_time"], run_time)
  206. # eval at 3:00:01pm, will run.
  207. run_time = dateutil.parser.parse("11/29/2017 3:00:01pm")
  208. self.schedule.eval(now=run_time)
  209. ret = self.schedule.job_status(job_name)
  210. self.assertEqual(ret["_last_run"], run_time)
  211. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  212. def test_run_seconds_skip(self):
  213. """
  214. verify that scheduled job is skipped during the specified range
  215. """
  216. job_name = "run_seconds_skip"
  217. job = {"schedule": {job_name: {"function": "test.ping", "seconds": "10"}}}
  218. # Add job to schedule
  219. self.schedule.opts.update(job)
  220. # eval at 2:00pm, to prime the scheduler
  221. run_time = dateutil.parser.parse("11/29/2017 2:00pm")
  222. self.schedule.eval(now=run_time)
  223. ret = self.schedule.job_status(job_name)
  224. # eval at 2:00:10pm
  225. run_time = dateutil.parser.parse("11/29/2017 2:00:10pm")
  226. self.schedule.eval(now=run_time)
  227. ret = self.schedule.job_status(job_name)
  228. # Skip at 2:00:20pm
  229. run_time = dateutil.parser.parse("11/29/2017 2:00:20pm")
  230. self.schedule.skip_job(
  231. job_name,
  232. {
  233. "time": run_time.strftime("%Y-%m-%dT%H:%M:%S"),
  234. "time_fmt": "%Y-%m-%dT%H:%M:%S",
  235. },
  236. )
  237. self.schedule.eval(now=run_time)
  238. ret = self.schedule.job_status(job_name)
  239. self.assertIn("_next_fire_time", ret)
  240. self.assertEqual(ret["_skip_reason"], "skip_explicit")
  241. self.assertEqual(ret["_skipped_time"], run_time)
  242. # Run at 2:00:30pm
  243. run_time = dateutil.parser.parse("11/29/2017 2:00:30pm")
  244. self.schedule.eval(now=run_time)
  245. ret = self.schedule.job_status(job_name)
  246. self.assertIn("_last_run", ret)