ProcessCronQueueObserverTest.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Cron\Test\Unit\Observer;
  7. use Magento\Cron\Model\Schedule;
  8. use Magento\Cron\Observer\ProcessCronQueueObserver as ProcessCronQueueObserver;
  9. use Magento\Framework\App\State;
  10. use Magento\Framework\Profiler\Driver\Standard\StatFactory;
  11. /**
  12. * Class \Magento\Cron\Test\Unit\Model\ObserverTest
  13. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  14. * @SuppressWarnings(PHPMD.TooManyFields)
  15. */
  16. class ProcessCronQueueObserverTest extends \PHPUnit\Framework\TestCase
  17. {
  18. /**
  19. * @var ProcessCronQueueObserver
  20. */
  21. protected $_observer;
  22. /**
  23. * @var \Magento\Framework\App\ObjectManager|\PHPUnit_Framework_MockObject_MockObject
  24. */
  25. protected $_objectManager;
  26. /**
  27. * @var \PHPUnit_Framework_MockObject_MockObject
  28. */
  29. protected $_cache;
  30. /**
  31. * @var \Magento\Cron\Model\Config|\PHPUnit_Framework_MockObject_MockObject
  32. */
  33. protected $_config;
  34. /**
  35. * @var \Magento\Cron\Model\ScheduleFactory|\PHPUnit_Framework_MockObject_MockObject
  36. */
  37. protected $_scheduleFactory;
  38. /**
  39. * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
  40. */
  41. protected $_scopeConfig;
  42. /**
  43. * @var \Magento\Framework\App\Console\Request|\PHPUnit_Framework_MockObject_MockObject
  44. */
  45. protected $_request;
  46. /**
  47. * @var \Magento\Framework\ShellInterface|\PHPUnit_Framework_MockObject_MockObject
  48. */
  49. protected $_shell;
  50. /** @var \Magento\Cron\Model\ResourceModel\Schedule\Collection|\PHPUnit_Framework_MockObject_MockObject */
  51. protected $_collection;
  52. /**
  53. * @var \Magento\Cron\Model\Groups\Config\Data
  54. */
  55. protected $_cronGroupConfig;
  56. /**
  57. * @var \Magento\Framework\Stdlib\DateTime\DateTime
  58. */
  59. protected $dateTimeMock;
  60. /**
  61. * @var \Magento\Framework\Event\Observer
  62. */
  63. protected $observer;
  64. /**
  65. * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
  66. */
  67. protected $loggerMock;
  68. /**
  69. * @var \Magento\Framework\App\State|\PHPUnit_Framework_MockObject_MockObject
  70. */
  71. protected $appStateMock;
  72. /**
  73. * @var \Magento\Framework\Lock\LockManagerInterface|\PHPUnit_Framework_MockObject_MockObject
  74. */
  75. private $lockManagerMock;
  76. /**
  77. * @var \Magento\Cron\Model\ResourceModel\Schedule|\PHPUnit_Framework_MockObject_MockObject
  78. */
  79. protected $scheduleResource;
  80. /**
  81. * @var int
  82. */
  83. protected $time = 1501538400;
  84. /**
  85. * Prepare parameters
  86. */
  87. protected function setUp()
  88. {
  89. $this->_objectManager = $this->getMockBuilder(
  90. \Magento\Framework\App\ObjectManager::class
  91. )->disableOriginalConstructor()->getMock();
  92. $this->_cache = $this->createMock(\Magento\Framework\App\CacheInterface::class);
  93. $this->_config = $this->getMockBuilder(
  94. \Magento\Cron\Model\Config::class
  95. )->disableOriginalConstructor()->getMock();
  96. $this->_scopeConfig = $this->getMockBuilder(
  97. \Magento\Framework\App\Config\ScopeConfigInterface::class
  98. )->disableOriginalConstructor()->getMock();
  99. $this->_collection = $this->getMockBuilder(
  100. \Magento\Cron\Model\ResourceModel\Schedule\Collection::class
  101. )->setMethods(
  102. ['addFieldToFilter', 'load', '__wakeup']
  103. )->disableOriginalConstructor()->getMock();
  104. $this->_collection->expects($this->any())->method('addFieldToFilter')->will($this->returnSelf());
  105. $this->_collection->expects($this->any())->method('load')->will($this->returnSelf());
  106. $this->_scheduleFactory = $this->getMockBuilder(
  107. \Magento\Cron\Model\ScheduleFactory::class
  108. )->setMethods(
  109. ['create']
  110. )->disableOriginalConstructor()->getMock();
  111. $this->_request = $this->getMockBuilder(
  112. \Magento\Framework\App\Console\Request::class
  113. )->disableOriginalConstructor()->getMock();
  114. $this->_shell = $this->getMockBuilder(
  115. \Magento\Framework\ShellInterface::class
  116. )->disableOriginalConstructor()->setMethods(
  117. ['execute']
  118. )->getMock();
  119. $this->loggerMock = $this->createMock(\Psr\Log\LoggerInterface::class);
  120. $this->appStateMock = $this->getMockBuilder(\Magento\Framework\App\State::class)
  121. ->disableOriginalConstructor()
  122. ->getMock();
  123. $this->lockManagerMock = $this->getMockBuilder(\Magento\Framework\Lock\LockManagerInterface::class)
  124. ->disableOriginalConstructor()
  125. ->getMock();
  126. $this->lockManagerMock->method('lock')->willReturn(true);
  127. $this->lockManagerMock->method('unlock')->willReturn(true);
  128. $this->observer = $this->createMock(\Magento\Framework\Event\Observer::class);
  129. $this->dateTimeMock = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\DateTime::class)
  130. ->disableOriginalConstructor()
  131. ->getMock();
  132. $this->dateTimeMock->expects($this->any())->method('gmtTimestamp')->will($this->returnValue($this->time));
  133. $phpExecutableFinder = $this->createMock(\Symfony\Component\Process\PhpExecutableFinder::class);
  134. $phpExecutableFinder->expects($this->any())->method('find')->willReturn('php');
  135. $phpExecutableFinderFactory = $this->createMock(
  136. \Magento\Framework\Process\PhpExecutableFinderFactory::class
  137. );
  138. $phpExecutableFinderFactory->expects($this->any())->method('create')->willReturn($phpExecutableFinder);
  139. $this->scheduleResource = $this->getMockBuilder(\Magento\Cron\Model\ResourceModel\Schedule::class)
  140. ->disableOriginalConstructor()
  141. ->getMock();
  142. $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
  143. ->disableOriginalConstructor()
  144. ->getMock();
  145. $this->scheduleResource->method('getConnection')->willReturn($connection);
  146. $connection->method('delete')->willReturn(1);
  147. $this->statFactory = $this->getMockBuilder(StatFactory::class)
  148. ->setMethods(['create'])
  149. ->disableOriginalConstructor()
  150. ->getMock();
  151. $this->stat = $this->getMockBuilder(\Magento\Framework\Profiler\Driver\Standard\Stat::class)
  152. ->disableOriginalConstructor()
  153. ->getMock();
  154. $this->statFactory->expects($this->any())->method('create')->willReturn($this->stat);
  155. $this->_observer = new ProcessCronQueueObserver(
  156. $this->_objectManager,
  157. $this->_scheduleFactory,
  158. $this->_cache,
  159. $this->_config,
  160. $this->_scopeConfig,
  161. $this->_request,
  162. $this->_shell,
  163. $this->dateTimeMock,
  164. $phpExecutableFinderFactory,
  165. $this->loggerMock,
  166. $this->appStateMock,
  167. $this->statFactory,
  168. $this->lockManagerMock
  169. );
  170. }
  171. /**
  172. * Test case for not existed cron jobs in files but in data base is presented
  173. */
  174. public function testDispatchNoJobConfig()
  175. {
  176. $lastRun = $this->time + 10000000;
  177. $this->_cache->expects($this->atLeastOnce())->method('load')->will($this->returnValue($lastRun));
  178. $this->_scopeConfig->expects($this->atLeastOnce())->method('getValue')->will($this->returnValue(0));
  179. $this->_config->expects(
  180. $this->atLeastOnce()
  181. )->method(
  182. 'getJobs'
  183. )->will(
  184. $this->returnValue(['test_job1' => ['test_data']])
  185. );
  186. $schedule = $this->createPartialMock(\Magento\Cron\Model\Schedule::class, ['getJobCode', '__wakeup']);
  187. $schedule->expects($this->atLeastOnce())
  188. ->method('getJobCode')
  189. ->will($this->returnValue('not_existed_job_code'));
  190. $this->_collection->addItem($schedule);
  191. $scheduleMock = $this->getMockBuilder(
  192. \Magento\Cron\Model\Schedule::class
  193. )->disableOriginalConstructor()->getMock();
  194. $scheduleMock->expects($this->atLeastOnce())
  195. ->method('getCollection')
  196. ->will($this->returnValue($this->_collection));
  197. $this->_scheduleFactory->expects($this->atLeastOnce())
  198. ->method('create')
  199. ->will($this->returnValue($scheduleMock));
  200. $this->_observer->execute($this->observer);
  201. }
  202. /**
  203. * Test case checks if some job can't be locked
  204. */
  205. public function testDispatchCanNotLock()
  206. {
  207. $lastRun = $this->time + 10000000;
  208. $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun));
  209. $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(0));
  210. $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group'));
  211. $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400);
  212. $schedule = $this->getMockBuilder(
  213. \Magento\Cron\Model\Schedule::class
  214. )->setMethods(
  215. ['getJobCode', 'tryLockJob', 'getScheduledAt', '__wakeup', 'save', 'setFinishedAt']
  216. )->disableOriginalConstructor()->getMock();
  217. $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('test_job1'));
  218. $schedule->expects($this->atLeastOnce())->method('getScheduledAt')->will($this->returnValue($dateScheduledAt));
  219. $schedule->expects($this->once())->method('tryLockJob')->will($this->returnValue(false));
  220. $schedule->expects($this->never())->method('setFinishedAt');
  221. $abstractModel = $this->createMock(\Magento\Framework\Model\AbstractModel::class);
  222. $schedule->expects($this->any())->method('save')->will($this->returnValue($abstractModel));
  223. $this->_collection->addItem($schedule);
  224. $this->_config->expects(
  225. $this->exactly(2)
  226. )->method(
  227. 'getJobs'
  228. )->will(
  229. $this->returnValue(['test_group' => ['test_job1' => ['test_data']]])
  230. );
  231. $scheduleMock = $this->getMockBuilder(
  232. \Magento\Cron\Model\Schedule::class
  233. )->disableOriginalConstructor()->getMock();
  234. $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection));
  235. $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource));
  236. $this->_scheduleFactory->expects($this->atLeastOnce())
  237. ->method('create')
  238. ->will($this->returnValue($scheduleMock));
  239. $this->_observer->execute($this->observer);
  240. }
  241. /**
  242. * Test case catch exception if too late for schedule
  243. */
  244. public function testDispatchExceptionTooLate()
  245. {
  246. $exceptionMessage = 'Cron Job test_job1 is missed at 2017-07-30 15:00:00';
  247. $jobCode = 'test_job1';
  248. $lastRun = $this->time + 10000000;
  249. $this->_cache->expects($this->any())->method('load')->willReturn($lastRun);
  250. $this->_scopeConfig->expects($this->any())->method('getValue')->willReturn(0);
  251. $this->_request->expects($this->any())->method('getParam')->willReturn('test_group');
  252. $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400);
  253. $schedule = $this->getMockBuilder(
  254. \Magento\Cron\Model\Schedule::class
  255. )->setMethods(
  256. [
  257. 'getJobCode',
  258. 'tryLockJob',
  259. 'getScheduledAt',
  260. 'save',
  261. 'setStatus',
  262. 'setMessages',
  263. '__wakeup',
  264. 'getStatus',
  265. 'getMessages',
  266. 'getScheduleId',
  267. ]
  268. )->disableOriginalConstructor()->getMock();
  269. $schedule->expects($this->atLeastOnce())->method('getJobCode')->willReturn($jobCode);
  270. $schedule->expects($this->atLeastOnce())->method('getScheduledAt')->willReturn($dateScheduledAt);
  271. $schedule->expects($this->once())->method('tryLockJob')->willReturn(true);
  272. $schedule->expects(
  273. $this->any()
  274. )->method(
  275. 'setStatus'
  276. )->with(
  277. $this->equalTo(\Magento\Cron\Model\Schedule::STATUS_MISSED)
  278. )->willReturnSelf();
  279. $schedule->expects($this->once())->method('setMessages')->with($this->equalTo($exceptionMessage));
  280. $schedule->expects($this->atLeastOnce())->method('getStatus')->willReturn(Schedule::STATUS_MISSED);
  281. $schedule->expects($this->atLeastOnce())->method('getMessages')->willReturn($exceptionMessage);
  282. $schedule->expects($this->once())->method('save');
  283. $this->appStateMock->expects($this->once())->method('getMode')->willReturn(State::MODE_DEVELOPER);
  284. $this->loggerMock->expects($this->once())->method('info')
  285. ->with('Cron Job test_job1 is missed at 2017-07-30 15:00:00');
  286. $this->_collection->addItem($schedule);
  287. $this->_config->expects(
  288. $this->exactly(2)
  289. )->method(
  290. 'getJobs'
  291. )->willReturn(
  292. ['test_group' => ['test_job1' => ['test_data']]]
  293. );
  294. $scheduleMock = $this->getMockBuilder(\Magento\Cron\Model\Schedule::class)
  295. ->disableOriginalConstructor()->getMock();
  296. $scheduleMock->expects($this->any())->method('getCollection')->willReturn($this->_collection);
  297. $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource));
  298. $this->_scheduleFactory->expects($this->atLeastOnce())->method('create')->willReturn($scheduleMock);
  299. $this->_observer->execute($this->observer);
  300. }
  301. /**
  302. * Test case catch exception if callback not exist
  303. */
  304. public function testDispatchExceptionNoCallback()
  305. {
  306. $jobName = 'test_job1';
  307. $exceptionMessage = 'No callbacks found for cron job ' . $jobName;
  308. $exception = new \Exception(__($exceptionMessage));
  309. $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400);
  310. $schedule = $this->getMockBuilder(
  311. \Magento\Cron\Model\Schedule::class
  312. )->setMethods(
  313. ['getJobCode', 'tryLockJob', 'getScheduledAt', 'save', 'setStatus', 'setMessages', '__wakeup', 'getStatus']
  314. )->disableOriginalConstructor()->getMock();
  315. $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('test_job1'));
  316. $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue($dateScheduledAt));
  317. $schedule->expects($this->once())->method('tryLockJob')->will($this->returnValue(true));
  318. $schedule->expects(
  319. $this->once()
  320. )->method(
  321. 'setStatus'
  322. )->with(
  323. $this->equalTo(\Magento\Cron\Model\Schedule::STATUS_ERROR)
  324. )->will(
  325. $this->returnSelf()
  326. );
  327. $schedule->expects($this->once())->method('setMessages')->with($this->equalTo($exceptionMessage));
  328. $schedule->expects($this->any())->method('getStatus')->willReturn(Schedule::STATUS_ERROR);
  329. $schedule->expects($this->once())->method('save');
  330. $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group'));
  331. $this->_collection->addItem($schedule);
  332. $this->loggerMock->expects($this->once())->method('critical')->with($exception);
  333. $jobConfig = ['test_group' => [$jobName => ['instance' => 'Some_Class']]];
  334. $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig));
  335. $lastRun = $this->time + 10000000;
  336. $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun));
  337. $this->_scopeConfig->expects($this->any())
  338. ->method('getValue')
  339. ->will($this->returnValue($this->time + 86400));
  340. $scheduleMock = $this->getMockBuilder(
  341. \Magento\Cron\Model\Schedule::class
  342. )->disableOriginalConstructor()->getMock();
  343. $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection));
  344. $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource));
  345. $this->_scheduleFactory->expects($this->once())->method('create')->will($this->returnValue($scheduleMock));
  346. $this->_observer->execute($this->observer);
  347. }
  348. /**
  349. * Test case catch exception if callback is not callable or throws exception
  350. *
  351. * @param string $cronJobType
  352. * @param mixed $cronJobObject
  353. * @param string $exceptionMessage
  354. * @param int $saveCalls
  355. * @param \Exception $exception
  356. *
  357. * @dataProvider dispatchExceptionInCallbackDataProvider
  358. */
  359. public function testDispatchExceptionInCallback(
  360. $cronJobType,
  361. $cronJobObject,
  362. $exceptionMessage,
  363. $saveCalls,
  364. $exception
  365. ) {
  366. $jobConfig = [
  367. 'test_group' => [
  368. 'test_job1' => ['instance' => $cronJobType, 'method' => 'execute'],
  369. ],
  370. ];
  371. $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group'));
  372. $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400);
  373. $schedule = $this->getMockBuilder(
  374. \Magento\Cron\Model\Schedule::class
  375. )->setMethods(
  376. ['getJobCode', 'tryLockJob', 'getScheduledAt', 'save', 'setStatus', 'setMessages', '__wakeup', 'getStatus']
  377. )->disableOriginalConstructor()->getMock();
  378. $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('test_job1'));
  379. $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue($dateScheduledAt));
  380. $schedule->expects($this->once())->method('tryLockJob')->will($this->returnValue(true));
  381. $schedule->expects($this->once())
  382. ->method('setStatus')
  383. ->with($this->equalTo(\Magento\Cron\Model\Schedule::STATUS_ERROR))
  384. ->will($this->returnSelf());
  385. $schedule->expects($this->once())->method('setMessages')->with($this->equalTo($exceptionMessage));
  386. $schedule->expects($this->any())->method('getStatus')->willReturn(Schedule::STATUS_ERROR);
  387. $schedule->expects($this->exactly($saveCalls))->method('save');
  388. $this->loggerMock->expects($this->once())->method('critical')->with($exception);
  389. $this->_collection->addItem($schedule);
  390. $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig));
  391. $lastRun = $this->time + 10000000;
  392. $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun));
  393. $this->_scopeConfig->expects($this->any())
  394. ->method('getValue')
  395. ->will($this->returnValue($this->time + 86400));
  396. $scheduleMock = $this->getMockBuilder(
  397. \Magento\Cron\Model\Schedule::class
  398. )->disableOriginalConstructor()->getMock();
  399. $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection));
  400. $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource));
  401. $this->_scheduleFactory->expects($this->once())->method('create')->will($this->returnValue($scheduleMock));
  402. $this->_objectManager
  403. ->expects($this->once())
  404. ->method('create')
  405. ->with($this->equalTo($cronJobType))
  406. ->will($this->returnValue($cronJobObject));
  407. $this->_observer->execute($this->observer);
  408. }
  409. /**
  410. * @return array
  411. */
  412. public function dispatchExceptionInCallbackDataProvider()
  413. {
  414. $throwable = new \TypeError();
  415. return [
  416. 'non-callable callback' => [
  417. 'Not_Existed_Class',
  418. '',
  419. 'Invalid callback: Not_Existed_Class::execute can\'t be called',
  420. 1,
  421. new \Exception(__('Invalid callback: Not_Existed_Class::execute can\'t be called'))
  422. ],
  423. 'exception in execution' => [
  424. 'CronJobException',
  425. new \Magento\Cron\Test\Unit\Model\CronJobException(),
  426. 'Test exception',
  427. 2,
  428. new \Exception(__('Test exception'))
  429. ],
  430. 'throwable in execution' => [
  431. 'CronJobException',
  432. new \Magento\Cron\Test\Unit\Model\CronJobException(
  433. $throwable
  434. ),
  435. 'Error when running a cron job',
  436. 2,
  437. new \RuntimeException(
  438. 'Error when running a cron job',
  439. 0,
  440. $throwable
  441. )
  442. ],
  443. ];
  444. }
  445. /**
  446. * Test case, successfully run job
  447. */
  448. public function testDispatchRunJob()
  449. {
  450. $jobConfig = [
  451. 'test_group' => ['test_job1' => ['instance' => 'CronJob', 'method' => 'execute']],
  452. ];
  453. $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group'));
  454. $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400);
  455. $scheduleMethods = [
  456. 'getJobCode',
  457. 'tryLockJob',
  458. 'getScheduledAt',
  459. 'save',
  460. 'setStatus',
  461. 'setMessages',
  462. 'setExecutedAt',
  463. 'setFinishedAt',
  464. '__wakeup',
  465. ];
  466. /** @var \Magento\Cron\Model\Schedule|\PHPUnit_Framework_MockObject_MockObject $schedule */
  467. $schedule = $this->getMockBuilder(
  468. \Magento\Cron\Model\Schedule::class
  469. )->setMethods(
  470. $scheduleMethods
  471. )->disableOriginalConstructor()->getMock();
  472. $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('test_job1'));
  473. $schedule->expects($this->atLeastOnce())->method('getScheduledAt')->will($this->returnValue($dateScheduledAt));
  474. $schedule->expects($this->atLeastOnce())->method('tryLockJob')->will($this->returnValue(true));
  475. $schedule->expects($this->any())->method('setFinishedAt')->willReturnSelf();
  476. // cron start to execute some job
  477. $schedule->expects($this->any())->method('setExecutedAt')->will($this->returnSelf());
  478. $schedule->expects($this->atLeastOnce())->method('save');
  479. // cron end execute some job
  480. $schedule->expects(
  481. $this->atLeastOnce()
  482. )->method(
  483. 'setStatus'
  484. )->with(
  485. $this->equalTo(\Magento\Cron\Model\Schedule::STATUS_SUCCESS)
  486. )->willReturnSelf();
  487. $schedule->expects($this->at(8))->method('save');
  488. $this->_collection->addItem($schedule);
  489. $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig));
  490. $lastRun = $this->time + 10000000;
  491. $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun));
  492. $this->_scopeConfig->expects($this->any())
  493. ->method('getValue')
  494. ->will($this->returnValue($this->time + 86400));
  495. $scheduleMock = $this->getMockBuilder(
  496. \Magento\Cron\Model\Schedule::class
  497. )->disableOriginalConstructor()->getMock();
  498. $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection));
  499. $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource));
  500. $this->_scheduleFactory->expects($this->once(2))->method('create')->will($this->returnValue($scheduleMock));
  501. $testCronJob = $this->getMockBuilder('CronJob')->setMethods(['execute'])->getMock();
  502. $testCronJob->expects($this->atLeastOnce())->method('execute')->with($schedule);
  503. $this->_objectManager->expects(
  504. $this->once()
  505. )->method(
  506. 'create'
  507. )->with(
  508. $this->equalTo('CronJob')
  509. )->will(
  510. $this->returnValue($testCronJob)
  511. );
  512. $this->_observer->execute($this->observer);
  513. }
  514. /**
  515. * Testing _generate(), iterate over saved cron jobs
  516. */
  517. public function testDispatchNotGenerate()
  518. {
  519. $jobConfig = [
  520. 'test_group' => ['test_job1' => ['instance' => 'CronJob', 'method' => 'execute']],
  521. ];
  522. $this->_config->expects($this->at(0))->method('getJobs')->will($this->returnValue($jobConfig));
  523. $this->_config->expects(
  524. $this->at(1)
  525. )->method(
  526. 'getJobs'
  527. )->will(
  528. $this->returnValue(['test_group' => []])
  529. );
  530. $this->_config->expects($this->at(2))->method('getJobs')->will($this->returnValue($jobConfig));
  531. $this->_config->expects($this->at(3))->method('getJobs')->will($this->returnValue($jobConfig));
  532. $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group'));
  533. $this->_cache->expects(
  534. $this->at(0)
  535. )->method(
  536. 'load'
  537. )->with(
  538. $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . 'test_group')
  539. )->will(
  540. $this->returnValue($this->time + 10000000)
  541. );
  542. $this->_cache->expects(
  543. $this->at(1)
  544. )->method(
  545. 'load'
  546. )->with(
  547. $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT . 'test_group')
  548. )->will(
  549. $this->returnValue($this->time - 10000000)
  550. );
  551. $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(0));
  552. $schedule = $this->getMockBuilder(
  553. \Magento\Cron\Model\Schedule::class
  554. )->setMethods(
  555. ['getJobCode', 'getScheduledAt', '__wakeup']
  556. )->disableOriginalConstructor()->getMock();
  557. $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('job_code1'));
  558. $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue('* * * * *'));
  559. $this->_collection->addItem(new \Magento\Framework\DataObject());
  560. $this->_collection->addItem($schedule);
  561. $this->_cache->expects($this->any())->method('save');
  562. $scheduleMock = $this->getMockBuilder(
  563. \Magento\Cron\Model\Schedule::class
  564. )->disableOriginalConstructor()->getMock();
  565. $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection));
  566. $this->_scheduleFactory->expects($this->any())->method('create')->will($this->returnValue($scheduleMock));
  567. $this->_scheduleFactory->expects($this->any())->method('create')->will($this->returnValue($schedule));
  568. $this->_observer->execute($this->observer);
  569. }
  570. /**
  571. * Testing _generate(), iterate over saved cron jobs and generate jobs
  572. */
  573. public function testDispatchGenerate()
  574. {
  575. $jobConfig = [
  576. 'default' => [
  577. 'test_job1' => [
  578. 'instance' => 'CronJob',
  579. 'method' => 'execute',
  580. ],
  581. ],
  582. ];
  583. $jobs = [
  584. 'default' => [
  585. 'job1' => ['config_path' => 'test/path'],
  586. 'job2' => ['schedule' => ''],
  587. 'job3' => ['schedule' => '* * * * *'],
  588. ],
  589. ];
  590. $this->_config->expects($this->at(0))->method('getJobs')->willReturn($jobConfig);
  591. $this->_config->expects($this->at(1))->method('getJobs')->willReturn($jobs);
  592. $this->_config->expects($this->at(2))->method('getJobs')->willReturn($jobs);
  593. $this->_config->expects($this->at(3))->method('getJobs')->willReturn($jobs);
  594. $this->_request->expects($this->any())->method('getParam')->willReturn('default');
  595. $this->_cache->expects(
  596. $this->at(0)
  597. )->method(
  598. 'load'
  599. )->with(
  600. $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . 'default')
  601. )->willReturn($this->time + 10000000);
  602. $this->_cache->expects(
  603. $this->at(1)
  604. )->method(
  605. 'load'
  606. )->with(
  607. $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT . 'default')
  608. )->willReturn($this->time - 10000000);
  609. $this->_scopeConfig->expects($this->any())->method('getValue')->willReturnMap(
  610. [
  611. [
  612. 'system/cron/default/schedule_generate_every',
  613. \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
  614. null,
  615. 0
  616. ],
  617. [
  618. 'system/cron/default/schedule_ahead_for',
  619. \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
  620. null,
  621. 2
  622. ]
  623. ]
  624. );
  625. $schedule = $this->getMockBuilder(
  626. \Magento\Cron\Model\Schedule::class
  627. )->setMethods(
  628. ['getJobCode', 'save', 'getScheduledAt', 'unsScheduleId', 'trySchedule', 'getCollection', 'getResource']
  629. )->disableOriginalConstructor()->getMock();
  630. $schedule->expects($this->any())->method('getJobCode')->willReturn('job_code1');
  631. $schedule->expects($this->once())->method('getScheduledAt')->willReturn('* * * * *');
  632. $schedule->expects($this->any())->method('unsScheduleId')->willReturnSelf();
  633. $schedule->expects($this->any())->method('trySchedule')->willReturnSelf();
  634. $schedule->expects($this->any())->method('getCollection')->willReturn($this->_collection);
  635. $schedule->expects($this->atLeastOnce())->method('save')->willReturnSelf();
  636. $schedule->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource));
  637. $this->_collection->addItem(new \Magento\Framework\DataObject());
  638. $this->_collection->addItem($schedule);
  639. $this->_cache->expects($this->any())->method('save');
  640. $this->_scheduleFactory->expects($this->any())->method('create')->willReturn($schedule);
  641. $this->_observer->execute($this->observer);
  642. }
  643. /**
  644. * Test case without saved cron jobs in data base
  645. */
  646. public function testDispatchCleanup()
  647. {
  648. $jobConfig = [
  649. 'test_group' => ['test_job1' => ['instance' => 'CronJob', 'method' => 'execute']],
  650. ];
  651. $dateExecutedAt = date('Y-m-d H:i:s', $this->time - 86400);
  652. $schedule = $this->getMockBuilder(
  653. \Magento\Cron\Model\Schedule::class
  654. )->disableOriginalConstructor()->setMethods(
  655. ['getExecutedAt', 'getStatus', 'delete', '__wakeup']
  656. )->getMock();
  657. $schedule->expects($this->any())->method('getExecutedAt')->will($this->returnValue($dateExecutedAt));
  658. $schedule->expects($this->any())->method('getStatus')->will($this->returnValue('success'));
  659. $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group'));
  660. $this->_collection->addItem($schedule);
  661. $this->_config->expects($this->atLeastOnce())->method('getJobs')->will($this->returnValue($jobConfig));
  662. $this->_cache->expects($this->at(0))->method('load')->will($this->returnValue($this->time + 10000000));
  663. $this->_cache->expects($this->at(1))->method('load')->will($this->returnValue($this->time - 10000000));
  664. $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(0));
  665. $scheduleMock = $this->getMockBuilder(
  666. \Magento\Cron\Model\Schedule::class
  667. )->disableOriginalConstructor()->getMock();
  668. $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection));
  669. $this->_scheduleFactory->expects($this->at(0))->method('create')->will($this->returnValue($scheduleMock));
  670. $collection = $this->getMockBuilder(
  671. \Magento\Cron\Model\ResourceModel\Schedule\Collection::class
  672. )->setMethods(
  673. ['addFieldToFilter', 'load', '__wakeup']
  674. )->disableOriginalConstructor()->getMock();
  675. $collection->expects($this->any())->method('addFieldToFilter')->will($this->returnSelf());
  676. $collection->expects($this->any())->method('load')->will($this->returnSelf());
  677. $collection->addItem($schedule);
  678. $scheduleMock = $this->getMockBuilder(
  679. \Magento\Cron\Model\Schedule::class
  680. )->setMethods(['getCollection', 'getResource'])->disableOriginalConstructor()->getMock();
  681. $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($collection));
  682. $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource));
  683. $this->_scheduleFactory->expects($this->any())->method('create')->will($this->returnValue($scheduleMock));
  684. $this->_observer->execute($this->observer);
  685. }
  686. public function testMissedJobsCleanedInTime()
  687. {
  688. /* 1. Initialize dependencies of _cleanup() method which is called first */
  689. $scheduleMock = $this->getMockBuilder(
  690. \Magento\Cron\Model\Schedule::class
  691. )->disableOriginalConstructor()->getMock();
  692. $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection));
  693. //get configuration value CACHE_KEY_LAST_HISTORY_CLEANUP_AT in the "_cleanup()"
  694. $this->_cache->expects($this->at(0))->method('load')->will($this->returnValue($this->time - 10000000));
  695. $this->_scheduleFactory->expects($this->at(0))->method('create')->will($this->returnValue($scheduleMock));
  696. /* 2. Initialize dependencies of _generate() method which is called second */
  697. $jobConfig = [
  698. 'test_group' => ['test_job1' => ['instance' => 'CronJob', 'method' => 'execute']],
  699. ];
  700. //get configuration value CACHE_KEY_LAST_HISTORY_CLEANUP_AT in the "_generate()"
  701. $this->_cache->expects($this->at(2))->method('load')->will($this->returnValue($this->time + 10000000));
  702. $this->_scheduleFactory->expects($this->at(2))->method('create')->will($this->returnValue($scheduleMock));
  703. $this->_config->expects($this->atLeastOnce())->method('getJobs')->will($this->returnValue($jobConfig));
  704. $this->_scopeConfig->expects($this->any())->method('getValue')
  705. ->willReturnMap([
  706. ['system/cron/test_group/use_separate_process', 0],
  707. ['system/cron/test_group/history_cleanup_every', 10],
  708. ['system/cron/test_group/schedule_lifetime', 2*24*60],
  709. ['system/cron/test_group/history_success_lifetime', 0],
  710. ['system/cron/test_group/history_failure_lifetime', 0],
  711. ['system/cron/test_group/schedule_generate_every', 0],
  712. ]);
  713. $this->_collection->expects($this->any())->method('addFieldToFilter')->will($this->returnSelf());
  714. $this->_collection->expects($this->any())->method('load')->will($this->returnSelf());
  715. $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection));
  716. $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource));
  717. $this->_scheduleFactory->expects($this->at(1))->method('create')->will($this->returnValue($scheduleMock));
  718. $this->_observer->execute($this->observer);
  719. }
  720. }