test_error.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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['grains']['whens'] = {'tea time': '11/29/2017 12:00pm'}
  42. def tearDown(self):
  43. self.schedule.reset()
  44. @skipIf(not HAS_CRONITER, 'Cannot find croniter python module')
  45. def test_eval_cron_invalid(self):
  46. '''
  47. verify that scheduled job runs
  48. '''
  49. job = {
  50. 'schedule': {
  51. 'job1': {
  52. 'function': 'test.ping',
  53. 'cron': '0 16 29 13 *'
  54. }
  55. }
  56. }
  57. # Add the job to the scheduler
  58. self.schedule.opts.update(job)
  59. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  60. with patch('croniter.croniter.get_next', MagicMock(return_value=run_time)):
  61. self.schedule.eval(now=run_time)
  62. ret = self.schedule.job_status('job1')
  63. self.assertEqual(ret['_error'],
  64. 'Invalid cron string. Ignoring job job1.')
  65. def test_eval_when_invalid_date(self):
  66. '''
  67. verify that scheduled job does not run
  68. and returns the right error
  69. '''
  70. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  71. job = {
  72. 'schedule': {
  73. 'job1': {
  74. 'function': 'test.ping',
  75. 'when': '13/29/2017 1:00pm',
  76. }
  77. }
  78. }
  79. # Add the job to the scheduler
  80. self.schedule.opts.update(job)
  81. # Evaluate 1 second before the run time
  82. self.schedule.eval(now=run_time)
  83. ret = self.schedule.job_status('job1')
  84. self.assertEqual(ret['_error'],
  85. 'Invalid date string. Ignoring job job1.')
  86. def test_eval_whens_grain_not_dict(self):
  87. '''
  88. verify that scheduled job does not run
  89. and returns the right error
  90. '''
  91. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  92. job = {
  93. 'schedule': {
  94. 'job1': {
  95. 'function': 'test.ping',
  96. 'when': 'tea time',
  97. }
  98. }
  99. }
  100. self.schedule.opts['grains']['whens'] = ['tea time']
  101. # Add the job to the scheduler
  102. self.schedule.opts.update(job)
  103. # Evaluate 1 second before the run time
  104. self.schedule.eval(now=run_time)
  105. ret = self.schedule.job_status('job1')
  106. self.assertEqual(ret['_error'],
  107. 'Grain "whens" must be a dict. Ignoring job job1.')
  108. def test_eval_once_invalid_datestring(self):
  109. '''
  110. verify that scheduled job does not run
  111. and returns the right error
  112. '''
  113. job = {
  114. 'schedule': {
  115. 'job1': {
  116. 'function': 'test.ping',
  117. 'once': '2017-13-13T13:00:00',
  118. }
  119. }
  120. }
  121. run_time = dateutil_parser.parse('12/13/2017 1:00pm')
  122. # Add the job to the scheduler
  123. self.schedule.opts.update(job)
  124. # Evaluate 1 second at the run time
  125. self.schedule.eval(now=run_time)
  126. ret = self.schedule.job_status('job1')
  127. _expected = ('Date string could not be parsed: '
  128. '2017-13-13T13:00:00, %Y-%m-%dT%H:%M:%S. '
  129. 'Ignoring job job1.')
  130. self.assertEqual(ret['_error'], _expected)
  131. def test_eval_skip_during_range_invalid_date(self):
  132. '''
  133. verify that scheduled job does not run
  134. and returns the right error
  135. '''
  136. job = {
  137. 'schedule': {
  138. 'job1': {
  139. 'function': 'test.ping',
  140. 'hours': 1,
  141. 'skip_during_range': {'start': '1:00pm', 'end': '25:00pm'}
  142. }
  143. }
  144. }
  145. # Add the job to the scheduler
  146. self.schedule.opts.update(job)
  147. # eval at 3:00pm to prime, simulate minion start up.
  148. run_time = dateutil_parser.parse('11/29/2017 3:00pm')
  149. self.schedule.eval(now=run_time)
  150. ret = self.schedule.job_status('job1')
  151. # eval at 4:00pm to prime
  152. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  153. self.schedule.eval(now=run_time)
  154. ret = self.schedule.job_status('job1')
  155. _expected = ('Invalid date string for end in '
  156. 'skip_during_range. Ignoring '
  157. 'job job1.')
  158. self.assertEqual(ret['_error'], _expected)
  159. def test_eval_skip_during_range_end_before_start(self):
  160. '''
  161. verify that scheduled job does not run
  162. and returns the right error
  163. '''
  164. job = {
  165. 'schedule': {
  166. 'job1': {
  167. 'function': 'test.ping',
  168. 'hours': 1,
  169. 'skip_during_range': {'start': '1:00pm', 'end': '12:00pm'}
  170. }
  171. }
  172. }
  173. # Add the job to the scheduler
  174. self.schedule.opts.update(job)
  175. # eval at 3:00pm to prime, simulate minion start up.
  176. run_time = dateutil_parser.parse('11/29/2017 3:00pm')
  177. self.schedule.eval(now=run_time)
  178. ret = self.schedule.job_status('job1')
  179. # eval at 4:00pm to prime
  180. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  181. self.schedule.eval(now=run_time)
  182. ret = self.schedule.job_status('job1')
  183. _expected = ('schedule.handle_func: Invalid '
  184. 'range, end must be larger than '
  185. 'start. Ignoring job job1.')
  186. self.assertEqual(ret['_error'], _expected)
  187. def test_eval_skip_during_range_not_dict(self):
  188. '''
  189. verify that scheduled job does not run
  190. and returns the right error
  191. '''
  192. job = {
  193. 'schedule': {
  194. 'job1': {
  195. 'function': 'test.ping',
  196. 'hours': 1,
  197. 'skip_during_range': ['start', '1:00pm', 'end', '12:00pm']
  198. }
  199. }
  200. }
  201. # Add the job to the scheduler
  202. self.schedule.opts.update(job)
  203. # eval at 3:00pm to prime, simulate minion start up.
  204. run_time = dateutil_parser.parse('11/29/2017 3:00pm')
  205. self.schedule.eval(now=run_time)
  206. ret = self.schedule.job_status('job1')
  207. # eval at 4:00pm to prime
  208. run_time = dateutil_parser.parse('11/29/2017 4:00pm')
  209. self.schedule.eval(now=run_time)
  210. ret = self.schedule.job_status('job1')
  211. _expected = ('schedule.handle_func: Invalid, '
  212. 'range must be specified as a '
  213. 'dictionary. Ignoring job job1.')
  214. self.assertEqual(ret['_error'], _expected)