CleanupGeneratedDocumentsCommandTest.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. namespace Tests\Feature;
  3. use App\Models\File;
  4. use App\Models\Import;
  5. use App\Models\User;
  6. use Illuminate\Foundation\Testing\RefreshDatabase;
  7. use Illuminate\Support\Facades\Artisan;
  8. use Illuminate\Support\Facades\Storage;
  9. use Tests\TestCase;
  10. class CleanupGeneratedDocumentsCommandTest extends TestCase
  11. {
  12. use RefreshDatabase;
  13. public function test_cleanup_generated_documents_removes_only_old_generated_files(): void
  14. {
  15. Storage::fake('public');
  16. $user = User::factory()->create();
  17. $generated = File::factory()->create([
  18. 'user_id' => $user->id,
  19. 'original_name' => 'Монтаж тест.zip',
  20. 'mime_type' => 'application/zip',
  21. 'path' => 'orders/10/Монтаж тест.zip',
  22. 'link' => url('/storage/orders/10/Монтаж тест.zip'),
  23. 'is_generated' => true,
  24. 'created_at' => now()->subDays(15),
  25. 'updated_at' => now()->subDays(15),
  26. ]);
  27. $uploaded = File::factory()->create([
  28. 'user_id' => $user->id,
  29. 'original_name' => 'manual.zip',
  30. 'mime_type' => 'application/zip',
  31. 'path' => 'orders/10/document/manual.zip',
  32. 'link' => url('/storage/orders/10/document/manual.zip'),
  33. 'is_generated' => false,
  34. 'created_at' => now()->subDays(30),
  35. 'updated_at' => now()->subDays(30),
  36. ]);
  37. $freshGenerated = File::factory()->create([
  38. 'user_id' => $user->id,
  39. 'original_name' => 'Сдача свежий.zip',
  40. 'mime_type' => 'application/zip',
  41. 'path' => 'orders/11/Сдача свежий.zip',
  42. 'link' => url('/storage/orders/11/Сдача свежий.zip'),
  43. 'is_generated' => true,
  44. 'created_at' => now()->subDays(2),
  45. 'updated_at' => now()->subDays(2),
  46. ]);
  47. Storage::disk('public')->put($generated->path, 'generated');
  48. Storage::disk('public')->put($uploaded->path, 'uploaded');
  49. Storage::disk('public')->put($freshGenerated->path, 'fresh');
  50. $exitCode = Artisan::call('documents:cleanup-generated', ['--days' => 14]);
  51. $this->assertSame(0, $exitCode);
  52. $this->assertDatabaseMissing('files', ['id' => $generated->id]);
  53. $this->assertDatabaseHas('files', ['id' => $uploaded->id]);
  54. $this->assertDatabaseHas('files', ['id' => $freshGenerated->id]);
  55. Storage::disk('public')->assertMissing($generated->path);
  56. Storage::disk('public')->assertExists($uploaded->path);
  57. Storage::disk('public')->assertExists($freshGenerated->path);
  58. }
  59. public function test_cleanup_generated_documents_removes_legacy_tmp_archive_path(): void
  60. {
  61. Storage::fake('public');
  62. $user = User::factory()->create();
  63. $file = File::factory()->create([
  64. 'user_id' => $user->id,
  65. 'original_name' => 'Рекламация тест.zip',
  66. 'mime_type' => 'application/zip',
  67. 'path' => 'reclamations/20/tmp/Рекламация тест.zip',
  68. 'link' => url('/storage/reclamations/20/Рекламация тест.zip'),
  69. 'is_generated' => true,
  70. 'created_at' => now()->subDays(15),
  71. 'updated_at' => now()->subDays(15),
  72. ]);
  73. Storage::disk('public')->put('reclamations/20/Рекламация тест.zip', 'legacy archive');
  74. $exitCode = Artisan::call('documents:cleanup-generated', ['--days' => 14]);
  75. $this->assertSame(0, $exitCode);
  76. $this->assertDatabaseMissing('files', ['id' => $file->id]);
  77. Storage::disk('public')->assertMissing('reclamations/20/Рекламация тест.zip');
  78. }
  79. public function test_cleanup_generated_documents_removes_old_orphan_generated_archive(): void
  80. {
  81. Storage::fake('public');
  82. Storage::fake('upload');
  83. Storage::disk('public')->put('orders/15/Монтаж сирота.zip', 'orphan archive');
  84. touch(Storage::disk('public')->path('orders/15/Монтаж сирота.zip'), now()->subDays(20)->timestamp);
  85. Storage::disk('public')->put('orders/15/document/manual.zip', 'manual archive');
  86. touch(Storage::disk('public')->path('orders/15/document/manual.zip'), now()->subDays(20)->timestamp);
  87. $exitCode = Artisan::call('documents:cleanup-generated', ['--days' => 14]);
  88. $this->assertSame(0, $exitCode);
  89. Storage::disk('public')->assertMissing('orders/15/Монтаж сирота.zip');
  90. Storage::disk('public')->assertExists('orders/15/document/manual.zip');
  91. }
  92. public function test_cleanup_generated_documents_removes_old_import_files_and_orphans(): void
  93. {
  94. Storage::fake('public');
  95. Storage::fake('upload');
  96. $oldImport = Import::factory()->create([
  97. 'filename' => 'ab/old-import.xlsx',
  98. 'created_at' => now()->subDays(20),
  99. 'updated_at' => now()->subDays(20),
  100. ]);
  101. $freshImport = Import::factory()->create([
  102. 'filename' => 'cd/fresh-import.xlsx',
  103. 'created_at' => now()->subDays(2),
  104. 'updated_at' => now()->subDays(2),
  105. ]);
  106. Storage::disk('upload')->put($oldImport->filename, 'old import');
  107. Storage::disk('upload')->put($freshImport->filename, 'fresh import');
  108. Storage::disk('upload')->put('ef/orphan-import.xlsx', 'orphan import');
  109. touch(Storage::disk('upload')->path('ef/orphan-import.xlsx'), now()->subDays(20)->timestamp);
  110. $exitCode = Artisan::call('documents:cleanup-generated', [
  111. '--days' => 14,
  112. '--import-days' => 14,
  113. ]);
  114. $this->assertSame(0, $exitCode);
  115. Storage::disk('upload')->assertMissing($oldImport->filename);
  116. Storage::disk('upload')->assertExists($freshImport->filename);
  117. Storage::disk('upload')->assertMissing('ef/orphan-import.xlsx');
  118. }
  119. public function test_cleanup_generated_documents_removes_only_old_system_temp_zip_files(): void
  120. {
  121. Storage::fake('public');
  122. Storage::fake('upload');
  123. $tempDir = storage_path('framework/testing/tmp-cleanup');
  124. if (!is_dir($tempDir)) {
  125. mkdir($tempDir, 0777, true);
  126. }
  127. $oldZip = $tempDir . '/old-zip';
  128. $freshZip = $tempDir . '/fresh-zip';
  129. $oldText = $tempDir . '/old-text';
  130. file_put_contents($oldZip, "PK\x03\x04old");
  131. file_put_contents($freshZip, "PK\x03\x04fresh");
  132. file_put_contents($oldText, 'not zip');
  133. touch($oldZip, now()->subHours(2)->timestamp);
  134. touch($oldText, now()->subHours(2)->timestamp);
  135. config(['documents.temp_directory' => $tempDir]);
  136. try {
  137. $exitCode = Artisan::call('documents:cleanup-generated', [
  138. '--days' => 14,
  139. '--temp-hours' => 1,
  140. ]);
  141. $this->assertSame(0, $exitCode);
  142. $this->assertFileDoesNotExist($oldZip);
  143. $this->assertFileExists($freshZip);
  144. $this->assertFileExists($oldText);
  145. } finally {
  146. @unlink($oldZip);
  147. @unlink($freshZip);
  148. @unlink($oldText);
  149. @rmdir($tempDir);
  150. }
  151. }
  152. }