lthn.io/app/Core/Tests/Feature/OffloadMigrateCommandTest.php

288 lines
8.6 KiB
PHP
Raw Permalink Normal View History

<?php
declare(strict_types=1);
/*
* Core PHP Framework
*
* Licensed under the European Union Public Licence (EUPL) v1.2.
* See LICENSE file for details.
*/
namespace Core\Tests\Feature;
use Core\Cdn\Models\StorageOffload as StorageOffloadModel;
use Core\Cdn\Services\StorageOffload as StorageOffloadService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class OffloadMigrateCommandTest extends TestCase
{
use RefreshDatabase;
protected string $testDirectory;
protected function setUp(): void
{
parent::setUp();
// Enable offload for testing
Config::set('offload.enabled', true);
Config::set('offload.disk', 'testing');
Config::set('offload.keep_local', false);
Config::set('filesystems.disks.testing', [
'driver' => 'local',
'root' => storage_path('framework/testing/offload'),
'url' => env('APP_URL').'/testing',
'visibility' => 'public',
]);
// Rebind the service so it picks up the new config
$this->app->forgetInstance(StorageOffloadService::class);
$this->app->bind(StorageOffloadService::class, function () {
return new StorageOffloadService;
});
// Create test directory with files
$this->testDirectory = storage_path('framework/testing/migrate-test');
@mkdir($this->testDirectory, 0755, true);
// Create test files
file_put_contents($this->testDirectory.'/image1.jpg', 'image content 1');
file_put_contents($this->testDirectory.'/image2.png', 'image content 2');
file_put_contents($this->testDirectory.'/document.pdf', 'pdf content');
}
protected function tearDown(): void
{
// Clean up test directory recursively
if (is_dir($this->testDirectory)) {
$this->deleteDirectory($this->testDirectory);
}
// Clean up testing disk
Storage::disk('testing')->deleteDirectory('');
parent::tearDown();
}
/**
* Recursively delete a directory.
*/
protected function deleteDirectory(string $dir): void
{
if (! is_dir($dir)) {
return;
}
$items = glob($dir.'/*');
foreach ($items as $item) {
if (is_dir($item)) {
$this->deleteDirectory($item);
} else {
@unlink($item);
}
}
@rmdir($dir);
}
public function test_command_fails_when_offload_disabled(): void
{
Config::set('offload.enabled', false);
$this->artisan('offload:migrate', ['path' => $this->testDirectory])
->expectsOutput('Storage offload is not enabled in configuration.')
->assertExitCode(1);
}
public function test_command_fails_for_non_existent_directory(): void
{
$this->artisan('offload:migrate', ['path' => '/nonexistent/path'])
->assertExitCode(1);
}
public function test_command_can_migrate_files_with_dry_run(): void
{
$this->artisan('offload:migrate', [
'path' => $this->testDirectory,
'--dry-run' => true,
'--force' => true,
])
->expectsOutput('DRY RUN MODE - No files will be offloaded')
->assertExitCode(0);
// Files should still exist locally
$this->assertFileExists($this->testDirectory.'/image1.jpg');
$this->assertFileExists($this->testDirectory.'/image2.png');
// No database records should be created
$this->assertEquals(0, StorageOffloadModel::count());
}
public function test_command_can_migrate_files(): void
{
$this->artisan('offload:migrate', [
'path' => $this->testDirectory,
'--force' => true,
])
->assertExitCode(0);
// Files should be offloaded
$this->assertEquals(3, StorageOffloadModel::count());
// Files should exist on remote storage
$records = StorageOffloadModel::all();
foreach ($records as $record) {
$this->assertTrue(Storage::disk('testing')->exists($record->remote_path));
}
}
public function test_command_respects_category_option(): void
{
$this->artisan('offload:migrate', [
'path' => $this->testDirectory,
'--category' => 'page',
'--force' => true,
])
->assertExitCode(0);
$records = StorageOffloadModel::all();
foreach ($records as $record) {
$this->assertEquals('page', $record->category);
}
}
public function test_command_respects_allowed_extensions(): void
{
Config::set('offload.allowed_extensions', ['jpg', 'png']);
$this->artisan('offload:migrate', [
'path' => $this->testDirectory,
'--force' => true,
])
->assertExitCode(0);
// Only jpg and png files should be offloaded (not pdf)
$this->assertEquals(2, StorageOffloadModel::count());
}
public function test_command_respects_max_file_size(): void
{
// Create large file
$largeFile = $this->testDirectory.'/large.jpg';
file_put_contents($largeFile, str_repeat('x', 10000));
Config::set('offload.max_file_size', 100); // 100 bytes
$this->artisan('offload:migrate', [
'path' => $this->testDirectory,
'--force' => true,
])
->assertExitCode(0);
// Large file should not be offloaded
$largeFileRecord = StorageOffloadModel::where('local_path', $largeFile)->first();
$this->assertNull($largeFileRecord);
}
public function test_command_skips_already_offloaded_files(): void
{
// Offload one file first
$service = app(StorageOffloadService::class);
$service->upload($this->testDirectory.'/image1.jpg', null, 'media');
$this->artisan('offload:migrate', [
'path' => $this->testDirectory,
'--force' => true,
])
->assertExitCode(0);
// Should still be 3 total (not 4 with duplicate)
$this->assertEquals(3, StorageOffloadModel::count());
}
public function test_command_with_only_missing_flag(): void
{
// Offload one file first
$service = app(StorageOffloadService::class);
$service->upload($this->testDirectory.'/image1.jpg', null, 'media');
$this->artisan('offload:migrate', [
'path' => $this->testDirectory,
'--only-missing' => true,
'--force' => true,
])
->assertExitCode(0);
// Should offload the 2 missing files
$this->assertEquals(3, StorageOffloadModel::count());
}
public function test_command_displays_summary_table(): void
{
$this->artisan('offload:migrate', [
'path' => $this->testDirectory,
'--force' => true,
])
->expectsTable(
['Status', 'Count'],
[
['Processed', 3],
['Failed', 0],
['Skipped', 0],
['Total', 3],
]
)
->assertExitCode(0);
}
public function test_command_defaults_to_storage_app_public(): void
{
// Create a file in default location
$defaultPath = storage_path('app/public/test.jpg');
@mkdir(dirname($defaultPath), 0755, true);
file_put_contents($defaultPath, 'test content');
$this->artisan('offload:migrate', ['--force' => true])
->assertExitCode(0);
// Clean up
@unlink($defaultPath);
}
public function test_command_handles_empty_directory(): void
{
$emptyDir = storage_path('framework/testing/empty-dir');
@mkdir($emptyDir, 0755, true);
$this->artisan('offload:migrate', [
'path' => $emptyDir,
'--force' => true,
])
->expectsOutput('No eligible files found.')
->assertExitCode(0);
@rmdir($emptyDir);
}
public function test_command_scans_subdirectories(): void
{
$subDir = $this->testDirectory.'/subdir';
@mkdir($subDir, 0755, true);
file_put_contents($subDir.'/nested.jpg', 'nested content');
$this->artisan('offload:migrate', [
'path' => $this->testDirectory,
'--force' => true,
])
->assertExitCode(0);
// Should find 4 files (3 in root + 1 in subdir)
$this->assertEquals(4, StorageOffloadModel::count());
}
}