2016-06-02 13:48:57 +01:00
|
|
|
<?php
|
|
|
|
|
|
2017-01-17 14:30:19 +00:00
|
|
|
namespace Illuminate\Tests\Queue;
|
|
|
|
|
|
2016-06-02 13:48:57 +01:00
|
|
|
use Illuminate\Container\Container;
|
2016-12-03 18:53:29 +00:00
|
|
|
use Illuminate\Database\Capsule\Manager as DB;
|
|
|
|
|
use Illuminate\Database\Eloquent\Model as Eloquent;
|
2019-09-10 17:16:05 +02:00
|
|
|
use Illuminate\Database\Schema\Blueprint;
|
2023-08-25 23:48:19 +10:00
|
|
|
use Illuminate\Events\Dispatcher;
|
2019-09-10 17:16:05 +02:00
|
|
|
use Illuminate\Queue\DatabaseQueue;
|
2023-08-25 23:48:19 +10:00
|
|
|
use Illuminate\Queue\Events\JobQueued;
|
2024-01-17 21:20:57 +00:00
|
|
|
use Illuminate\Queue\Events\JobQueueing;
|
2019-09-10 17:16:05 +02:00
|
|
|
use Illuminate\Support\Carbon;
|
2023-08-25 23:48:19 +10:00
|
|
|
use Illuminate\Support\Str;
|
2019-09-10 17:16:05 +02:00
|
|
|
use PHPUnit\Framework\TestCase;
|
2016-06-02 13:48:57 +01:00
|
|
|
|
2016-12-30 21:31:11 +01:00
|
|
|
class QueueDatabaseQueueIntegrationTest extends TestCase
|
2016-06-02 13:48:57 +01:00
|
|
|
{
|
|
|
|
|
/**
|
2020-03-28 16:25:38 +01:00
|
|
|
* @var \Illuminate\Queue\DatabaseQueue
|
2016-06-02 13:48:57 +01:00
|
|
|
*/
|
|
|
|
|
protected $queue;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @var string The jobs table name.
|
|
|
|
|
*/
|
|
|
|
|
protected $table;
|
|
|
|
|
|
|
|
|
|
/**
|
2020-03-28 16:25:38 +01:00
|
|
|
* @var \Illuminate\Container\Container
|
2016-06-02 13:48:57 +01:00
|
|
|
*/
|
|
|
|
|
protected $container;
|
|
|
|
|
|
2019-02-08 23:05:58 +01:00
|
|
|
protected function setUp(): void
|
2016-06-02 13:48:57 +01:00
|
|
|
{
|
|
|
|
|
$db = new DB;
|
|
|
|
|
|
|
|
|
|
$db->addConnection([
|
2021-07-05 23:30:07 +08:00
|
|
|
'driver' => 'sqlite',
|
|
|
|
|
'database' => ':memory:',
|
2016-06-02 13:48:57 +01:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$db->bootEloquent();
|
|
|
|
|
|
|
|
|
|
$db->setAsGlobal();
|
|
|
|
|
|
|
|
|
|
$this->table = 'jobs';
|
|
|
|
|
|
|
|
|
|
$this->queue = new DatabaseQueue($this->connection(), $this->table);
|
|
|
|
|
|
2023-08-25 23:48:19 +10:00
|
|
|
$this->container = new Container;
|
|
|
|
|
|
|
|
|
|
$this->container->instance('events', new Dispatcher($this->container));
|
2016-06-02 13:48:57 +01:00
|
|
|
|
|
|
|
|
$this->queue->setContainer($this->container);
|
|
|
|
|
|
|
|
|
|
$this->createSchema();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Setup the database schema.
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function createSchema()
|
|
|
|
|
{
|
|
|
|
|
$this->schema()->create($this->table, function (Blueprint $table) {
|
|
|
|
|
$table->bigIncrements('id');
|
|
|
|
|
$table->string('queue');
|
|
|
|
|
$table->longText('payload');
|
|
|
|
|
$table->tinyInteger('attempts')->unsigned();
|
|
|
|
|
$table->unsignedInteger('reserved_at')->nullable();
|
|
|
|
|
$table->unsignedInteger('available_at');
|
|
|
|
|
$table->unsignedInteger('created_at');
|
2016-07-05 14:55:03 +01:00
|
|
|
$table->index(['queue', 'reserved_at']);
|
2016-06-02 13:48:57 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a database connection instance.
|
|
|
|
|
*
|
|
|
|
|
* @return \Illuminate\Database\Connection
|
|
|
|
|
*/
|
|
|
|
|
protected function connection()
|
|
|
|
|
{
|
|
|
|
|
return Eloquent::getConnectionResolver()->connection();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a schema builder instance.
|
|
|
|
|
*
|
2017-01-17 14:30:19 +00:00
|
|
|
* @return \Illuminate\Database\Schema\Builder
|
2016-06-02 13:48:57 +01:00
|
|
|
*/
|
|
|
|
|
protected function schema()
|
|
|
|
|
{
|
|
|
|
|
return $this->connection()->getSchemaBuilder();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Tear down the database schema.
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2019-02-08 23:05:58 +01:00
|
|
|
protected function tearDown(): void
|
2016-06-02 13:48:57 +01:00
|
|
|
{
|
|
|
|
|
$this->schema()->drop('jobs');
|
2026-01-05 18:12:30 +01:00
|
|
|
|
|
|
|
|
parent::tearDown();
|
2016-06-02 13:48:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test that jobs that are not reserved and have an available_at value less then now, are popped.
|
|
|
|
|
*/
|
|
|
|
|
public function testAvailableAndUnReservedJobsArePopped()
|
|
|
|
|
{
|
|
|
|
|
$this->connection()
|
|
|
|
|
->table('jobs')
|
|
|
|
|
->insert([
|
|
|
|
|
'id' => 1,
|
|
|
|
|
'queue' => $mock_queue_name = 'mock_queue_name',
|
|
|
|
|
'payload' => 'mock_payload',
|
|
|
|
|
'attempts' => 0,
|
|
|
|
|
'reserved_at' => null,
|
|
|
|
|
'available_at' => Carbon::now()->subSeconds(1)->getTimestamp(),
|
|
|
|
|
'created_at' => Carbon::now()->getTimestamp(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$popped_job = $this->queue->pop($mock_queue_name);
|
|
|
|
|
|
|
|
|
|
$this->assertNotNull($popped_job);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test that when jobs are popped, the attempts attribute is incremented.
|
|
|
|
|
*/
|
|
|
|
|
public function testPoppedJobsIncrementAttempts()
|
|
|
|
|
{
|
|
|
|
|
$job = [
|
|
|
|
|
'id' => 1,
|
|
|
|
|
'queue' => 'mock_queue_name',
|
|
|
|
|
'payload' => 'mock_payload',
|
|
|
|
|
'attempts' => 0,
|
|
|
|
|
'reserved_at' => null,
|
|
|
|
|
'available_at' => Carbon::now()->subSeconds(1)->getTimestamp(),
|
|
|
|
|
'created_at' => Carbon::now()->getTimestamp(),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$this->connection()->table('jobs')->insert($job);
|
|
|
|
|
|
|
|
|
|
$popped_job = $this->queue->pop($job['queue']);
|
|
|
|
|
|
|
|
|
|
$database_record = $this->connection()->table('jobs')->find($job['id']);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(1, $database_record->attempts, 'Job attempts not updated in the database!');
|
|
|
|
|
$this->assertEquals(1, $popped_job->attempts(), 'The "attempts" attribute of the Job object was not updated by pop!');
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 18:16:26 +05:30
|
|
|
/**
|
|
|
|
|
* Test that the queue can be cleared.
|
|
|
|
|
*/
|
|
|
|
|
public function testThatQueueCanBeCleared()
|
|
|
|
|
{
|
|
|
|
|
$this->connection()
|
|
|
|
|
->table('jobs')
|
|
|
|
|
->insert([[
|
|
|
|
|
'id' => 1,
|
|
|
|
|
'queue' => $mock_queue_name = 'mock_queue_name',
|
|
|
|
|
'payload' => 'mock_payload',
|
|
|
|
|
'attempts' => 0,
|
|
|
|
|
'reserved_at' => Carbon::now()->addDay()->getTimestamp(),
|
|
|
|
|
'available_at' => Carbon::now()->subDay()->getTimestamp(),
|
|
|
|
|
'created_at' => Carbon::now()->getTimestamp(),
|
|
|
|
|
], [
|
|
|
|
|
'id' => 2,
|
|
|
|
|
'queue' => $mock_queue_name,
|
|
|
|
|
'payload' => 'mock_payload 2',
|
|
|
|
|
'attempts' => 0,
|
|
|
|
|
'reserved_at' => null,
|
|
|
|
|
'available_at' => Carbon::now()->subSeconds(1)->getTimestamp(),
|
|
|
|
|
'created_at' => Carbon::now()->getTimestamp(),
|
|
|
|
|
]]);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(2, $this->queue->clear($mock_queue_name));
|
|
|
|
|
$this->assertEquals(0, $this->queue->size());
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-02 13:48:57 +01:00
|
|
|
/**
|
|
|
|
|
* Test that jobs that are not reserved and have an available_at value in the future, are not popped.
|
|
|
|
|
*/
|
|
|
|
|
public function testUnavailableJobsAreNotPopped()
|
|
|
|
|
{
|
|
|
|
|
$this->connection()
|
|
|
|
|
->table('jobs')
|
|
|
|
|
->insert([
|
|
|
|
|
'id' => 1,
|
|
|
|
|
'queue' => $mock_queue_name = 'mock_queue_name',
|
|
|
|
|
'payload' => 'mock_payload',
|
|
|
|
|
'attempts' => 0,
|
|
|
|
|
'reserved_at' => null,
|
|
|
|
|
'available_at' => Carbon::now()->addSeconds(60)->getTimestamp(),
|
|
|
|
|
'created_at' => Carbon::now()->getTimestamp(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$popped_job = $this->queue->pop($mock_queue_name);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($popped_job);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test that jobs that are reserved and have expired are popped.
|
|
|
|
|
*/
|
|
|
|
|
public function testThatReservedAndExpiredJobsArePopped()
|
|
|
|
|
{
|
|
|
|
|
$this->connection()
|
|
|
|
|
->table('jobs')
|
|
|
|
|
->insert([
|
|
|
|
|
'id' => 1,
|
|
|
|
|
'queue' => $mock_queue_name = 'mock_queue_name',
|
|
|
|
|
'payload' => 'mock_payload',
|
|
|
|
|
'attempts' => 0,
|
|
|
|
|
'reserved_at' => Carbon::now()->subDay()->getTimestamp(),
|
|
|
|
|
'available_at' => Carbon::now()->addDay()->getTimestamp(),
|
|
|
|
|
'created_at' => Carbon::now()->getTimestamp(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$popped_job = $this->queue->pop($mock_queue_name);
|
|
|
|
|
|
|
|
|
|
$this->assertNotNull($popped_job);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test that jobs that are reserved and not expired and available are not popped.
|
|
|
|
|
*/
|
|
|
|
|
public function testThatReservedJobsAreNotPopped()
|
|
|
|
|
{
|
|
|
|
|
$this->connection()
|
|
|
|
|
->table('jobs')
|
|
|
|
|
->insert([
|
|
|
|
|
'id' => 1,
|
|
|
|
|
'queue' => $mock_queue_name = 'mock_queue_name',
|
|
|
|
|
'payload' => 'mock_payload',
|
|
|
|
|
'attempts' => 0,
|
|
|
|
|
'reserved_at' => Carbon::now()->addDay()->getTimestamp(),
|
|
|
|
|
'available_at' => Carbon::now()->subDay()->getTimestamp(),
|
|
|
|
|
'created_at' => Carbon::now()->getTimestamp(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$popped_job = $this->queue->pop($mock_queue_name);
|
|
|
|
|
|
|
|
|
|
$this->assertNull($popped_job);
|
|
|
|
|
}
|
2023-08-25 23:48:19 +10:00
|
|
|
|
2024-01-17 21:20:57 +00:00
|
|
|
public function testJobPayloadIsAvailableOnEvents()
|
2023-08-25 23:48:19 +10:00
|
|
|
{
|
2024-01-17 21:20:57 +00:00
|
|
|
$jobQueueingEvent = null;
|
|
|
|
|
$jobQueuedEvent = null;
|
2023-08-25 23:48:19 +10:00
|
|
|
Str::createUuidsUsingSequence([
|
|
|
|
|
'expected-job-uuid',
|
|
|
|
|
]);
|
2024-01-17 21:20:57 +00:00
|
|
|
$this->container['events']->listen(function (JobQueueing $e) use (&$jobQueueingEvent) {
|
|
|
|
|
$jobQueueingEvent = $e;
|
|
|
|
|
});
|
|
|
|
|
$this->container['events']->listen(function (JobQueued $e) use (&$jobQueuedEvent) {
|
|
|
|
|
$jobQueuedEvent = $e;
|
2023-08-25 23:48:19 +10:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$this->queue->push('MyJob', [
|
|
|
|
|
'laravel' => 'Framework',
|
|
|
|
|
]);
|
|
|
|
|
|
2024-01-17 21:20:57 +00:00
|
|
|
$this->assertIsArray($jobQueueingEvent->payload());
|
|
|
|
|
$this->assertSame('expected-job-uuid', $jobQueueingEvent->payload()['uuid']);
|
|
|
|
|
|
|
|
|
|
$this->assertIsArray($jobQueuedEvent->payload());
|
|
|
|
|
$this->assertSame('expected-job-uuid', $jobQueuedEvent->payload()['uuid']);
|
2023-08-25 23:48:19 +10:00
|
|
|
}
|
2016-06-02 13:48:57 +01:00
|
|
|
}
|