Files
coruna-lab/tests/Feature/PhotoOriginTest.php
T
2026-09-14 01:09:01 +08:00

121 lines
3.8 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Admin;
use App\Models\Device;
use App\Models\Photo;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
class PhotoOriginTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
Storage::fake('local');
}
/**
* @return array{0: Device, 1: Photo, 2: string}
*/
private function seedMissingPhoto(): array
{
$device = Device::query()->create(['device_id' => 'dev-origin-1']);
$png = $this->tinyPng();
$path = 'c2/photos/'.$device->device_id.'/shot.png';
$photo = Photo::query()->create([
'device_id' => $device->id,
'sha256' => hash('sha256', $png),
'path' => $path,
'size' => strlen($png),
]);
return [$device, $photo, $png];
}
private function tinyPng(): string
{
$tmp = sys_get_temp_dir().'/album_'.uniqid().'.png';
$im = imagecreatetruecolor(4, 4);
imagefilledrectangle($im, 0, 0, 3, 3, imagecolorallocate($im, 9, 8, 7));
imagepng($im, $tmp);
$png = (string) file_get_contents($tmp);
@unlink($tmp);
return $png;
}
#[Test]
public function origin_endpoint_requires_token(): void
{
config(['coruna.photo_origin.token' => 'secret-origin']);
[, $photo, $png] = $this->seedMissingPhoto();
Storage::disk('local')->put($photo->path, $png);
$this->get(route('hooks.photo-origin', $photo))->assertUnauthorized();
$this->get(route('hooks.photo-origin', $photo).'?token=wrong')->assertUnauthorized();
$this->get(route('hooks.photo-origin', $photo).'?token=secret-origin')
->assertOk()
->assertHeader('X-Photo-Origin', 'local');
}
#[Test]
public function origin_endpoint_404s_when_file_missing_locally(): void
{
config(['coruna.photo_origin.token' => 'secret-origin']);
[, $photo] = $this->seedMissingPhoto();
$this->withHeaders(['X-Photo-Origin-Token' => 'secret-origin'])
->get(route('hooks.photo-origin', $photo))
->assertNotFound();
}
#[Test]
public function viewing_missing_photo_pulls_from_origin_and_writes_through(): void
{
config([
'coruna.photo_origin.url' => 'http://old.example',
'coruna.photo_origin.token' => 'secret-origin',
]);
[$device, $photo, $png] = $this->seedMissingPhoto();
$admin = Admin::query()->create(['username' => 'root', 'password' => 'secret12', 'is_super' => 1]);
Http::fake([
'http://old.example/hooks/photo-origin/'.$photo->id => Http::response($png, 200, [
'Content-Type' => 'image/png',
]),
]);
$this->actingAs($admin, 'admin')
->get(route('admin.devices.photo', [$device, $photo->id]))
->assertOk()
->assertHeader('Content-Type', 'image/png');
Storage::disk('local')->assertExists($photo->path);
$this->assertSame($png, Storage::disk('local')->get($photo->path));
}
#[Test]
public function viewing_missing_photo_without_origin_stays_404(): void
{
config([
'coruna.photo_origin.url' => '',
'coruna.photo_origin.token' => '',
]);
[$device, $photo] = $this->seedMissingPhoto();
$admin = Admin::query()->create(['username' => 'root', 'password' => 'secret12', 'is_super' => 1]);
$this->actingAs($admin, 'admin')
->get(route('admin.devices.photo', [$device, $photo->id]))
->assertNotFound();
Storage::disk('local')->assertMissing($photo->path);
}
}