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