QueueDatabaseQueueIntegrationTest.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <?php
  2. namespace Illuminate\Tests\Queue;
  3. use Illuminate\Container\Container;
  4. use Illuminate\Database\Capsule\Manager as DB;
  5. use Illuminate\Database\Eloquent\Model as Eloquent;
  6. use Illuminate\Database\Schema\Blueprint;
  7. use Illuminate\Queue\DatabaseQueue;
  8. use Illuminate\Support\Carbon;
  9. use PHPUnit\Framework\TestCase;
  10. class QueueDatabaseQueueIntegrationTest extends TestCase
  11. {
  12. /**
  13. * @var \Illuminate\Queue\DatabaseQueue
  14. */
  15. protected $queue;
  16. /**
  17. * @var string The jobs table name.
  18. */
  19. protected $table;
  20. /**
  21. * @var \Illuminate\Container\Container
  22. */
  23. protected $container;
  24. protected function setUp(): void
  25. {
  26. $db = new DB;
  27. $db->addConnection([
  28. 'driver' => 'sqlite',
  29. 'database' => ':memory:',
  30. ]);
  31. $db->bootEloquent();
  32. $db->setAsGlobal();
  33. $this->table = 'jobs';
  34. $this->queue = new DatabaseQueue($this->connection(), $this->table);
  35. $this->container = $this->createMock(Container::class);
  36. $this->queue->setContainer($this->container);
  37. $this->createSchema();
  38. }
  39. /**
  40. * Setup the database schema.
  41. *
  42. * @return void
  43. */
  44. public function createSchema()
  45. {
  46. $this->schema()->create($this->table, function (Blueprint $table) {
  47. $table->bigIncrements('id');
  48. $table->string('queue');
  49. $table->longText('payload');
  50. $table->tinyInteger('attempts')->unsigned();
  51. $table->unsignedInteger('reserved_at')->nullable();
  52. $table->unsignedInteger('available_at');
  53. $table->unsignedInteger('created_at');
  54. $table->index(['queue', 'reserved_at']);
  55. });
  56. }
  57. /**
  58. * Get a database connection instance.
  59. *
  60. * @return \Illuminate\Database\Connection
  61. */
  62. protected function connection()
  63. {
  64. return Eloquent::getConnectionResolver()->connection();
  65. }
  66. /**
  67. * Get a schema builder instance.
  68. *
  69. * @return \Illuminate\Database\Schema\Builder
  70. */
  71. protected function schema()
  72. {
  73. return $this->connection()->getSchemaBuilder();
  74. }
  75. /**
  76. * Tear down the database schema.
  77. *
  78. * @return void
  79. */
  80. protected function tearDown(): void
  81. {
  82. $this->schema()->drop('jobs');
  83. }
  84. /**
  85. * Test that jobs that are not reserved and have an available_at value less then now, are popped.
  86. */
  87. public function testAvailableAndUnReservedJobsArePopped()
  88. {
  89. $this->connection()
  90. ->table('jobs')
  91. ->insert([
  92. 'id' => 1,
  93. 'queue' => $mock_queue_name = 'mock_queue_name',
  94. 'payload' => 'mock_payload',
  95. 'attempts' => 0,
  96. 'reserved_at' => null,
  97. 'available_at' => Carbon::now()->subSeconds(1)->getTimestamp(),
  98. 'created_at' => Carbon::now()->getTimestamp(),
  99. ]);
  100. $popped_job = $this->queue->pop($mock_queue_name);
  101. $this->assertNotNull($popped_job);
  102. }
  103. /**
  104. * Test that when jobs are popped, the attempts attribute is incremented.
  105. */
  106. public function testPoppedJobsIncrementAttempts()
  107. {
  108. $job = [
  109. 'id' => 1,
  110. 'queue' => 'mock_queue_name',
  111. 'payload' => 'mock_payload',
  112. 'attempts' => 0,
  113. 'reserved_at' => null,
  114. 'available_at' => Carbon::now()->subSeconds(1)->getTimestamp(),
  115. 'created_at' => Carbon::now()->getTimestamp(),
  116. ];
  117. $this->connection()->table('jobs')->insert($job);
  118. $popped_job = $this->queue->pop($job['queue']);
  119. $database_record = $this->connection()->table('jobs')->find($job['id']);
  120. $this->assertEquals(1, $database_record->attempts, 'Job attempts not updated in the database!');
  121. $this->assertEquals(1, $popped_job->attempts(), 'The "attempts" attribute of the Job object was not updated by pop!');
  122. }
  123. /**
  124. * Test that the queue can be cleared.
  125. */
  126. public function testThatQueueCanBeCleared()
  127. {
  128. $this->connection()
  129. ->table('jobs')
  130. ->insert([[
  131. 'id' => 1,
  132. 'queue' => $mock_queue_name = 'mock_queue_name',
  133. 'payload' => 'mock_payload',
  134. 'attempts' => 0,
  135. 'reserved_at' => Carbon::now()->addDay()->getTimestamp(),
  136. 'available_at' => Carbon::now()->subDay()->getTimestamp(),
  137. 'created_at' => Carbon::now()->getTimestamp(),
  138. ], [
  139. 'id' => 2,
  140. 'queue' => $mock_queue_name,
  141. 'payload' => 'mock_payload 2',
  142. 'attempts' => 0,
  143. 'reserved_at' => null,
  144. 'available_at' => Carbon::now()->subSeconds(1)->getTimestamp(),
  145. 'created_at' => Carbon::now()->getTimestamp(),
  146. ]]);
  147. $this->assertEquals(2, $this->queue->clear($mock_queue_name));
  148. $this->assertEquals(0, $this->queue->size());
  149. }
  150. /**
  151. * Test that jobs that are not reserved and have an available_at value in the future, are not popped.
  152. */
  153. public function testUnavailableJobsAreNotPopped()
  154. {
  155. $this->connection()
  156. ->table('jobs')
  157. ->insert([
  158. 'id' => 1,
  159. 'queue' => $mock_queue_name = 'mock_queue_name',
  160. 'payload' => 'mock_payload',
  161. 'attempts' => 0,
  162. 'reserved_at' => null,
  163. 'available_at' => Carbon::now()->addSeconds(60)->getTimestamp(),
  164. 'created_at' => Carbon::now()->getTimestamp(),
  165. ]);
  166. $popped_job = $this->queue->pop($mock_queue_name);
  167. $this->assertNull($popped_job);
  168. }
  169. /**
  170. * Test that jobs that are reserved and have expired are popped.
  171. */
  172. public function testThatReservedAndExpiredJobsArePopped()
  173. {
  174. $this->connection()
  175. ->table('jobs')
  176. ->insert([
  177. 'id' => 1,
  178. 'queue' => $mock_queue_name = 'mock_queue_name',
  179. 'payload' => 'mock_payload',
  180. 'attempts' => 0,
  181. 'reserved_at' => Carbon::now()->subDay()->getTimestamp(),
  182. 'available_at' => Carbon::now()->addDay()->getTimestamp(),
  183. 'created_at' => Carbon::now()->getTimestamp(),
  184. ]);
  185. $popped_job = $this->queue->pop($mock_queue_name);
  186. $this->assertNotNull($popped_job);
  187. }
  188. /**
  189. * Test that jobs that are reserved and not expired and available are not popped.
  190. */
  191. public function testThatReservedJobsAreNotPopped()
  192. {
  193. $this->connection()
  194. ->table('jobs')
  195. ->insert([
  196. 'id' => 1,
  197. 'queue' => $mock_queue_name = 'mock_queue_name',
  198. 'payload' => 'mock_payload',
  199. 'attempts' => 0,
  200. 'reserved_at' => Carbon::now()->addDay()->getTimestamp(),
  201. 'available_at' => Carbon::now()->subDay()->getTimestamp(),
  202. 'created_at' => Carbon::now()->getTimestamp(),
  203. ]);
  204. $popped_job = $this->queue->pop($mock_queue_name);
  205. $this->assertNull($popped_job);
  206. }
  207. }