create(); $generated = File::factory()->create([ 'user_id' => $user->id, 'original_name' => 'Монтаж тест.zip', 'mime_type' => 'application/zip', 'path' => 'orders/10/Монтаж тест.zip', 'link' => url('/storage/orders/10/Монтаж тест.zip'), 'is_generated' => true, 'created_at' => now()->subDays(15), 'updated_at' => now()->subDays(15), ]); $uploaded = File::factory()->create([ 'user_id' => $user->id, 'original_name' => 'manual.zip', 'mime_type' => 'application/zip', 'path' => 'orders/10/document/manual.zip', 'link' => url('/storage/orders/10/document/manual.zip'), 'is_generated' => false, 'created_at' => now()->subDays(30), 'updated_at' => now()->subDays(30), ]); $freshGenerated = File::factory()->create([ 'user_id' => $user->id, 'original_name' => 'Сдача свежий.zip', 'mime_type' => 'application/zip', 'path' => 'orders/11/Сдача свежий.zip', 'link' => url('/storage/orders/11/Сдача свежий.zip'), 'is_generated' => true, 'created_at' => now()->subDays(2), 'updated_at' => now()->subDays(2), ]); Storage::disk('public')->put($generated->path, 'generated'); Storage::disk('public')->put($uploaded->path, 'uploaded'); Storage::disk('public')->put($freshGenerated->path, 'fresh'); $exitCode = Artisan::call('documents:cleanup-generated', ['--days' => 14]); $this->assertSame(0, $exitCode); $this->assertDatabaseMissing('files', ['id' => $generated->id]); $this->assertDatabaseHas('files', ['id' => $uploaded->id]); $this->assertDatabaseHas('files', ['id' => $freshGenerated->id]); Storage::disk('public')->assertMissing($generated->path); Storage::disk('public')->assertExists($uploaded->path); Storage::disk('public')->assertExists($freshGenerated->path); } public function test_cleanup_generated_documents_removes_legacy_tmp_archive_path(): void { Storage::fake('public'); $user = User::factory()->create(); $file = File::factory()->create([ 'user_id' => $user->id, 'original_name' => 'Рекламация тест.zip', 'mime_type' => 'application/zip', 'path' => 'reclamations/20/tmp/Рекламация тест.zip', 'link' => url('/storage/reclamations/20/Рекламация тест.zip'), 'is_generated' => true, 'created_at' => now()->subDays(15), 'updated_at' => now()->subDays(15), ]); Storage::disk('public')->put('reclamations/20/Рекламация тест.zip', 'legacy archive'); $exitCode = Artisan::call('documents:cleanup-generated', ['--days' => 14]); $this->assertSame(0, $exitCode); $this->assertDatabaseMissing('files', ['id' => $file->id]); Storage::disk('public')->assertMissing('reclamations/20/Рекламация тест.zip'); } public function test_cleanup_generated_documents_removes_old_orphan_generated_archive(): void { Storage::fake('public'); Storage::fake('upload'); Storage::disk('public')->put('orders/15/Монтаж сирота.zip', 'orphan archive'); touch(Storage::disk('public')->path('orders/15/Монтаж сирота.zip'), now()->subDays(20)->timestamp); Storage::disk('public')->put('orders/15/document/manual.zip', 'manual archive'); touch(Storage::disk('public')->path('orders/15/document/manual.zip'), now()->subDays(20)->timestamp); $exitCode = Artisan::call('documents:cleanup-generated', ['--days' => 14]); $this->assertSame(0, $exitCode); Storage::disk('public')->assertMissing('orders/15/Монтаж сирота.zip'); Storage::disk('public')->assertExists('orders/15/document/manual.zip'); } public function test_cleanup_generated_documents_removes_old_import_files_and_orphans(): void { Storage::fake('public'); Storage::fake('upload'); $oldImport = Import::factory()->create([ 'filename' => 'ab/old-import.xlsx', 'created_at' => now()->subDays(20), 'updated_at' => now()->subDays(20), ]); $freshImport = Import::factory()->create([ 'filename' => 'cd/fresh-import.xlsx', 'created_at' => now()->subDays(2), 'updated_at' => now()->subDays(2), ]); Storage::disk('upload')->put($oldImport->filename, 'old import'); Storage::disk('upload')->put($freshImport->filename, 'fresh import'); Storage::disk('upload')->put('ef/orphan-import.xlsx', 'orphan import'); touch(Storage::disk('upload')->path('ef/orphan-import.xlsx'), now()->subDays(20)->timestamp); $exitCode = Artisan::call('documents:cleanup-generated', [ '--days' => 14, '--import-days' => 14, ]); $this->assertSame(0, $exitCode); Storage::disk('upload')->assertMissing($oldImport->filename); Storage::disk('upload')->assertExists($freshImport->filename); Storage::disk('upload')->assertMissing('ef/orphan-import.xlsx'); } public function test_cleanup_generated_documents_removes_only_old_system_temp_zip_files(): void { Storage::fake('public'); Storage::fake('upload'); $tempDir = storage_path('framework/testing/tmp-cleanup'); if (!is_dir($tempDir)) { mkdir($tempDir, 0777, true); } $oldZip = $tempDir . '/old-zip'; $freshZip = $tempDir . '/fresh-zip'; $oldText = $tempDir . '/old-text'; file_put_contents($oldZip, "PK\x03\x04old"); file_put_contents($freshZip, "PK\x03\x04fresh"); file_put_contents($oldText, 'not zip'); touch($oldZip, now()->subHours(2)->timestamp); touch($oldText, now()->subHours(2)->timestamp); config(['documents.temp_directory' => $tempDir]); try { $exitCode = Artisan::call('documents:cleanup-generated', [ '--days' => 14, '--temp-hours' => 1, ]); $this->assertSame(0, $exitCode); $this->assertFileDoesNotExist($oldZip); $this->assertFileExists($freshZip); $this->assertFileExists($oldText); } finally { @unlink($oldZip); @unlink($freshZip); @unlink($oldText); @rmdir($tempDir); } } }