QueuedImportTest.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. namespace Maatwebsite\Excel\Tests;
  3. use Illuminate\Foundation\Bus\PendingDispatch;
  4. use Illuminate\Queue\Events\JobExceptionOccurred;
  5. use Illuminate\Queue\Events\JobProcessed;
  6. use Illuminate\Queue\Events\JobProcessing;
  7. use Illuminate\Support\Facades\Bus;
  8. use Illuminate\Support\Facades\Queue;
  9. use Maatwebsite\Excel\Concerns\Importable;
  10. use Maatwebsite\Excel\Files\RemoteTemporaryFile;
  11. use Maatwebsite\Excel\Files\TemporaryFile;
  12. use Maatwebsite\Excel\Jobs\AfterImportJob;
  13. use Maatwebsite\Excel\Jobs\ReadChunk;
  14. use Maatwebsite\Excel\SettingsProvider;
  15. use Maatwebsite\Excel\Tests\Data\Stubs\AfterQueueImportJob;
  16. use Maatwebsite\Excel\Tests\Data\Stubs\QueuedImport;
  17. use Maatwebsite\Excel\Tests\Data\Stubs\QueuedImportWithFailure;
  18. use Maatwebsite\Excel\Tests\Data\Stubs\QueuedImportWithMiddleware;
  19. use Maatwebsite\Excel\Tests\Data\Stubs\QueuedImportWithRetryUntil;
  20. use Throwable;
  21. class QueuedImportTest extends TestCase
  22. {
  23. /**
  24. * Setup the test environment.
  25. */
  26. protected function setUp(): void
  27. {
  28. parent::setUp();
  29. $this->loadLaravelMigrations(['--database' => 'testing']);
  30. $this->loadMigrationsFrom(__DIR__ . '/Data/Stubs/Database/Migrations');
  31. }
  32. /**
  33. * @test
  34. */
  35. public function cannot_queue_import_that_does_not_implement_should_queue()
  36. {
  37. $this->expectException(\InvalidArgumentException::class);
  38. $this->expectExceptionMessage('Importable should implement ShouldQueue to be queued.');
  39. $import = new class
  40. {
  41. use Importable;
  42. };
  43. $import->queue('import-batches.xlsx');
  44. }
  45. /**
  46. * @test
  47. */
  48. public function can_queue_an_import()
  49. {
  50. $import = new QueuedImport();
  51. $chain = $import->queue('import-batches.xlsx')->chain([
  52. new AfterQueueImportJob(5000),
  53. ]);
  54. $this->assertInstanceOf(PendingDispatch::class, $chain);
  55. }
  56. /**
  57. * @test
  58. */
  59. public function can_queue_an_import_with_batch_cache_and_file_store()
  60. {
  61. config()->set('queue.default', 'sync');
  62. config()->set('excel.cache.driver', 'batch');
  63. config()->set('excel.cache.illuminate.store', 'file');
  64. // Reset the cache settings
  65. $this->app->make(SettingsProvider::class)->provide();
  66. $import = new QueuedImport();
  67. $chain = $import->queue('import-batches.xlsx');
  68. $this->assertInstanceOf(PendingDispatch::class, $chain);
  69. }
  70. /**
  71. * @test
  72. */
  73. public function can_queue_import_with_remote_temp_disk()
  74. {
  75. config()->set('excel.temporary_files.remote_disk', 'test');
  76. // Delete the local temp file before each read chunk job
  77. // to simulate using a shared remote disk, without
  78. // having a dependency on a local temp file.
  79. Queue::before(function (JobProcessing $event) {
  80. if ($event->job->resolveName() === ReadChunk::class) {
  81. /** @var TemporaryFile $tempFile */
  82. $tempFile = $this->inspectJobProperty($event->job, 'temporaryFile');
  83. $this->assertInstanceOf(RemoteTemporaryFile::class, $tempFile);
  84. // Should exist remote
  85. $this->assertTrue(
  86. $tempFile->exists()
  87. );
  88. $this->assertTrue(
  89. unlink($tempFile->getLocalPath())
  90. );
  91. }
  92. });
  93. $import = new QueuedImport();
  94. $chain = $import->queue('import-batches.xlsx')->chain([
  95. new AfterQueueImportJob(5000),
  96. ]);
  97. $this->assertInstanceOf(PendingDispatch::class, $chain);
  98. }
  99. /**
  100. * @test
  101. */
  102. public function can_keep_extension_for_temp_file_on_remote_disk()
  103. {
  104. config()->set('excel.temporary_files.remote_disk', 'test');
  105. Queue::before(function (JobProcessing $event) {
  106. if ($event->job->resolveName() === ReadChunk::class) {
  107. /** @var TemporaryFile $tempFile */
  108. $tempFile = $this->inspectJobProperty($event->job, 'temporaryFile');
  109. $this->assertStringContains('.xlsx', $tempFile->getLocalPath());
  110. }
  111. });
  112. (new QueuedImport())->queue('import-batches.xlsx');
  113. }
  114. /**
  115. * @test
  116. */
  117. public function can_queue_import_with_remote_temp_disk_and_prefix()
  118. {
  119. config()->set('excel.temporary_files.remote_disk', 'test');
  120. config()->set('excel.temporary_files.remote_prefix', 'tmp/');
  121. $import = new QueuedImport();
  122. $chain = $import->queue('import-batches.xlsx')->chain([
  123. new AfterQueueImportJob(5000),
  124. ]);
  125. $this->assertInstanceOf(PendingDispatch::class, $chain);
  126. }
  127. /**
  128. * @test
  129. */
  130. public function can_automatically_delete_temp_file_on_failure_when_using_remote_disk()
  131. {
  132. config()->set('excel.temporary_files.remote_disk', 'test');
  133. $tempFile = '';
  134. Queue::exceptionOccurred(function (JobExceptionOccurred $event) use (&$tempFile) {
  135. if ($event->job->resolveName() === ReadChunk::class) {
  136. $tempFile = $this->inspectJobProperty($event->job, 'temporaryFile');
  137. }
  138. });
  139. try {
  140. (new QueuedImportWithFailure())->queue('import-batches.xlsx');
  141. } catch (Throwable $e) {
  142. $this->assertEquals('Something went wrong in the chunk', $e->getMessage());
  143. }
  144. $this->assertFalse($tempFile->existsLocally());
  145. $this->assertTrue($tempFile->exists());
  146. }
  147. /**
  148. * @test
  149. */
  150. public function cannot_automatically_delete_temp_file_on_failure_when_using_local_disk()
  151. {
  152. $tempFile = '';
  153. Queue::exceptionOccurred(function (JobExceptionOccurred $event) use (&$tempFile) {
  154. if ($event->job->resolveName() === ReadChunk::class) {
  155. $tempFile = $this->inspectJobProperty($event->job, 'temporaryFile');
  156. }
  157. });
  158. try {
  159. (new QueuedImportWithFailure())->queue('import-batches.xlsx');
  160. } catch (Throwable $e) {
  161. $this->assertEquals('Something went wrong in the chunk', $e->getMessage());
  162. }
  163. $this->assertTrue($tempFile->exists());
  164. }
  165. /**
  166. * @test
  167. */
  168. public function can_force_remote_download_and_deletion_for_each_chunk_on_queue()
  169. {
  170. config()->set('excel.temporary_files.remote_disk', 'test');
  171. config()->set('excel.temporary_files.force_resync_remote', true);
  172. Bus::fake([AfterImportJob::class]);
  173. Queue::after(function (JobProcessed $event) {
  174. if ($event->job->resolveName() === ReadChunk::class) {
  175. $tempFile = $this->inspectJobProperty($event->job, 'temporaryFile');
  176. // Should not exist locally after each chunk
  177. $this->assertFalse(
  178. $tempFile->existsLocally()
  179. );
  180. }
  181. });
  182. (new QueuedImport())->queue('import-batches.xlsx');
  183. }
  184. /**
  185. * @test
  186. */
  187. public function can_define_middleware_method_on_queued_import()
  188. {
  189. try {
  190. (new QueuedImportWithMiddleware())->queue('import-batches.xlsx');
  191. } catch (Throwable $e) {
  192. $this->assertEquals('Job reached middleware method', $e->getMessage());
  193. }
  194. }
  195. /**
  196. * @test
  197. */
  198. public function can_define_retry_until_method_on_queued_import()
  199. {
  200. try {
  201. (new QueuedImportWithRetryUntil())->queue('import-batches.xlsx');
  202. } catch (Throwable $e) {
  203. $this->assertEquals('Job reached retryUntil method', $e->getMessage());
  204. }
  205. }
  206. /**
  207. * @test
  208. */
  209. public function can_define_max_exceptions_property_on_queued_import()
  210. {
  211. $maxExceptionsCount = 0;
  212. Queue::exceptionOccurred(function (JobExceptionOccurred $event) use (&$maxExceptionsCount) {
  213. if ($event->job->resolveName() === ReadChunk::class) {
  214. $maxExceptionsCount = $this->inspectJobProperty($event->job, 'maxExceptions');
  215. }
  216. });
  217. try {
  218. $import = new QueuedImportWithFailure();
  219. $import->maxExceptions = 3;
  220. $import->queue('import-batches.xlsx');
  221. } catch (Throwable $e) {
  222. $this->assertEquals('Something went wrong in the chunk', $e->getMessage());
  223. }
  224. $this->assertEquals(3, $maxExceptionsCount);
  225. }
  226. }