ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
CronJobScheduleTest.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
23 
24 class CronJobScheduleTest extends TestCase
25 {
26  private static DateTimeImmutable $now;
28 
29  private static function getJob(
30  bool $has_flexible_schedule,
31  CronJobScheduleType $default_schedule_type,
32  ?int $default_schedule_value,
33  CronJobScheduleType $schedule_type,
34  ?int $schedule_value
35  ): ilCronJob {
36  $job_instance = new class (
37  $has_flexible_schedule,
38  $default_schedule_type,
39  $default_schedule_value,
40  $schedule_type,
41  $schedule_value
42  ) extends
43  ilCronJob {
44  public function __construct(
45  private readonly bool $has_flexible_schedule,
46  private readonly CronJobScheduleType $default_schedule_type,
47  private readonly ?int $default_schedule_value,
48  CronJobScheduleType $schedule_type,
49  ?int $schedule_value
50  ) {
51  $this->schedule_type = $schedule_type;
52  $this->schedule_value = $schedule_value;
53  }
54 
55  public function getId(): string
56  {
57  return 'phpunit';
58  }
59 
60  public function getTitle(): string
61  {
62  return 'phpunit';
63  }
64 
65  public function getDescription(): string
66  {
67  return 'phpunit';
68  }
69 
70  public function hasAutoActivation(): bool
71  {
72  return false;
73  }
74 
75  public function hasFlexibleSchedule(): bool
76  {
77  return $this->has_flexible_schedule;
78  }
79 
80  public function getDefaultScheduleType(): CronJobScheduleType
81  {
82  return $this->default_schedule_type;
83  }
84 
85  public function getDefaultScheduleValue(): ?int
86  {
87  return $this->default_schedule_value;
88  }
89 
90  public function run(): ilCronJobResult
91  {
92  return new ilCronJobResult();
93  }
94  };
95 
96  $job_instance->setDateTimeProvider(function (): DateTimeImmutable {
97  return self::$now;
98  });
99 
100  return $job_instance;
101  }
102 
106  public static function jobProvider(): array
107  {
108  return [
109  'Manual Run is Always Due' => [
110  self::getJob(
111  true,
112  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
113  null,
114  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
115  null
116  ),
117  true,
118  null,
119  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
120  null,
121  true
122  ],
123  'Job Without Any Run is Always Due' => [
124  self::getJob(
125  true,
126  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
127  null,
128  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
129  null
130  ),
131  false,
132  null,
133  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
134  null,
135  true
136  ],
137  'Daily Schedule / Did not run Today' => [
138  self::getJob(
139  true,
140  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
141  null,
142  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
143  null
144  ),
145  false,
146  function (): DateTimeImmutable {
147  self::$now = new DateTimeImmutable('@' . time());
148 
149  return self::$now->modify('-1 day');
150  },
151  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
152  null,
153  true
154  ],
155  'Daily Schedule / Did run Today' => [
156  self::getJob(
157  true,
158  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
159  null,
160  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
161  null
162  ),
163  false,
164  function (): DateTimeImmutable {
165  self::$now = new DateTimeImmutable('@' . time());
166 
167  return self::$now;
168  },
169  CronJobScheduleType::SCHEDULE_TYPE_DAILY,
170  null,
171  false
172  ],
173  'Weekly Schedule / Did not run this Week' => [
174  self::getJob(
175  true,
176  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
177  null,
178  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
179  null
180  ),
181  false,
182  function (): DateTimeImmutable {
183  self::$now = new DateTimeImmutable('@' . time());
184 
185  return self::$now->modify('-1 week');
186  },
187  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
188  null,
189  true
190  ],
191  'Weekly Schedule / Did run this Week' => [
192  self::getJob(
193  true,
194  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
195  null,
196  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
197  null
198  ),
199  false,
200  function (): DateTimeImmutable {
201  self::$now = new DateTimeImmutable('@' . time());
202 
203  return self::$now->modify('monday this week');
204  },
205  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
206  null,
207  false
208  ],
209  'Monthly Schedule / Did not run this Month' => [
210  self::getJob(
211  true,
212  CronJobScheduleType::SCHEDULE_TYPE_MONTHLY,
213  null,
214  CronJobScheduleType::SCHEDULE_TYPE_MONTHLY,
215  null
216  ),
217  false,
218  function (): DateTimeImmutable {
219  self::$now = new DateTimeImmutable('@' . time());
220 
221  return self::$now->modify('last day of last month');
222  },
223  CronJobScheduleType::SCHEDULE_TYPE_MONTHLY,
224  null,
225  true
226  ],
227  'Monthly Schedule / Did run this Month' => [
228  self::getJob(
229  true,
230  CronJobScheduleType::SCHEDULE_TYPE_MONTHLY,
231  null,
232  CronJobScheduleType::SCHEDULE_TYPE_MONTHLY,
233  null
234  ),
235  false,
236  function (): DateTimeImmutable {
237  self::$now = new DateTimeImmutable('@' . time());
238 
239  return self::$now->modify('first day of this month');
240  },
241  CronJobScheduleType::SCHEDULE_TYPE_MONTHLY,
242  null,
243  false
244  ],
245  'Yearly Schedule / Did not run this Year' => [
246  self::getJob(
247  true,
249  null,
251  null
252  ),
253  false,
254  function (): DateTimeImmutable {
255  self::$now = new DateTimeImmutable('@' . time());
256 
257  return self::$now->modify('-1 year');
258  },
260  null,
261  true
262  ],
263  'Yearly Schedule / Did run this Year' => [
264  self::getJob(
265  true,
267  null,
269  null
270  ),
271  false,
272  function (): DateTimeImmutable {
273  self::$now = new DateTimeImmutable('@' . time());
274 
275  return self::$now->modify('first day of January this year');
276  },
278  null,
279  false
280  ],
281  'Quarterly Schedule / Did not run this Quarter' => [
282  self::getJob(
283  true,
284  CronJobScheduleType::SCHEDULE_TYPE_QUARTERLY,
285  null,
286  CronJobScheduleType::SCHEDULE_TYPE_QUARTERLY,
287  null
288  ),
289  false,
290  function (): DateTimeImmutable {
291  self::$now = new DateTimeImmutable('@' . time());
292 
293  $offset = (((int) self::$now->format('n')) - 1) % 3;
294  self::$this_quarter_start = self::$now->modify("first day of -$offset month midnight");
295 
296  return self::$this_quarter_start->modify('-1 seconds');
297  },
298  CronJobScheduleType::SCHEDULE_TYPE_QUARTERLY,
299  null,
300  true
301  ],
302  'Quarterly Schedule / Did run this Quarter' => [
303  self::getJob(
304  true,
305  CronJobScheduleType::SCHEDULE_TYPE_QUARTERLY,
306  null,
307  CronJobScheduleType::SCHEDULE_TYPE_QUARTERLY,
308  null
309  ),
310  false,
311  function (): DateTimeImmutable {
312  self::$now = new DateTimeImmutable('@' . time());
313 
314  $offset = (((int) self::$now->format('n')) - 1) % 3;
315  self::$this_quarter_start = self::$now->modify("first day of -$offset month midnight");
316 
317  return self::$this_quarter_start->modify('+30 seconds');
318  },
319  CronJobScheduleType::SCHEDULE_TYPE_QUARTERLY,
320  null,
321  false
322  ],
323  'Minutely Schedule / Did not run this Minute' => [
324  self::getJob(
325  true,
326  CronJobScheduleType::SCHEDULE_TYPE_IN_MINUTES,
327  1,
328  CronJobScheduleType::SCHEDULE_TYPE_IN_MINUTES,
329  1
330  ),
331  false,
332  function (): DateTimeImmutable {
333  self::$now = new DateTimeImmutable('@' . time());
334 
335  return self::$now->modify('-1 minute');
336  },
337  CronJobScheduleType::SCHEDULE_TYPE_IN_MINUTES,
338  1,
339  true
340  ],
341  'Minutely Schedule / Did run this Minute' => [
342  self::getJob(
343  true,
344  CronJobScheduleType::SCHEDULE_TYPE_IN_MINUTES,
345  1,
346  CronJobScheduleType::SCHEDULE_TYPE_IN_MINUTES,
347  1
348  ),
349  false,
350  function (): DateTimeImmutable {
351  self::$now = new DateTimeImmutable('@' . time());
352 
353  return self::$now->modify('-30 seconds');
354  },
355  CronJobScheduleType::SCHEDULE_TYPE_IN_MINUTES,
356  1,
357  false
358  ],
359  'Hourly Schedule / Did not run this Hour' => [
360  self::getJob(
361  true,
362  CronJobScheduleType::SCHEDULE_TYPE_IN_HOURS,
363  7,
364  CronJobScheduleType::SCHEDULE_TYPE_IN_HOURS,
365  7
366  ),
367  false,
368  function (): DateTimeImmutable {
369  self::$now = new DateTimeImmutable('@' . time());
370 
371  return self::$now->modify('-7 hours');
372  },
373  CronJobScheduleType::SCHEDULE_TYPE_IN_HOURS,
374  7,
375  true
376  ],
377  'Hourly Schedule / Did run this Hour' => [
378  self::getJob(
379  true,
380  CronJobScheduleType::SCHEDULE_TYPE_IN_HOURS,
381  7,
382  CronJobScheduleType::SCHEDULE_TYPE_IN_HOURS,
383  7
384  ),
385  false,
386  function (): DateTimeImmutable {
387  self::$now = new DateTimeImmutable('@' . time());
388 
389  return self::$now->modify('-7 hours +30 seconds');
390  },
391  CronJobScheduleType::SCHEDULE_TYPE_IN_HOURS,
392  7,
393  false
394  ],
395  'Every 5 Days Schedule / Did not run for 5 Days' => [
396  self::getJob(
397  true,
398  CronJobScheduleType::SCHEDULE_TYPE_IN_DAYS,
399  5,
400  CronJobScheduleType::SCHEDULE_TYPE_IN_DAYS,
401  5
402  ),
403  false,
404  function (): DateTimeImmutable {
405  self::$now = new DateTimeImmutable('@' . time());
406 
407  return self::$now->modify('-5 days');
408  },
409  CronJobScheduleType::SCHEDULE_TYPE_IN_DAYS,
410  5,
411  true
412  ],
413  'Every 5 Days Schedule / Did run withing the last 5 Days' => [
414  self::getJob(
415  true,
416  CronJobScheduleType::SCHEDULE_TYPE_IN_DAYS,
417  5,
418  CronJobScheduleType::SCHEDULE_TYPE_IN_DAYS,
419  5
420  ),
421  false,
422  function (): DateTimeImmutable {
423  self::$now = new DateTimeImmutable('@' . time());
424 
425  return self::$now->modify('-4 days');
426  },
427  CronJobScheduleType::SCHEDULE_TYPE_IN_DAYS,
428  5,
429  false
430  ]
431  ];
432  }
433 
438  public function testSchedule(
439  ilCronJob $job_instance,
440  bool $is_manual_run,
441  ?callable $last_run_datetime_callable,
442  CronJobScheduleType $schedule_type,
443  ?int $schedule_value,
444  bool $should_be_due
445  ): void {
446  $last_run_datetime = $last_run_datetime_callable ? $last_run_datetime_callable() : null;
447  self::assertEquals(
448  $should_be_due,
449  $job_instance->isDue($last_run_datetime, $schedule_type, $schedule_value, $is_manual_run),
450  'Last run: ' . ($last_run_datetime ? $last_run_datetime->format(DATE_ATOM) : 'never')
451  );
452  }
453 
454  public static function weeklyScheduleProvider(): Generator
455  {
456  yield 'Different Week' => [
457  self::getJob(
458  true,
459  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
460  null,
461  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
462  null
463  ),
464  function (): DateTimeImmutable {
465  self::$now = new DateTimeImmutable(
466  '@1672570104'
467  ); // Sun Jan 01 2023 10:48:24 GMT+0000 (year: 2023 / week: 52)
468 
469  return self::$now->modify('-1 week'); // Sun Dec 25 2022 10:48:24 GMT+0000 (year: 2022 / week: 51)
470  },
471  true
472  ];
473 
474  yield 'Same Week and Year, but different Month: December (now) and January (Last run)' => [
475  self::getJob(
476  true,
477  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
478  null,
479  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
480  null
481  ),
482  function (): DateTimeImmutable {
483  self::$now = new DateTimeImmutable(
484  '@1703669703'
485  ); // Wed Dec 27 2023 09:35:03 GMT+0000 (year: 2023 / week: 52 / month: 12)
486 
487  return new DateTimeImmutable(
488  '@1672570104'
489  ); // Sun Jan 01 2023 10:48:24 GMT+0000 (year: 2023 / week: 52 / month: 1)
490  },
491  true
492  ];
493 
494  yield 'Same Week and Year and same Month: January' => [
495  self::getJob(
496  true,
497  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
498  null,
499  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
500  null
501  ),
502  function (): DateTimeImmutable {
503  self::$now = new DateTimeImmutable(
504  '@1704188103'
505  ); // Tue Jan 02 2024 09:35:03 GMT+0000 (year: 2024 / week: 1 / month: 1)
506 
507  return self::$now->modify(
508  '-1 day'
509  ); // Mon Jan 01 2024 09:35:03 GMT+0000 (year: 2024 / week: 1 / month: 1)
510  },
511  false
512  ];
513 
514  yield 'Same Week (52nd), but Year Difference > 1' => [
515  self::getJob(
516  true,
517  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
518  null,
519  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
520  null
521  ),
522  function (): DateTimeImmutable {
523  self::$now = new DateTimeImmutable(
524  '@1672570104'
525  ); // Sun Jan 01 2023 10:48:24 GMT+0000 (year: 2023 / week: 52)
526 
527  return self::$now->modify('tuesday this week')->modify(
528  '-1 year'
529  ); // Mon Dec 27 2021 10:48:24 GMT+0000 (year: 2021 / week: 52)
530  },
531  true
532  ];
533 
534  yield 'Same Week (52nd) in different Years, but Turn of the Year' => [
535  self::getJob(
536  true,
537  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
538  null,
539  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
540  null
541  ),
542  function (): DateTimeImmutable {
543  self::$now = new DateTimeImmutable(
544  '@1672570104'
545  ); // Sun Jan 01 2023 10:48:24 GMT+0000 (year: 2023 / week: 52 / month: 1)
546 
547  return self::$now->modify(
548  'monday this week'
549  ); // Mon Dec 26 2022 10:48:24 GMT+0000 (year: 2022 / week: 52 / month: 12)
550  },
551  false
552  ];
553 
554  yield 'Same Week (52nd) in different Years, but not Turn of the Year' => [
555  self::getJob(
556  true,
557  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
558  null,
559  CronJobScheduleType::SCHEDULE_TYPE_WEEKLY,
560  null
561  ),
562  function (): DateTimeImmutable {
563  self::$now = new DateTimeImmutable(
564  '@1703669703'
565  ); // Wed Dec 27 2023 09:35:03 GMT+0000 (year: 2023 / week: 52 / month: 12)
566 
567  return new DateTimeImmutable(
568  '@1672012800'
569  ); // Mon Dec 26 2022 00:00:00 GMT+0000 (year: 2022 / week: 52 / month: 12)
570  },
571  true
572  ];
573  }
574 
579  public function testWeeklySchedules(
580  ilCronJob $job_instance,
581  callable $last_run_datetime_provider,
582  bool $should_be_due
583  ): void {
584  $last_run_datetime = $last_run_datetime_provider();
585 
586  self::assertSame(
587  $should_be_due,
588  $job_instance->isDue(
589  $last_run_datetime,
590  $job_instance->getScheduleType(),
591  $job_instance->getScheduleValue(),
592  false
593  ),
594  'Last run: ' . $last_run_datetime->format(DATE_ATOM)
595  );
596  }
597 }
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
isDue(?DateTimeImmutable $last_run, ?CronJobScheduleType $schedule_type, ?int $schedule_value, bool $is_manually_executed=false)
testWeeklySchedules(ilCronJob $job_instance, callable $last_run_datetime_provider, bool $should_be_due)
weeklyScheduleProvider
static DateTimeImmutable $this_quarter_start
static getJob(bool $has_flexible_schedule, CronJobScheduleType $default_schedule_type, ?int $default_schedule_value, CronJobScheduleType $schedule_type, ?int $schedule_value)
testSchedule(ilCronJob $job_instance, bool $is_manual_run, ?callable $last_run_datetime_callable, CronJobScheduleType $schedule_type, ?int $schedule_value, bool $should_be_due)
jobProvider
static DateTimeImmutable $now
__construct(Container $dic, ilPlugin $plugin)
getScheduleValue()
Get current schedule value (if flexible)
getScheduleType()
Get current schedule type (if flexible)