test_error.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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. from tests.support.unit import skipIf
  14. import tests.integration as integration
  15. # Import Salt libs
  16. import salt.utils.schedule
  17. from salt.modules.test import ping as ping
  18. try:
  19. import croniter # pylint: disable=W0611
  20. HAS_CRONITER = True
  21. except ImportError:
  22. HAS_CRONITER = False
  23. log = logging.getLogger(__name__)
  24. ROOT_DIR = os.path.join(integration.TMP, 'schedule-unit-tests')
  25. SOCK_DIR = os.path.join(ROOT_DIR, 'test-socks')
  26. DEFAULT_CONFIG = salt.config.minion_config(None)
  27. DEFAULT_CONFIG['conf_dir'] = ROOT_DIR
  28. DEFAULT_CONFIG['root_dir'] = ROOT_DIR
  29. DEFAULT_CONFIG['sock_dir'] = SOCK_DIR
  30. DEFAULT_CONFIG['pki_dir'] = os.path.join(ROOT_DIR, 'pki')
  31. DEFAULT_CONFIG['cachedir'] = os.path.join(ROOT_DIR, 'cache')
  32. class SchedulerErrorTest(ModuleCase, SaltReturnAssertsMixin):
  33. '''
  34. Validate the pkg module
  35. '''
  36. def setUp(self):
  37. with patch('salt.utils.schedule.clean_proc_dir', MagicMock(return_value=None)):
  38. functions = {'test.ping': ping}
  39. self.schedule = salt.utils.schedule.Schedule(copy.deepcopy(DEFAULT_CONFIG), functions, returners={})
  40. self.schedule.opts['loop_interval'] = 1
  41. self.schedule.opts['run_schedule_jobs_in_background'] = False
  42. self.schedule.opts['grains']['whens'] = {'tea time': '11/29/2017 12:00pm'}
  43. def tearDown(self):
  44. self.schedule.reset()
  45. @skipIf(not HAS_CRONITER, 'Cannot find croniter python module')
  46. def test_eval_cron_invalid(self):
  47. '''
  48. verify that scheduled job runs
  49. '''
  50. job = {
  51. 'schedule': {
  52. 'job1': {
  53. 'function': 'test.ping',
  54. 'cron': '0 16 29 13 *'
  55. }
  56. }
  57. }
  58. # Add the job to the scheduler
  59. self.schedule.opts.update(job)
  60. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  61. with patch('croniter.croniter.get_next', MagicMock(return_value=run_time)):
  62. self.schedule.eval(now=run_time)
  63. ret = self.schedule.job_status('job1')
  64. self.assertEqual(ret['_error'],
  65. 'Invalid cron string. Ignoring job job1.')
  66. def test_eval_when_invalid_date(self):
  67. '''
  68. verify that scheduled job does not run
  69. and returns the right error
  70. '''
  71. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  72. job = {
  73. 'schedule': {
  74. 'job1': {
  75. 'function': 'test.ping',
  76. 'when': '13/29/2017 1:00pm',
  77. }
  78. }
  79. }
  80. # Add the job to the scheduler
  81. self.schedule.opts.update(job)
  82. # Evaluate 1 second before the run time
  83. self.schedule.eval(now=run_time)
  84. ret = self.schedule.job_status('job1')
  85. self.assertEqual(ret['_error'],
  86. 'Invalid date string. Ignoring job job1.')
  87. def test_eval_whens_grain_not_dict(self):
  88. '''
  89. verify that scheduled job does not run
  90. and returns the right error
  91. '''
  92. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  93. job = {
  94. 'schedule': {
  95. 'job1': {
  96. 'function': 'test.ping',
  97. 'when': 'tea time',
  98. }
  99. }
  100. }
  101. self.schedule.opts['grains']['whens'] = ['tea time']
  102. # Add the job to the scheduler
  103. self.schedule.opts.update(job)
  104. # Evaluate 1 second before the run time
  105. self.schedule.eval(now=run_time)
  106. ret = self.schedule.job_status('job1')
  107. self.assertEqual(ret['_error'],
  108. 'Grain "whens" must be a dict. Ignoring job job1.')
  109. def test_eval_once_invalid_datestring(self):
  110. '''
  111. verify that scheduled job does not run
  112. and returns the right error
  113. '''
  114. job = {
  115. 'schedule': {
  116. 'job1': {
  117. 'function': 'test.ping',
  118. 'once': '2017-13-13T13:00:00',
  119. }
  120. }
  121. }
  122. run_time = dateutil_parser.parse('12/13/2017 1:00pm')
  123. # Add the job to the scheduler
  124. self.schedule.opts.update(job)
  125. # Evaluate 1 second at the run time
  126. self.schedule.eval(now=run_time)
  127. ret = self.schedule.job_status('job1')
  128. _expected = ('Date string could not be parsed: '
  129. '2017-13-13T13:00:00, %Y-%m-%dT%H:%M:%S. '
  130. 'Ignoring job job1.')
  131. self.assertEqual(ret['_error'], _expected)
  132. def test_eval_skip_during_range_invalid_date(self):
  133. '''
  134. verify that scheduled job does not run
  135. and returns the right error
  136. '''
  137. job = {
  138. 'schedule': {
  139. 'job1': {
  140. 'function': 'test.ping',
  141. 'hours': 1,
  142. 'skip_during_range': {'start': '1:00pm', 'end': '25:00pm'}
  143. }
  144. }
  145. }
  146. # Add the job to the scheduler
  147. self.schedule.opts.update(job)
  148. # eval at 3:00pm to prime, simulate minion start up.
  149. run_time = dateutil_parser.parse('11/29/2017 3:00pm')
  150. self.schedule.eval(now=run_time)
  151. ret = self.schedule.job_status('job1')
  152. # eval at 4:00pm to prime
  153. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  154. self.schedule.eval(now=run_time)
  155. ret = self.schedule.job_status('job1')
  156. _expected = ('Invalid date string for end in '
  157. 'skip_during_range. Ignoring '
  158. 'job job1.')
  159. self.assertEqual(ret['_error'], _expected)
  160. def test_eval_skip_during_range_end_before_start(self):
  161. '''
  162. verify that scheduled job does not run
  163. and returns the right error
  164. '''
  165. job = {
  166. 'schedule': {
  167. 'job1': {
  168. 'function': 'test.ping',
  169. 'hours': 1,
  170. 'skip_during_range': {'start': '1:00pm', 'end': '12:00pm'}
  171. }
  172. }
  173. }
  174. # Add the job to the scheduler
  175. self.schedule.opts.update(job)
  176. # eval at 3:00pm to prime, simulate minion start up.
  177. run_time = dateutil_parser.parse('11/29/2017 3:00pm')
  178. self.schedule.eval(now=run_time)
  179. ret = self.schedule.job_status('job1')
  180. # eval at 4:00pm to prime
  181. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  182. self.schedule.eval(now=run_time)
  183. ret = self.schedule.job_status('job1')
  184. _expected = ('schedule.handle_func: Invalid '
  185. 'range, end must be larger than '
  186. 'start. Ignoring job job1.')
  187. self.assertEqual(ret['_error'], _expected)
  188. def test_eval_skip_during_range_not_dict(self):
  189. '''
  190. verify that scheduled job does not run
  191. and returns the right error
  192. '''
  193. job = {
  194. 'schedule': {
  195. 'job1': {
  196. 'function': 'test.ping',
  197. 'hours': 1,
  198. 'skip_during_range': ['start', '1:00pm', 'end', '12:00pm']
  199. }
  200. }
  201. }
  202. # Add the job to the scheduler
  203. self.schedule.opts.update(job)
  204. # eval at 3:00pm to prime, simulate minion start up.
  205. run_time = dateutil_parser.parse('11/29/2017 3:00pm')
  206. self.schedule.eval(now=run_time)
  207. ret = self.schedule.job_status('job1')
  208. # eval at 4:00pm to prime
  209. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  210. self.schedule.eval(now=run_time)
  211. ret = self.schedule.job_status('job1')
  212. _expected = ('schedule.handle_func: Invalid, '
  213. 'range must be specified as a '
  214. 'dictionary. Ignoring job job1.')
  215. self.assertEqual(ret['_error'], _expected)