183 lines
6.7 KiB
PHP
183 lines
6.7 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Services;
|
|
|
|
use App\Enums\MediaDiskEnum;
|
|
use App\Models\Medium;
|
|
use App\Services\FileStorageService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
use Tests\TestCase;
|
|
|
|
class FileStorageServiceTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected FileStorageService $service;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
Storage::fake('public');
|
|
Storage::fake('private');
|
|
$this->service = app(FileStorageService::class);
|
|
}
|
|
|
|
protected function storedMedium(string $disk = 'private', string $content = 'hello'): Medium
|
|
{
|
|
$medium = Medium::factory()->create(['disk' => $disk, 'path' => 'files/sample.txt', 'filename' => 'sample.txt', 'mime_type' => 'text/plain']);
|
|
Storage::disk($disk)->put($medium->path, $content);
|
|
|
|
return $medium;
|
|
}
|
|
|
|
public function test_store_file_saves_public_file_and_medium_with_url(): void
|
|
{
|
|
$file = UploadedFile::fake()->create('My Scan.pdf', 12, 'application/pdf');
|
|
|
|
$medium = $this->service->storeFile($file);
|
|
|
|
$this->assertSame(MediaDiskEnum::Public, $medium->disk);
|
|
$this->assertMatchesRegularExpression('/^\d+_[A-Za-z0-9]{6}_my-scan\.pdf$/', $medium->filename);
|
|
$this->assertSame('files/' . $medium->filename, $medium->path);
|
|
$this->assertSame(Storage::disk('public')->url($medium->path), $medium->url);
|
|
$this->assertSame(12 * 1024, $medium->size);
|
|
$this->assertSame('application/pdf', $medium->mime_type);
|
|
Storage::disk('public')->assertExists($medium->path);
|
|
}
|
|
|
|
public function test_store_file_saves_private_file_without_url_in_custom_directory(): void
|
|
{
|
|
$medium = $this->service->storeFile(UploadedFile::fake()->image('x.png'), 'private', 'reports');
|
|
|
|
$this->assertSame(MediaDiskEnum::Private, $medium->disk);
|
|
$this->assertNull($medium->url);
|
|
$this->assertStringStartsWith('reports/', $medium->path);
|
|
Storage::disk('private')->assertExists($medium->path);
|
|
Storage::disk('public')->assertMissing($medium->path);
|
|
}
|
|
|
|
public function test_store_file_generates_distinct_filenames_for_same_upload_name(): void
|
|
{
|
|
$first = $this->service->storeFile(UploadedFile::fake()->image('same.png'));
|
|
$second = $this->service->storeFile(UploadedFile::fake()->image('same.png'));
|
|
|
|
$this->assertNotSame($first->filename, $second->filename);
|
|
}
|
|
|
|
public function test_move_to_disk_moves_file_from_private_to_public_and_sets_url(): void
|
|
{
|
|
$medium = $this->storedMedium('private');
|
|
|
|
$this->assertTrue($this->service->moveToDisk($medium, 'public'));
|
|
|
|
$medium->refresh();
|
|
$this->assertSame(MediaDiskEnum::Public, $medium->disk);
|
|
$this->assertSame(Storage::disk('public')->url('files/sample.txt'), $medium->url);
|
|
Storage::disk('public')->assertExists('files/sample.txt');
|
|
Storage::disk('private')->assertMissing('files/sample.txt');
|
|
$this->assertSame('hello', Storage::disk('public')->get('files/sample.txt'));
|
|
}
|
|
|
|
public function test_move_to_disk_moves_file_to_private_and_clears_url(): void
|
|
{
|
|
$medium = $this->storedMedium('public');
|
|
$medium->update(['url' => 'http://example.test/files/sample.txt']);
|
|
|
|
$this->assertTrue($this->service->moveToDisk($medium, 'private'));
|
|
|
|
$medium->refresh();
|
|
$this->assertSame(MediaDiskEnum::Private, $medium->disk);
|
|
$this->assertNull($medium->url);
|
|
Storage::disk('private')->assertExists('files/sample.txt');
|
|
Storage::disk('public')->assertMissing('files/sample.txt');
|
|
}
|
|
|
|
public function test_move_to_disk_returns_true_without_changes_for_same_disk(): void
|
|
{
|
|
$medium = $this->storedMedium('private');
|
|
|
|
$this->assertTrue($this->service->moveToDisk($medium, 'private'));
|
|
Storage::disk('private')->assertExists('files/sample.txt');
|
|
}
|
|
|
|
public function test_move_to_disk_returns_false_when_source_file_is_missing(): void
|
|
{
|
|
$medium = Medium::factory()->private()->create(['path' => 'files/missing.txt']);
|
|
|
|
$this->assertFalse($this->service->moveToDisk($medium, 'public'));
|
|
$this->assertSame(MediaDiskEnum::Private, $medium->fresh()->disk);
|
|
}
|
|
|
|
public function test_delete_medium_removes_file_and_record(): void
|
|
{
|
|
$medium = $this->storedMedium('private');
|
|
|
|
$this->service->deleteMedium($medium);
|
|
|
|
Storage::disk('private')->assertMissing('files/sample.txt');
|
|
$this->assertDatabaseMissing('media', ['id' => $medium->id]);
|
|
}
|
|
|
|
public function test_delete_medium_removes_record_even_when_file_is_missing(): void
|
|
{
|
|
$medium = Medium::factory()->private()->create(['path' => 'files/missing.txt']);
|
|
|
|
$this->service->deleteMedium($medium);
|
|
|
|
$this->assertDatabaseMissing('media', ['id' => $medium->id]);
|
|
}
|
|
|
|
public function test_download_file_returns_attachment_for_private_existing_file(): void
|
|
{
|
|
$medium = $this->storedMedium('private');
|
|
|
|
$response = $this->service->downloadFile($medium);
|
|
|
|
$this->assertStringContainsString('attachment', $response->headers->get('Content-Disposition'));
|
|
$this->assertStringContainsString('sample.txt', $response->headers->get('Content-Disposition'));
|
|
}
|
|
|
|
public function test_download_file_aborts_for_public_medium(): void
|
|
{
|
|
$medium = $this->storedMedium('public');
|
|
|
|
$this->expectException(NotFoundHttpException::class);
|
|
|
|
$this->service->downloadFile($medium);
|
|
}
|
|
|
|
public function test_download_file_aborts_when_file_is_missing(): void
|
|
{
|
|
$medium = Medium::factory()->private()->create(['path' => 'files/missing.txt']);
|
|
|
|
$this->expectException(NotFoundHttpException::class);
|
|
|
|
$this->service->downloadFile($medium);
|
|
}
|
|
|
|
public function test_serve_file_returns_inline_content_with_mime_type(): void
|
|
{
|
|
$medium = $this->storedMedium('private', 'inline body');
|
|
|
|
$response = $this->service->serveFile($medium);
|
|
|
|
$this->assertSame(200, $response->getStatusCode());
|
|
$this->assertSame('inline body', $response->getContent());
|
|
$this->assertSame('text/plain', $response->headers->get('Content-Type'));
|
|
$this->assertSame('inline; filename="sample.txt"', $response->headers->get('Content-Disposition'));
|
|
}
|
|
|
|
public function test_serve_file_aborts_for_public_medium(): void
|
|
{
|
|
$medium = $this->storedMedium('public');
|
|
|
|
$this->expectException(NotFoundHttpException::class);
|
|
|
|
$this->service->serveFile($medium);
|
|
}
|
|
}
|