test_skip.py 9.8 KB

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