95 lines
4.6 KiB
PHP
95 lines
4.6 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use Illuminate\Support\Facades\Artisan;
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Tests\TestCase;
|
|
|
|
#[\PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses]
|
|
#[\PHPUnit\Framework\Attributes\PreserveGlobalState(false)]
|
|
class IllustrationDeliveryTest extends TestCase
|
|
{
|
|
private string $dir;
|
|
|
|
private string $id = '11111111-1111-4111-8111-111111111111';
|
|
|
|
private string $asset = '22222222-2222-4222-8222-222222222222';
|
|
|
|
private string $sha;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->app['env'] = 'production';
|
|
$this->dir = sys_get_temp_dir().'/delivery-fna-'.bin2hex(random_bytes(8));
|
|
mkdir($this->dir, 0700, true);
|
|
mkdir($this->dir.'/public');
|
|
file_put_contents($this->dir.'/credential.json', json_encode(['project' => 'fna-v3', 'base_url' => 'https://resource-v2.gemcook.net', 'token' => 'rsv2_'.str_repeat('a', 64)]));
|
|
config(['illustrations.enabled' => true, 'illustrations.local_enabled' => true, 'illustrations.delivery_enabled' => true, 'illustrations.base_url' => 'https://resource-v2.gemcook.net', 'illustrations.credential_file' => $this->dir.'/credential.json', 'illustrations.local_directory' => $this->dir.'/public', 'illustrations.local_manifest' => $this->dir.'/manifest.json']);
|
|
$this->sha = hash('sha256', 'verified-copy');
|
|
file_put_contents($this->dir.'/public/'.$this->sha.'.webp', 'verified-copy');
|
|
file_put_contents($this->dir.'/manifest.json', json_encode(['version' => 1, 'assets' => [$this->asset => ['sha256' => $this->sha, 'mime' => 'image/webp', 'bytes' => strlen('verified-copy'), 'url' => '/images/illustrations/'.$this->sha.'.webp']], 'selections' => ['freenode' => ['old-article' => 'old-asset']]]));
|
|
Http::preventStrayRequests();
|
|
Artisan::all();
|
|
\Illuminate\Support\Facades\Schema::create('articles', function ($t) {
|
|
$t->id();
|
|
$t->integer('iCategoryId');
|
|
$t->integer('iStatus');
|
|
$t->string('sSlug');
|
|
$t->timestamp('created_at')->nullable();
|
|
});
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
File::deleteDirectory($this->dir);
|
|
parent::tearDown();
|
|
}
|
|
|
|
private function fake(int $sync = 0, int $ack = 200): void
|
|
{
|
|
|
|
Http::fake([
|
|
'https://resource-v2.gemcook.net/api/v2/pools/*' => Http::response(['data' => ['items' => [['asset_id' => $this->asset, 'url' => 'https://resource-v2.gemcook.net/media/'.$this->id]], 'selections' => [], 'unavailable' => [], 'next' => null]], $sync ? 503 : 200),
|
|
'https://resource-v2.gemcook.net/api/v2/illustration-deliveries' => Http::response(['data' => [['id' => $this->id, 'state' => 'awaiting_sync', 'fingerprint' => str_repeat('b', 64), 'assets' => [['asset_id' => $this->asset, 'sha256' => $this->sha, 'pool' => 'freenode']]]]]),
|
|
'https://resource-v2.gemcook.net/api/v2/illustration-deliveries/*/ack' => Http::response(['data' => ['state' => 'completed']], $ack),
|
|
]);
|
|
}
|
|
|
|
public function test_verified_copy_is_acknowledged_and_lost_ack_can_retry(): void
|
|
{
|
|
$this->fake(0, 503);
|
|
$this->artisan('illustrations:sync-deliveries')->assertExitCode(1);
|
|
Http::swap(new \Illuminate\Http\Client\Factory);
|
|
Http::preventStrayRequests();
|
|
$this->fake();
|
|
$this->artisan('illustrations:sync-deliveries')->assertExitCode(0);
|
|
$this->assertSame('old-asset', json_decode(file_get_contents($this->dir.'/manifest.json'), true)['selections']['freenode']['old-article']);
|
|
Http::assertSent(fn ($r) => str_ends_with($r->url(), '/ack') && $r['fingerprint'] === str_repeat('b', 64) && $r['manifest_sha256'] === hash_file('sha256', $this->dir.'/manifest.json'));
|
|
}
|
|
|
|
public function test_failed_sync_sends_no_ack(): void
|
|
{
|
|
$this->fake(1);
|
|
$this->artisan('illustrations:sync-deliveries')->assertExitCode(1);
|
|
Http::assertNotSent(fn ($r) => str_ends_with($r->url(), '/ack'));
|
|
}
|
|
|
|
public function test_corrupt_copy_sends_no_ack(): void
|
|
{
|
|
$this->fake();
|
|
file_put_contents($this->dir.'/public/'.$this->sha.'.webp', 'corrupt');
|
|
$this->artisan('illustrations:sync-deliveries')->assertExitCode(1);
|
|
Http::assertNotSent(fn ($r) => str_ends_with($r->url(), '/ack'));
|
|
}
|
|
|
|
public function test_disabled_worker_does_not_contact_resource(): void
|
|
{
|
|
config(['illustrations.delivery_enabled' => false]);
|
|
$this->artisan('illustrations:sync-deliveries')->assertExitCode(1);
|
|
Http::assertNothingSent();
|
|
}
|
|
}
|