Files
pictureFrame-webApp/tests/Integration/MessageHandler/RenderImageMessageHandlerTest.php
T
football2801 12245759ac
CI / test (push) Has been cancelled
chore: stage all in-progress work before repo split
Web app: new entities (Image, RenderedAsset, SharedImage, Token,
DeviceImageHistory), enums, repositories, controllers, message handlers,
migrations, tests, frontend upload/library/sticker UI, Vue components.

Firmware: EPD background screen binaries + gen scripts, setup_bg header.

Infra: ddev config, test bundle, gitignore coverage dir.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 12:11:31 -04:00

159 lines
5.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Integration\MessageHandler;
use App\Entity\Image;
use App\Enum\RenderStatus;
use App\Message\RenderImageMessage;
use App\MessageHandler\RenderImageMessageHandler;
use App\Repository\RenderedAssetRepository;
use App\Tests\AppKernelTestCase;
class RenderImageMessageHandlerTest extends AppKernelTestCase
{
private string $projectDir;
private string $fixtureJpeg;
private array $createdDirs = [];
protected function setUp(): void
{
parent::setUp();
$this->projectDir = static::getContainer()->getParameter('kernel.project_dir');
$this->createdDirs = [];
$storageDir = $this->projectDir . '/var/storage/images';
if (!is_dir($storageDir)) {
mkdir($storageDir, 0755, true);
}
$this->fixtureJpeg = $this->projectDir . '/var/storage/images/_render_fixture.jpg';
$imagick = new \Imagick();
$imagick->newImage(20, 20, new \ImagickPixel('white'));
$imagick->setImageFormat('jpeg');
$imagick->writeImage($this->fixtureJpeg);
$imagick->destroy();
}
protected function tearDown(): void
{
foreach ($this->createdDirs as $dir) {
if (is_dir($dir)) {
$this->deleteDir($dir);
}
}
if (file_exists($this->fixtureJpeg)) {
unlink($this->fixtureJpeg);
}
parent::tearDown();
}
private function deleteDir(string $dir): void
{
foreach (new \FilesystemIterator($dir) as $item) {
$item->isDir() ? $this->deleteDir($item->getPathname()) : unlink($item->getPathname());
}
rmdir($dir);
}
private function invokeHandler(int $imageId, string $model = 'v1', string $orientation = 'landscape'): void
{
$handler = static::getContainer()->get(RenderImageMessageHandler::class);
$handler(new RenderImageMessage($imageId, $model, $orientation));
}
// MH-01: happy path — bin written, RenderedAsset status = Ready
public function test_mh01_renders_image_to_bin_and_marks_ready(): void
{
$user = $this->createUser('mh01@example.com');
$image = (new Image())->setUser($user)
->setOriginalFilename('test.jpg')
->setStoragePath('var/storage/images/_render_fixture.jpg');
$this->em()->persist($image);
$this->em()->flush();
$imageId = $image->getId();
$imageDir = $this->projectDir . '/var/storage/images/' . $imageId;
mkdir($imageDir, 0755, true);
$this->createdDirs[] = $imageDir;
$this->invokeHandler($imageId);
/** @var RenderedAssetRepository $assetRepo */
$assetRepo = $this->em()->getRepository(\App\Entity\RenderedAsset::class);
$asset = $assetRepo->findOneBy(['image' => $image]);
$this->assertNotNull($asset);
$this->assertSame(RenderStatus::Ready, $asset->getStatus());
$this->assertFileExists($this->projectDir . '/' . $asset->getFilePath());
}
// MH-01b: composited.jpg is preferred over the raw original when present
public function test_mh01b_composited_jpg_preferred_over_original(): void
{
$user = $this->createUser('mh01b@example.com');
$image = (new Image())->setUser($user)
->setOriginalFilename('test.jpg')
->setStoragePath('var/storage/images/_render_fixture.jpg');
$this->em()->persist($image);
$this->em()->flush();
$imageId = $image->getId();
$imageDir = $this->projectDir . '/var/storage/images/' . $imageId;
mkdir($imageDir, 0755, true);
$this->createdDirs[] = $imageDir;
copy($this->fixtureJpeg, $imageDir . '/composited.jpg');
$this->invokeHandler($imageId);
$assetRepo = $this->em()->getRepository(\App\Entity\RenderedAsset::class);
$asset = $assetRepo->findOneBy(['image' => $image]);
$this->assertNotNull($asset);
$this->assertSame(RenderStatus::Ready, $asset->getStatus());
}
// MH-02: non-existent imageId → handler returns early, no RenderedAsset created
public function test_mh02_nonexistent_image_returns_early(): void
{
$this->invokeHandler(999999999);
$assetRepo = $this->em()->getRepository(\App\Entity\RenderedAsset::class);
$assets = $assetRepo->findAll();
$this->assertCount(0, $assets);
}
// MH-03: corrupt/non-image file → RenderedAsset status = Failed
public function test_mh03_imagick_failure_marks_asset_as_failed(): void
{
$badFile = $this->projectDir . '/var/storage/images/_render_bad.txt';
file_put_contents($badFile, 'not-an-image');
$user = $this->createUser('mh03@example.com');
$image = (new Image())->setUser($user)
->setOriginalFilename('bad.jpg')
->setStoragePath('var/storage/images/_render_bad.txt');
$this->em()->persist($image);
$this->em()->flush();
$imageId = $image->getId();
$imageDir = $this->projectDir . '/var/storage/images/' . $imageId;
mkdir($imageDir, 0755, true);
$this->createdDirs[] = $imageDir;
$this->invokeHandler($imageId);
$assetRepo = $this->em()->getRepository(\App\Entity\RenderedAsset::class);
$asset = $assetRepo->findOneBy(['image' => $image]);
$this->assertNotNull($asset);
$this->assertSame(RenderStatus::Failed, $asset->getStatus());
if (file_exists($badFile)) {
unlink($badFile);
}
}
}