Files
ephub/tests/Command/PruneBookingEventsCommandTest.php
T
AdminandClaude Opus 5.5 dcdce4d248 feat: add a booking event history for admins
Admins get /admin/history: one line per booking created, rescheduled or
released, per series created or ended, and per resource deleted with its
bookings. Sortable by time, kind, resource, booked day and both people;
filterable by period, kinds, who acted and resource type.

Events are snapshots written inside the same transaction as the change,
so a rolled-back booking leaves none and a released booking stays
readable. app:booking-events:prune keeps twelve months and needs a cron
entry on the server.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-16 16:02:07 +02:00

84 lines
2.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Command;
use App\Entity\BookingEvent;
use App\Enum\BookingEventType;
use App\Enum\ResourceType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Tester\CommandTester;
/**
* The retention period of the event history, enforced from cron.
*/
class PruneBookingEventsCommandTest extends KernelTestCase
{
private EntityManagerInterface $em;
private CommandTester $command;
protected function setUp(): void
{
self::bootKernel();
$this->em = self::getContainer()->get(EntityManagerInterface::class);
$this->em->getConnection()->beginTransaction();
$this->command = new CommandTester((new Application(self::$kernel))->find('app:booking-events:prune'));
}
protected function tearDown(): void
{
$this->em->getConnection()->rollBack();
parent::tearDown();
}
public function testEventsOlderThanAYearAreDeleted(): void
{
$old = $this->event('-13 months');
$recent = $this->event('-11 months');
$this->command->execute([]);
$this->command->assertCommandIsSuccessful();
self::assertStringContainsString('Deleted 1 booking events', $this->command->getDisplay());
self::assertNull($this->em->find(BookingEvent::class, $old));
self::assertNotNull($this->em->find(BookingEvent::class, $recent));
}
public function testTheRetentionCanBeShortened(): void
{
$event = $this->event('-2 months');
$this->command->execute(['--months' => '1']);
$this->command->assertCommandIsSuccessful();
self::assertNull($this->em->find(BookingEvent::class, $event));
}
public function testANonsensicalRetentionIsRefused(): void
{
$event = $this->event('-2 months');
self::assertSame(Command::INVALID, $this->command->execute(['--months' => '0']));
self::assertNotNull($this->em->find(BookingEvent::class, $event));
}
private function event(string $when): int
{
$event = new BookingEvent(BookingEventType::BOOKING_CREATED, null, 'System', null, 'Tisch 1', ResourceType::DESK);
$this->em->persist($event);
$this->em->flush();
$this->em->getConnection()->executeStatement(
'UPDATE booking_event SET occurred_at = ? WHERE id = ?',
[(new \DateTimeImmutable($when))->format('Y-m-d H:i:s'), $event->getId()],
);
$this->em->clear();
return (int) $event->getId();
}
}