From 9f77a2c31e958fec96fc1340b2ff4885dc8d9038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Fri, 7 Jul 2023 17:08:56 +0200 Subject: [PATCH 01/12] Add ability to query JobExecution in start/end time ranges --- .../src/DoctrineDBALJobExecutionStorage.php | 22 +++++++ .../DoctrineDBALJobExecutionStorageTest.php | 42 ++++++++++++++ .../Storage/FilesystemJobExecutionStorage.php | 20 +++++++ src/batch/src/Storage/Query.php | 14 ++++- src/batch/src/Storage/QueryBuilder.php | 58 ++++++++++++++++++- src/batch/src/Storage/TimeFilter.php | 29 ++++++++++ .../FilesystemJobExecutionStorageTest.php | 56 ++++++++++++++++++ src/batch/tests/Storage/QueryBuilderTest.php | 41 +++++++++++-- 8 files changed, 275 insertions(+), 7 deletions(-) create mode 100644 src/batch/src/Storage/TimeFilter.php diff --git a/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php b/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php index 21c8f278..1f046efa 100644 --- a/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php +++ b/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php @@ -175,6 +175,28 @@ public function query(Query $query): iterable $queryTypes['statuses'] = Connection::PARAM_INT_ARRAY; } + $startDateFrom = $query->startTime()?->getFrom(); + if ($startDateFrom) { + $qb->andWhere($qb->expr()->gte('start_time', ':startDateFrom')); + $queryParameters['startDateFrom'] = $startDateFrom; + } + $startDateTo = $query->startTime()?->getTo(); + if ($startDateTo) { + $qb->andWhere($qb->expr()->lte('start_time', ':startDateTo')); + $queryParameters['startDateTo'] = $startDateTo; + } + + $endDateFrom = $query->endTime()?->getFrom(); + if ($endDateFrom) { + $qb->andWhere($qb->expr()->gte('end_time', ':endDateFrom')); + $queryParameters['endDateFrom'] = $endDateFrom; + } + $endDateTo = $query->endTime()?->getTo(); + if ($endDateTo) { + $qb->andWhere($qb->expr()->lte('end_time', ':endDateTo')); + $queryParameters['endDateTo'] = $endDateTo; + } + switch ($query->sort()) { case Query::SORT_BY_START_ASC: $qb->orderBy('start_time', 'asc'); diff --git a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php index 027ad8db..83fa1551 100644 --- a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php +++ b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php @@ -357,6 +357,48 @@ public function queries(): Generator ['import', '789'], ], ]; + yield 'Filter start time lower boundary' => [ + (new QueryBuilder()) + ->startTime(new \DateTimeImmutable('2021-09-20T10:35:48+0200'), null), + [ + ], + ]; + yield 'Filter start time upper boundary' => [ + (new QueryBuilder()) + ->startTime(null, new \DateTimeImmutable('2021-09-20T10:35:50+0200')), + [ + ], + ]; + yield 'Filter start time boundaries' => [ + (new QueryBuilder()) + ->startTime( + new \DateTimeImmutable('2021-09-20T10:35:48+0200'), + new \DateTimeImmutable('2021-09-20T10:35:50+0200'), + ), + [ + ], + ]; + yield 'Filter end time lower boundary' => [ + (new QueryBuilder()) + ->endTime(new \DateTimeImmutable('2021-09-20T10:35:48+0200'), null), + [ + ], + ]; + yield 'Filter end time upper boundary' => [ + (new QueryBuilder()) + ->endTime(null, new \DateTimeImmutable('2021-09-20T10:35:50+0200')), + [ + ], + ]; + yield 'Filter end time boundaries' => [ + (new QueryBuilder()) + ->endTime( + new \DateTimeImmutable('2021-09-20T10:35:48+0200'), + new \DateTimeImmutable('2021-09-20T10:35:50+0200'), + ), + [ + ], + ]; } public static function assertExecutionIds(array $ids, iterable $executions): void diff --git a/src/batch/src/Storage/FilesystemJobExecutionStorage.php b/src/batch/src/Storage/FilesystemJobExecutionStorage.php index 1a7646a7..51581b59 100644 --- a/src/batch/src/Storage/FilesystemJobExecutionStorage.php +++ b/src/batch/src/Storage/FilesystemJobExecutionStorage.php @@ -113,6 +113,26 @@ public function query(Query $query): iterable continue; } + $startTime = $execution->getStartTime(); + $startDateFrom = $query->startTime()?->getFrom(); + if ($startDateFrom !== null && ($startTime === null || $startTime < $startDateFrom)) { + continue; + } + $startDateTo = $query->startTime()?->getTo(); + if ($startDateTo !== null && ($startTime === null || $startTime > $startDateTo)) { + continue; + } + + $endTime = $execution->getEndTime(); + $endDateFrom = $query->endTime()?->getFrom(); + if ($endDateFrom !== null && ($endTime === null || $endTime < $endDateFrom)) { + continue; + } + $endDateTo = $query->endTime()?->getTo(); + if ($endDateTo !== null && ($endTime === null || $endTime > $endDateTo)) { + continue; + } + $candidates[] = $execution; } diff --git a/src/batch/src/Storage/Query.php b/src/batch/src/Storage/Query.php index 2ac17b0a..f022c3aa 100644 --- a/src/batch/src/Storage/Query.php +++ b/src/batch/src/Storage/Query.php @@ -33,9 +33,11 @@ public function __construct( * @var int[] */ private array $statuses, + private ?TimeFilter $startTime, + private ?TimeFilter $endTime, private ?string $sort, private int $limit, - private int $offset = 0, + private int $offset, ) { } @@ -63,6 +65,16 @@ public function statuses(): array return $this->statuses; } + public function startTime(): ?TimeFilter + { + return $this->startTime; + } + + public function endTime(): ?TimeFilter + { + return $this->endTime; + } + public function sort(): ?string { return $this->sort; diff --git a/src/batch/src/Storage/QueryBuilder.php b/src/batch/src/Storage/QueryBuilder.php index c2602b7a..35e70c75 100644 --- a/src/batch/src/Storage/QueryBuilder.php +++ b/src/batch/src/Storage/QueryBuilder.php @@ -4,6 +4,7 @@ namespace Yokai\Batch\Storage; +use DateTimeInterface; use Yokai\Batch\BatchStatus; use Yokai\Batch\Exception\UnexpectedValueException; @@ -16,6 +17,8 @@ * ->ids(['123', '456']) * ->jobs(['export', 'import']) * ->statuses([BatchStatus::RUNNING, BatchStatus::COMPLETED]) + * ->startTime(new \DateTimeImmutable('2023-07-07 15:18'), new \DateTime('2023-07-07 16:30')) + * ->endTime(new \DateTimeImmutable('2023-07-07 15:18'), new \DateTime('2023-07-07 16:30')) * ->sort(Query::SORT_BY_END_DESC) * ->limit(6, 12) * ->getQuery(); @@ -26,6 +29,8 @@ * $builder->ids(['123', '456']); * $builder->jobs(['export', 'import']); * $builder->statuses([BatchStatus::RUNNING, BatchStatus::COMPLETED]); + * $builder->startTime(new \DateTimeImmutable('2023-07-07 15:18'), new \DateTime('2023-07-07 16:30')); + * $builder->endTime(new \DateTimeImmutable('2023-07-07 15:18'), new \DateTime('2023-07-07 16:30')); * $builder->sort(Query::SORT_BY_END_DESC); * $builder->limit(6, 12); * $builder->getQuery(); @@ -63,6 +68,10 @@ final class QueryBuilder */ private array $statuses = []; + private ?TimeFilter $startTime = null; + + private ?TimeFilter $endTime = null; + private ?string $sortBy = null; private int $limit = 10; @@ -126,6 +135,44 @@ public function statuses(array $statuses): self return $this; } + /** + * Filter executions that started in a frame. + * Both frame boundaries are optional. + * Calling this method with both null boundaries result in removing the filter. + * + * @param DateTimeInterface|null $from Beginning of the time frame + * @param DateTimeInterface|null $to End of the time frame + */ + public function startTime(?DateTimeInterface $from, ?DateTimeInterface $to): self + { + if ($from === null && $to === null) { + $this->startTime = null; + } else { + $this->startTime = new TimeFilter($from, $to); + } + + return $this; + } + + /** + * Filter executions that ended in a frame. + * Both frame boundaries are optional. + * Calling this method with both null boundaries result in removing the filter. + * + * @param DateTimeInterface|null $from Beginning of the time frame + * @param DateTimeInterface|null $to End of the time frame + */ + public function endTime(?DateTimeInterface $from, ?DateTimeInterface $to): self + { + if ($from === null && $to === null) { + $this->endTime = null; + } else { + $this->endTime = new TimeFilter($from, $to); + } + + return $this; + } + /** * Sort executions. * @@ -165,6 +212,15 @@ public function limit(int $limit, int $offset): self */ public function getQuery(): Query { - return new Query($this->jobNames, $this->ids, $this->statuses, $this->sortBy, $this->limit, $this->offset); + return new Query( + $this->jobNames, + $this->ids, + $this->statuses, + $this->startTime, + $this->endTime, + $this->sortBy, + $this->limit, + $this->offset + ); } } diff --git a/src/batch/src/Storage/TimeFilter.php b/src/batch/src/Storage/TimeFilter.php new file mode 100644 index 00000000..98c63be4 --- /dev/null +++ b/src/batch/src/Storage/TimeFilter.php @@ -0,0 +1,29 @@ +from; + } + + public function getTo(): ?DateTimeInterface + { + return $this->to; + } +} diff --git a/src/batch/tests/Storage/FilesystemJobExecutionStorageTest.php b/src/batch/tests/Storage/FilesystemJobExecutionStorageTest.php index 3d34c8a2..bb945a9b 100644 --- a/src/batch/tests/Storage/FilesystemJobExecutionStorageTest.php +++ b/src/batch/tests/Storage/FilesystemJobExecutionStorageTest.php @@ -232,6 +232,62 @@ public function query(): \Generator ['list', '20210910'], ], ]; + yield 'Filter start time lower boundary' => [ + (new QueryBuilder()) + ->startTime(new \DateTimeImmutable('2021-09-20T10:35:48+0200'), null), + [ + ['export', '20210920'], + ['export', '20210922'], + ['list', '20210920'], + ], + ]; + yield 'Filter start time upper boundary' => [ + (new QueryBuilder()) + ->startTime(null, new \DateTimeImmutable('2021-09-20T10:35:50+0200')), + [ + ['export', '20210920'], + ['list', '20210910'], + ['list', '20210915'], + ], + ]; + yield 'Filter start time boundaries' => [ + (new QueryBuilder()) + ->startTime( + new \DateTimeImmutable('2021-09-20T10:35:48+0200'), + new \DateTimeImmutable('2021-09-20T10:35:50+0200'), + ), + [ + ['export', '20210920'], + ], + ]; + yield 'Filter end time lower boundary' => [ + (new QueryBuilder()) + ->endTime(new \DateTimeImmutable('2021-09-20T10:35:48+0200'), null), + [ + ['export', '20210920'], + ['export', '20210922'], + ['list', '20210920'], + ], + ]; + yield 'Filter end time upper boundary' => [ + (new QueryBuilder()) + ->endTime(null, new \DateTimeImmutable('2021-09-20T10:35:50+0200')), + [ + ['export', '20210920'], + ['list', '20210910'], + ['list', '20210915'], + ], + ]; + yield 'Filter end time boundaries' => [ + (new QueryBuilder()) + ->endTime( + new \DateTimeImmutable('2021-09-20T10:35:48+0200'), + new \DateTimeImmutable('2021-09-20T10:35:50+0200'), + ), + [ + ['export', '20210920'], + ], + ]; } public function testRetrieveFilePathNotFound(): void diff --git a/src/batch/tests/Storage/QueryBuilderTest.php b/src/batch/tests/Storage/QueryBuilderTest.php index 75af5bdd..fd1e8048 100644 --- a/src/batch/tests/Storage/QueryBuilderTest.php +++ b/src/batch/tests/Storage/QueryBuilderTest.php @@ -10,6 +10,7 @@ use Yokai\Batch\Exception\UnexpectedValueException; use Yokai\Batch\Storage\Query; use Yokai\Batch\Storage\QueryBuilder; +use Yokai\Batch\Storage\TimeFilter; class QueryBuilderTest extends TestCase { @@ -24,6 +25,10 @@ public function testValid(callable $factory, Query $expected): void self::assertSame($expected->jobs(), $actual->jobs()); self::assertSame($expected->ids(), $actual->ids()); self::assertSame($expected->statuses(), $actual->statuses()); + self::assertSame($expected->startTime()?->getFrom(), $actual->startTime()?->getFrom()); + self::assertSame($expected->startTime()?->getTo(), $actual->startTime()?->getTo()); + self::assertSame($expected->endTime()?->getFrom(), $actual->endTime()?->getFrom()); + self::assertSame($expected->endTime()?->getTo(), $actual->endTime()?->getTo()); self::assertSame($expected->sort(), $actual->sort()); self::assertSame($expected->limit(), $actual->limit()); self::assertSame($expected->offset(), $actual->offset()); @@ -35,41 +40,67 @@ public function valid(): \Generator $jobNames = []; $ids = []; $statuses = []; + $startTime = null; + $endTime = null; $sortBy = null; $limit = 10; $offset = 0; yield 'Query job names' => [ fn() => (new QueryBuilder())->jobs(['job1', 'job2']), - new Query(['job1', 'job2'], $ids, $statuses, $sortBy, $limit, $offset), + new Query(['job1', 'job2'], $ids, $statuses, $startTime, $endTime, $sortBy, $limit, $offset), ]; yield 'Query job ids' => [ fn() => (new QueryBuilder())->ids(['id1', 'id2', 'id3']), - new Query($jobNames, ['id1', 'id2', 'id3'], $statuses, $sortBy, $limit, $offset), + new Query($jobNames, ['id1', 'id2', 'id3'], $statuses, $startTime, $endTime, $sortBy, $limit, $offset), ]; yield 'Query job statuses' => [ fn() => (new QueryBuilder())->statuses([BatchStatus::ABANDONED, BatchStatus::STOPPED]), - new Query($jobNames, $ids, [BatchStatus::ABANDONED, BatchStatus::STOPPED], $sortBy, $limit, $offset), + new Query($jobNames, $ids, [BatchStatus::ABANDONED, BatchStatus::STOPPED], $startTime, $endTime, $sortBy, $limit, $offset), ]; yield 'Query with sort' => [ fn() => (new QueryBuilder())->sort(Query::SORT_BY_START_DESC), - new Query($jobNames, $ids, $statuses, Query::SORT_BY_START_DESC, $limit, $offset), + new Query($jobNames, $ids, $statuses, $startTime, $endTime, Query::SORT_BY_START_DESC, $limit, $offset), ]; yield 'Query with limit' => [ fn() => (new QueryBuilder())->limit(30, 60), - new Query($jobNames, $ids, $statuses, $sortBy, 30, 60), + new Query($jobNames, $ids, $statuses, $startTime, $endTime, $sortBy, 30, 60), + ]; + $startTimeFrom = new \DateTimeImmutable('2023-07-07 15:18'); + $startTimeTo = new \DateTime('2023-07-07 16:30'); + yield 'Query with start time boundary' => [ + fn() => (new QueryBuilder())->startTime($startTimeFrom, $startTimeTo), + new Query($jobNames, $ids, $statuses, new TimeFilter($startTimeFrom, $startTimeTo), null, $sortBy, $limit, $offset), + ]; + yield 'Query with start time boundary reset' => [ + fn() => (new QueryBuilder())->startTime($startTimeFrom, $startTimeTo)->startTime(null, null), + new Query($jobNames, $ids, $statuses, null, null, $sortBy, $limit, $offset), + ]; + $endTimeFrom = new \DateTimeImmutable('2023-07-07 15:18'); + $endTimeTo = new \DateTime('2023-07-07 16:30'); + yield 'Query with end time boundary' => [ + fn() => (new QueryBuilder())->endTime($endTimeFrom, $endTimeTo), + new Query($jobNames, $ids, $statuses, null, new TimeFilter($endTimeFrom, $endTimeTo), $sortBy, $limit, $offset), + ]; + yield 'Query with end time boundary reset' => [ + fn() => (new QueryBuilder())->endTime($endTimeFrom, $endTimeTo)->endTime(null, null), + new Query($jobNames, $ids, $statuses, null, null, $sortBy, $limit, $offset), ]; yield 'Query complex' => [ fn() => (new QueryBuilder()) ->ids(['123', '456']) ->jobs(['export', 'import']) ->statuses([BatchStatus::RUNNING, BatchStatus::COMPLETED]) + ->startTime($startTimeFrom, $startTimeTo) + ->endTime($endTimeFrom, $endTimeTo) ->sort(Query::SORT_BY_END_DESC) ->limit(6, 12), new Query( ['export', 'import'], ['123', '456'], [BatchStatus::RUNNING, BatchStatus::COMPLETED], + new TimeFilter($startTimeFrom, $startTimeTo), + new TimeFilter($endTimeFrom, $endTimeTo), Query::SORT_BY_END_DESC, 6, 12 From d0994861bd20d353bd37978ca0662d38cec5c611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Fri, 7 Jul 2023 17:18:29 +0200 Subject: [PATCH 02/12] Add missing typehint to date query filters --- .../src/DoctrineDBALJobExecutionStorage.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php b/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php index 1f046efa..83bb3adc 100644 --- a/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php +++ b/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php @@ -179,22 +179,26 @@ public function query(Query $query): iterable if ($startDateFrom) { $qb->andWhere($qb->expr()->gte('start_time', ':startDateFrom')); $queryParameters['startDateFrom'] = $startDateFrom; + $queryTypes['startDateFrom'] = Types::DATETIME_IMMUTABLE; } $startDateTo = $query->startTime()?->getTo(); if ($startDateTo) { $qb->andWhere($qb->expr()->lte('start_time', ':startDateTo')); $queryParameters['startDateTo'] = $startDateTo; + $queryTypes['startDateTo'] = Types::DATETIME_IMMUTABLE; } $endDateFrom = $query->endTime()?->getFrom(); if ($endDateFrom) { $qb->andWhere($qb->expr()->gte('end_time', ':endDateFrom')); $queryParameters['endDateFrom'] = $endDateFrom; + $queryTypes['endDateFrom'] = Types::DATETIME_IMMUTABLE; } $endDateTo = $query->endTime()?->getTo(); if ($endDateTo) { $qb->andWhere($qb->expr()->lte('end_time', ':endDateTo')); $queryParameters['endDateTo'] = $endDateTo; + $queryTypes['endDateTo'] = Types::DATETIME_IMMUTABLE; } switch ($query->sort()) { From 8c0161a1c5c90399ae06d73347bbe37e8fb54bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Fri, 7 Jul 2023 17:35:16 +0200 Subject: [PATCH 03/12] Add where clause for date fields not null --- .../src/DoctrineDBALJobExecutionStorage.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php b/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php index 83bb3adc..b5bceb8e 100644 --- a/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php +++ b/src/batch-doctrine-dbal/src/DoctrineDBALJobExecutionStorage.php @@ -175,6 +175,9 @@ public function query(Query $query): iterable $queryTypes['statuses'] = Connection::PARAM_INT_ARRAY; } + if ($query->startTime()) { + $qb->andWhere($qb->expr()->isNotNull('start_time')); + } $startDateFrom = $query->startTime()?->getFrom(); if ($startDateFrom) { $qb->andWhere($qb->expr()->gte('start_time', ':startDateFrom')); @@ -188,6 +191,9 @@ public function query(Query $query): iterable $queryTypes['startDateTo'] = Types::DATETIME_IMMUTABLE; } + if ($query->endTime()) { + $qb->andWhere($qb->expr()->isNotNull('start_time')); + } $endDateFrom = $query->endTime()?->getFrom(); if ($endDateFrom) { $qb->andWhere($qb->expr()->gte('end_time', ':endDateFrom')); From 9367a69c0cf86ad0040a5b05385d7bbb07e382f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Fri, 7 Jul 2023 17:35:32 +0200 Subject: [PATCH 04/12] Fixed query dates test sets --- .../DoctrineDBALJobExecutionStorageTest.php | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php index 83fa1551..b42b851f 100644 --- a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php +++ b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php @@ -359,42 +359,49 @@ public function queries(): Generator ]; yield 'Filter start time lower boundary' => [ (new QueryBuilder()) - ->startTime(new \DateTimeImmutable('2021-09-20T10:35:48+0200'), null), + ->startTime(new \DateTimeImmutable('2019-07-01T13:00:01+0200'), null), [ + 'import/456', + 'import/789', ], ]; yield 'Filter start time upper boundary' => [ (new QueryBuilder()) - ->startTime(null, new \DateTimeImmutable('2021-09-20T10:35:50+0200')), + ->startTime(null, new \DateTimeImmutable('2019-06-30T21:59:59+0200')), [ + 'export/123', + 'import/456', ], ]; yield 'Filter start time boundaries' => [ (new QueryBuilder()) ->startTime( - new \DateTimeImmutable('2021-09-20T10:35:48+0200'), - new \DateTimeImmutable('2021-09-20T10:35:50+0200'), + new \DateTimeImmutable('2019-07-01T13:00:01+0200'), + new \DateTimeImmutable('2019-06-30T21:59:59+0200'), ), [ + 'import/456', ], ]; yield 'Filter end time lower boundary' => [ (new QueryBuilder()) - ->endTime(new \DateTimeImmutable('2021-09-20T10:35:48+0200'), null), + ->endTime(new \DateTimeImmutable('2019-07-01T13:30:01+0200'), null), [ + 'import/456', ], ]; yield 'Filter end time upper boundary' => [ (new QueryBuilder()) - ->endTime(null, new \DateTimeImmutable('2021-09-20T10:35:50+0200')), + ->endTime(null, new \DateTimeImmutable('2019-07-01T18:29:59+0200')), [ + 'export/123', ], ]; yield 'Filter end time boundaries' => [ (new QueryBuilder()) ->endTime( - new \DateTimeImmutable('2021-09-20T10:35:48+0200'), - new \DateTimeImmutable('2021-09-20T10:35:50+0200'), + new \DateTimeImmutable('2019-07-01T13:30:01+0200'), + new \DateTimeImmutable('2019-07-01T18:29:59+0200'), ), [ ], From 68e7ce06210464357724b63b85b5354188d79748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Fri, 7 Jul 2023 17:43:03 +0200 Subject: [PATCH 05/12] Fixed tests ids notation --- .../tests/DoctrineDBALJobExecutionStorageTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php index b42b851f..8864260a 100644 --- a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php +++ b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php @@ -361,16 +361,16 @@ public function queries(): Generator (new QueryBuilder()) ->startTime(new \DateTimeImmutable('2019-07-01T13:00:01+0200'), null), [ - 'import/456', - 'import/789', + ['import', '456'], + ['import', '789'], ], ]; yield 'Filter start time upper boundary' => [ (new QueryBuilder()) ->startTime(null, new \DateTimeImmutable('2019-06-30T21:59:59+0200')), [ - 'export/123', - 'import/456', + ['export', '123'], + ['import', '456'], ], ]; yield 'Filter start time boundaries' => [ @@ -380,21 +380,21 @@ public function queries(): Generator new \DateTimeImmutable('2019-06-30T21:59:59+0200'), ), [ - 'import/456', + ['import', '456'], ], ]; yield 'Filter end time lower boundary' => [ (new QueryBuilder()) ->endTime(new \DateTimeImmutable('2019-07-01T13:30:01+0200'), null), [ - 'import/456', + ['import', '456'], ], ]; yield 'Filter end time upper boundary' => [ (new QueryBuilder()) ->endTime(null, new \DateTimeImmutable('2019-07-01T18:29:59+0200')), [ - 'export/123', + ['export', '123'], ], ]; yield 'Filter end time boundaries' => [ From 61e0a7b388ec39f5203fad7bd29da2173aac266d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Tue, 7 Jan 2025 11:19:16 +0100 Subject: [PATCH 06/12] Fixed checkstyle with named parameters --- src/batch/tests/Storage/QueryBuilderTest.php | 93 ++++++++++++++++---- 1 file changed, 78 insertions(+), 15 deletions(-) diff --git a/src/batch/tests/Storage/QueryBuilderTest.php b/src/batch/tests/Storage/QueryBuilderTest.php index fd1e8048..f9b0dbf8 100644 --- a/src/batch/tests/Storage/QueryBuilderTest.php +++ b/src/batch/tests/Storage/QueryBuilderTest.php @@ -56,35 +56,98 @@ public function valid(): \Generator ]; yield 'Query job statuses' => [ fn() => (new QueryBuilder())->statuses([BatchStatus::ABANDONED, BatchStatus::STOPPED]), - new Query($jobNames, $ids, [BatchStatus::ABANDONED, BatchStatus::STOPPED], $startTime, $endTime, $sortBy, $limit, $offset), + new Query( + jobs: $jobNames, + ids: $ids, + statuses: [BatchStatus::ABANDONED, BatchStatus::STOPPED], + startTime: $startTime, + endTime: $endTime, + sort: $sortBy, + limit: $limit, + offset: $offset + ), ]; yield 'Query with sort' => [ fn() => (new QueryBuilder())->sort(Query::SORT_BY_START_DESC), - new Query($jobNames, $ids, $statuses, $startTime, $endTime, Query::SORT_BY_START_DESC, $limit, $offset), + new Query( + jobs: $jobNames, + ids: $ids, + statuses: $statuses, + startTime: $startTime, + endTime: $endTime, + sort: Query::SORT_BY_START_DESC, + limit: $limit, + offset: $offset + ), ]; yield 'Query with limit' => [ fn() => (new QueryBuilder())->limit(30, 60), - new Query($jobNames, $ids, $statuses, $startTime, $endTime, $sortBy, 30, 60), + new Query( + jobs: $jobNames, + ids: $ids, + statuses: $statuses, + startTime: $startTime, + endTime: $endTime, + sort: $sortBy, + limit: 30, + offset: 60 + ), ]; $startTimeFrom = new \DateTimeImmutable('2023-07-07 15:18'); $startTimeTo = new \DateTime('2023-07-07 16:30'); yield 'Query with start time boundary' => [ fn() => (new QueryBuilder())->startTime($startTimeFrom, $startTimeTo), - new Query($jobNames, $ids, $statuses, new TimeFilter($startTimeFrom, $startTimeTo), null, $sortBy, $limit, $offset), + new Query( + jobs: $jobNames, + ids: $ids, + statuses: $statuses, + startTime: new TimeFilter($startTimeFrom, $startTimeTo), + endTime: null, + sort: $sortBy, + limit: $limit, + offset: $offset + ), ]; yield 'Query with start time boundary reset' => [ fn() => (new QueryBuilder())->startTime($startTimeFrom, $startTimeTo)->startTime(null, null), - new Query($jobNames, $ids, $statuses, null, null, $sortBy, $limit, $offset), + new Query( + jobs: $jobNames, + ids: $ids, + statuses: $statuses, + startTime: null, + endTime: null, + sort: $sortBy, + limit: $limit, + offset: $offset + ), ]; $endTimeFrom = new \DateTimeImmutable('2023-07-07 15:18'); $endTimeTo = new \DateTime('2023-07-07 16:30'); yield 'Query with end time boundary' => [ fn() => (new QueryBuilder())->endTime($endTimeFrom, $endTimeTo), - new Query($jobNames, $ids, $statuses, null, new TimeFilter($endTimeFrom, $endTimeTo), $sortBy, $limit, $offset), + new Query( + jobs: $jobNames, + ids: $ids, + statuses: $statuses, + startTime: null, + endTime: new TimeFilter($endTimeFrom, $endTimeTo), + sort: $sortBy, + limit: $limit, + offset: $offset + ), ]; yield 'Query with end time boundary reset' => [ fn() => (new QueryBuilder())->endTime($endTimeFrom, $endTimeTo)->endTime(null, null), - new Query($jobNames, $ids, $statuses, null, null, $sortBy, $limit, $offset), + new Query( + jobs: $jobNames, + ids: $ids, + statuses: $statuses, + startTime: null, + endTime: null, + sort: $sortBy, + limit: $limit, + offset: $offset + ), ]; yield 'Query complex' => [ fn() => (new QueryBuilder()) @@ -96,14 +159,14 @@ public function valid(): \Generator ->sort(Query::SORT_BY_END_DESC) ->limit(6, 12), new Query( - ['export', 'import'], - ['123', '456'], - [BatchStatus::RUNNING, BatchStatus::COMPLETED], - new TimeFilter($startTimeFrom, $startTimeTo), - new TimeFilter($endTimeFrom, $endTimeTo), - Query::SORT_BY_END_DESC, - 6, - 12 + jobs: ['export', 'import'], + ids: ['123', '456'], + statuses: [BatchStatus::RUNNING, BatchStatus::COMPLETED], + startTime: new TimeFilter($startTimeFrom, $startTimeTo), + endTime: new TimeFilter($endTimeFrom, $endTimeTo), + sort: Query::SORT_BY_END_DESC, + limit: 6, + offset: 12 ), ]; } From 0f39426cbdf1088dd82349574b15c1b39805e3cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Tue, 7 Jan 2025 11:19:35 +0100 Subject: [PATCH 07/12] Fixed Doctrine DBAL storage tests with start time boundaries --- .../tests/DoctrineDBALJobExecutionStorageTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php index 8864260a..ce2e96ac 100644 --- a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php +++ b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php @@ -362,14 +362,12 @@ public function queries(): Generator ->startTime(new \DateTimeImmutable('2019-07-01T13:00:01+0200'), null), [ ['import', '456'], - ['import', '789'], ], ]; yield 'Filter start time upper boundary' => [ (new QueryBuilder()) - ->startTime(null, new \DateTimeImmutable('2019-06-30T21:59:59+0200')), + ->startTime(null, new \DateTimeImmutable('2019-06-30T22:00:00+0200')), [ - ['export', '123'], ['import', '456'], ], ]; @@ -377,7 +375,7 @@ public function queries(): Generator (new QueryBuilder()) ->startTime( new \DateTimeImmutable('2019-07-01T13:00:01+0200'), - new \DateTimeImmutable('2019-06-30T21:59:59+0200'), + new \DateTimeImmutable('2019-06-30T22:00:00+0200'), ), [ ['import', '456'], From 2b84ad9d014478697b5b51b181b2bbf583f01887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Tue, 7 Jan 2025 11:35:06 +0100 Subject: [PATCH 08/12] Ensure TimeFilter boundaries are correct --- src/batch/src/Storage/TimeFilter.php | 4 ++++ src/batch/tests/Storage/QueryBuilderTest.php | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/src/batch/src/Storage/TimeFilter.php b/src/batch/src/Storage/TimeFilter.php index 98c63be4..ca617ea0 100644 --- a/src/batch/src/Storage/TimeFilter.php +++ b/src/batch/src/Storage/TimeFilter.php @@ -5,6 +5,7 @@ namespace Yokai\Batch\Storage; use DateTimeInterface; +use Yokai\Batch\Exception\UnexpectedValueException; /** * DTO with optional time boundaries. @@ -15,6 +16,9 @@ public function __construct( private ?DateTimeInterface $from, private ?DateTimeInterface $to, ) { + if ($from !== null && $to !== null && $from > $to) { + throw new UnexpectedValueException('TimeFilter expect "from" boundary to be lower than "to" boundary.'); + } } public function getFrom(): ?DateTimeInterface diff --git a/src/batch/tests/Storage/QueryBuilderTest.php b/src/batch/tests/Storage/QueryBuilderTest.php index f9b0dbf8..40f34dbd 100644 --- a/src/batch/tests/Storage/QueryBuilderTest.php +++ b/src/batch/tests/Storage/QueryBuilderTest.php @@ -224,5 +224,13 @@ public function invalid(): \Generator fn() => (new QueryBuilder())->limit(1, -1), UnexpectedValueException::min(0, -1), ]; + yield 'QueryBuilder::startTime with inversed boundaries' => [ + fn() => (new QueryBuilder())->startTime(new \DateTimeImmutable('2024-01-01T00:00:00+0200'), new \DateTimeImmutable('2023-12-31T23:59:59+0200')), + new UnexpectedValueException('TimeFilter expect "from" boundary to be lower than "to" boundary.'), + ]; + yield 'QueryBuilder::endTime with inversed boundaries' => [ + fn() => (new QueryBuilder())->endTime(new \DateTimeImmutable('2024-01-01T00:00:00+0200'), new \DateTimeImmutable('2023-12-31T23:59:59+0200')), + new UnexpectedValueException('TimeFilter expect "from" boundary to be lower than "to" boundary.'), + ]; } } From e3a195733dd4f1d4edddfcb76e8e4b4942f2defc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Tue, 7 Jan 2025 11:35:29 +0100 Subject: [PATCH 09/12] Fixed Doctrine DBAL storage tests --- .../tests/DoctrineDBALJobExecutionStorageTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php index ce2e96ac..0f0cee95 100644 --- a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php +++ b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php @@ -368,17 +368,17 @@ public function queries(): Generator (new QueryBuilder()) ->startTime(null, new \DateTimeImmutable('2019-06-30T22:00:00+0200')), [ - ['import', '456'], + ['import', '789'], ], ]; yield 'Filter start time boundaries' => [ (new QueryBuilder()) ->startTime( new \DateTimeImmutable('2019-07-01T13:00:01+0200'), - new \DateTimeImmutable('2019-06-30T22:00:00+0200'), + new \DateTimeImmutable('2019-07-01T17:29:29+0200'), ), [ - ['import', '456'], + ['export', '123'], ], ]; yield 'Filter end time lower boundary' => [ From f0db255e63a4e8e783b44a6af7318523f406d027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Tue, 7 Jan 2025 11:36:55 +0100 Subject: [PATCH 10/12] Fixed checkstyle --- src/batch/tests/Storage/QueryBuilderTest.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/batch/tests/Storage/QueryBuilderTest.php b/src/batch/tests/Storage/QueryBuilderTest.php index 40f34dbd..daefe288 100644 --- a/src/batch/tests/Storage/QueryBuilderTest.php +++ b/src/batch/tests/Storage/QueryBuilderTest.php @@ -225,11 +225,17 @@ public function invalid(): \Generator UnexpectedValueException::min(0, -1), ]; yield 'QueryBuilder::startTime with inversed boundaries' => [ - fn() => (new QueryBuilder())->startTime(new \DateTimeImmutable('2024-01-01T00:00:00+0200'), new \DateTimeImmutable('2023-12-31T23:59:59+0200')), + fn() => (new QueryBuilder())->startTime( + new \DateTimeImmutable('2024-01-01T00:00:00+0200'), + new \DateTimeImmutable('2023-12-31T23:59:59+0200'), + ), new UnexpectedValueException('TimeFilter expect "from" boundary to be lower than "to" boundary.'), ]; yield 'QueryBuilder::endTime with inversed boundaries' => [ - fn() => (new QueryBuilder())->endTime(new \DateTimeImmutable('2024-01-01T00:00:00+0200'), new \DateTimeImmutable('2023-12-31T23:59:59+0200')), + fn() => (new QueryBuilder())->endTime( + new \DateTimeImmutable('2024-01-01T00:00:00+0200'), + new \DateTimeImmutable('2023-12-31T23:59:59+0200'), + ), new UnexpectedValueException('TimeFilter expect "from" boundary to be lower than "to" boundary.'), ]; } From 2340cb6bf9ec14d3f90376c50d0c0c09f529eadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Tue, 7 Jan 2025 11:37:52 +0100 Subject: [PATCH 11/12] Fixed Doctrine DBAL storage tests --- .../tests/DoctrineDBALJobExecutionStorageTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php index 0f0cee95..7ba5daca 100644 --- a/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php +++ b/src/batch-doctrine-dbal/tests/DoctrineDBALJobExecutionStorageTest.php @@ -378,7 +378,7 @@ public function queries(): Generator new \DateTimeImmutable('2019-07-01T17:29:29+0200'), ), [ - ['export', '123'], + // none ], ]; yield 'Filter end time lower boundary' => [ From 1840e6f9460b57d10d177a85f77c4f7c7441de48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20Eugon=C3=A9?= Date: Tue, 7 Jan 2025 11:51:16 +0100 Subject: [PATCH 12/12] Fix codecov upload --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 65c55562..238c386c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -88,9 +88,9 @@ jobs: symfony-version: '7.0.*' coverage-mode: 'xdebug' - name: "Run tests with phpunit/phpunit" - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} run: | vendor/bin/phpunit --testsuite=Code --coverage-clover coverage.xml - name: "Upload coverage to Codecov" - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v5 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}