mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-10-16 02:09:44 +00:00
215 lines
7.7 KiB
PHP
215 lines
7.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* Chill is a software for social workers
|
|
*
|
|
* For the full copyright and license information, please view
|
|
* the LICENSE file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Chill\MainBundle\Tests\Notification\Email;
|
|
|
|
use Chill\MainBundle\Notification\Email\DailyNotificationDigestCronjob;
|
|
use Chill\MainBundle\Notification\Email\NotificationEmailMessages\ScheduleDailyNotificationDigestMessage;
|
|
use Doctrine\DBAL\Connection;
|
|
use Doctrine\DBAL\Result;
|
|
use Doctrine\DBAL\Statement;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\Clock\ClockInterface;
|
|
use Symfony\Component\Clock\MockClock;
|
|
use Symfony\Component\Messenger\Envelope;
|
|
use Symfony\Component\Messenger\MessageBusInterface;
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* @covers \DailyNotificationDigestCronjob
|
|
*/
|
|
class DailyNotificationDigestCronJobTest extends TestCase
|
|
{
|
|
private ClockInterface $clock;
|
|
private Connection $connection;
|
|
private MessageBusInterface $messageBus;
|
|
private LoggerInterface $logger;
|
|
private DailyNotificationDigestCronjob $cronjob;
|
|
private \DateTimeImmutable $firstNow;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->clock = $this->createMock(ClockInterface::class);
|
|
$this->connection = $this->createMock(Connection::class);
|
|
$this->messageBus = $this->createMock(MessageBusInterface::class);
|
|
$this->logger = $this->createMock(LoggerInterface::class);
|
|
|
|
$this->firstNow = new \DateTimeImmutable('2024-01-02T07:15:00+00:00');
|
|
|
|
$this->cronjob = new DailyNotificationDigestCronjob(
|
|
$this->clock,
|
|
$this->connection,
|
|
$this->messageBus,
|
|
$this->logger
|
|
);
|
|
}
|
|
|
|
public function testGetKey(): void
|
|
{
|
|
$this->assertEquals('daily-notification-digest', $this->cronjob->getKey());
|
|
}
|
|
|
|
/**
|
|
* @dataProvider canRunTimeDataProvider
|
|
*/
|
|
public function testCanRunWithNullCronJobExecution(int $hour, bool $expected): void
|
|
{
|
|
$now = new \DateTimeImmutable("2024-01-01 {$hour}:00:00");
|
|
$this->clock->expects($this->once())
|
|
->method('now')
|
|
->willReturn($now);
|
|
|
|
$result = $this->cronjob->canRun(null);
|
|
|
|
$this->assertEquals($expected, $result);
|
|
}
|
|
|
|
public static function canRunTimeDataProvider(): array
|
|
{
|
|
return [
|
|
'hour 5 - should not run' => [5, false],
|
|
'hour 6 - should run' => [6, true],
|
|
'hour 7 - should run' => [7, true],
|
|
'hour 8 - should run' => [8, true],
|
|
'hour 9 - should not run' => [9, false],
|
|
'hour 10 - should not run' => [10, false],
|
|
'hour 23 - should not run' => [23, false],
|
|
];
|
|
}
|
|
|
|
public function testRunFirstExecutionReturnsStateAndDispatches(): array
|
|
{
|
|
// Use MockClock for deterministic time
|
|
$firstNow = $this->firstNow;
|
|
$clock = new MockClock($firstNow);
|
|
|
|
// Mock DBAL statement/result
|
|
$statement = $this->createMock(Statement::class);
|
|
$result = $this->createMock(Result::class);
|
|
|
|
$this->connection->method('prepare')->willReturn($statement);
|
|
$statement->method('bindValue')->willReturnSelf();
|
|
$statement->method('executeQuery')->willReturn($result);
|
|
|
|
$rows = [
|
|
['user_id' => 10],
|
|
['user_id' => 42],
|
|
];
|
|
$result->method('fetchAllAssociative')->willReturn($rows);
|
|
|
|
$dispatched = [];
|
|
$this->messageBus->method('dispatch')->willReturnCallback(function ($message) use (&$dispatched) {
|
|
$dispatched[] = $message;
|
|
|
|
return new Envelope($message);
|
|
});
|
|
|
|
$cron = new DailyNotificationDigestCronjob($clock, $this->connection, $this->messageBus, $this->logger);
|
|
$state = $cron->run([]);
|
|
|
|
// Assert dispatch count and message contents
|
|
self::assertCount(2, $dispatched);
|
|
$expectedLast = $firstNow->sub(new \DateInterval('P1D'));
|
|
foreach ($dispatched as $i => $msg) {
|
|
self::assertInstanceOf(ScheduleDailyNotificationDigestMessage::class, $msg);
|
|
self::assertTrue(in_array($msg->getUserId(), [10, 42], true));
|
|
self::assertEquals($firstNow, $msg->getCurrentDateTime(), 'compare the current date');
|
|
self::assertEquals($expectedLast, $msg->getLastExecutionDateTime(), 'compare the last execution date');
|
|
}
|
|
|
|
// Assert returned state
|
|
self::assertIsArray($state);
|
|
self::assertArrayHasKey('last_execution', $state);
|
|
self::assertSame($firstNow->format(\DateTimeInterface::ATOM), $state['last_execution']);
|
|
|
|
return $state;
|
|
}
|
|
|
|
/**
|
|
* @depends testRunFirstExecutionReturnsStateAndDispatches
|
|
*/
|
|
public function testRunSecondExecutionUsesPreviousState(array $previousState): void
|
|
{
|
|
$firstNow = $this->firstNow;
|
|
$secondNow = $firstNow->add(new \DateInterval('P1D'));
|
|
$clock = new MockClock($secondNow);
|
|
|
|
// Mock DBAL for a single user this time
|
|
$statement = $this->createMock(Statement::class);
|
|
$result = $this->createMock(Result::class);
|
|
|
|
$this->connection->method('prepare')->willReturn($statement);
|
|
$statement->method('bindValue')->willReturnSelf();
|
|
$statement->method('executeQuery')->willReturn($result);
|
|
|
|
$rows = [
|
|
['user_id' => 7],
|
|
];
|
|
$result->method('fetchAllAssociative')->willReturn($rows);
|
|
|
|
$captured = [];
|
|
$this->messageBus->method('dispatch')->willReturnCallback(function ($message) use (&$captured) {
|
|
$captured[] = $message;
|
|
|
|
return new Envelope($message);
|
|
});
|
|
|
|
$cron = new DailyNotificationDigestCronjob($clock, $this->connection, $this->messageBus, $this->logger);
|
|
$cron->run($previousState);
|
|
|
|
self::assertCount(1, $captured);
|
|
$msg = $captured[0];
|
|
self::assertInstanceOf(ScheduleDailyNotificationDigestMessage::class, $msg);
|
|
self::assertEquals(7, $msg->getUserId());
|
|
self::assertEquals($secondNow, $msg->getCurrentDateTime(), 'compare the current date');
|
|
self::assertEquals($firstNow, $msg->getLastExecutionDateTime(), 'compare the last execution date');
|
|
}
|
|
|
|
public function testRunWithInvalidExecutionState(): void
|
|
{
|
|
$firstNow = new \DateTimeImmutable('2025-10-14T10:30:00 Europe/Brussels');
|
|
$previousExpected = $firstNow->sub(new \DateInterval('P1D'));
|
|
$clock = new MockClock($firstNow);
|
|
|
|
// Mock DBAL for a single user this time
|
|
$statement = $this->createMock(Statement::class);
|
|
$result = $this->createMock(Result::class);
|
|
|
|
$this->connection->method('prepare')->willReturn($statement);
|
|
$statement->method('bindValue')->willReturnSelf();
|
|
$statement->method('executeQuery')->willReturn($result);
|
|
|
|
$rows = [
|
|
['user_id' => 7],
|
|
];
|
|
$result->method('fetchAllAssociative')->willReturn($rows);
|
|
|
|
$captured = [];
|
|
$this->messageBus->method('dispatch')->willReturnCallback(function ($message) use (&$captured) {
|
|
$captured[] = $message;
|
|
|
|
return new Envelope($message);
|
|
});
|
|
|
|
$cron = new DailyNotificationDigestCronjob($clock, $this->connection, $this->messageBus, $this->logger);
|
|
$cron->run(['last_execution' => 'invalid data']);
|
|
|
|
self::assertCount(1, $captured);
|
|
$msg = $captured[0];
|
|
self::assertInstanceOf(ScheduleDailyNotificationDigestMessage::class, $msg);
|
|
self::assertEquals(7, $msg->getUserId());
|
|
self::assertEquals($firstNow, $msg->getCurrentDateTime(), 'compare the current date');
|
|
self::assertEquals($previousExpected, $msg->getLastExecutionDateTime(), 'compare the last execution date');
|
|
}
|
|
}
|