121 lines
3.8 KiB
PHP
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);
|
|
}
|
|
}
|