Skip to content

Commit 8a19e95

Browse files
committed
Expand test suite
1 parent c387678 commit 8a19e95

File tree

6 files changed

+209
-1
lines changed

6 files changed

+209
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Please check the table below for supported Laravel and PHP versions:
5656
// does not respond by this deadline then the request is cancelled and the attempt
5757
// is marked as a DEADLINE_EXCEEDED failure.
5858
'dispatch_deadline' => null,
59+
'backoff' => 0,
5960
],
6061
```
6162

src/LogFake.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,12 @@ public function assertLogged(string $message): void
6868
{
6969
PHPUnit::assertTrue(in_array($message, $this->loggedMessages), 'The message [' . $message . '] was not logged.');
7070
}
71+
72+
public function assertNotLogged(string $message): void
73+
{
74+
PHPUnit::assertTrue(
75+
! in_array($message, $this->loggedMessages),
76+
'The message [' . $message . '] was logged.'
77+
);
78+
}
7179
}

src/TaskHandler.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ private function handleTask(array $task): void
147147

148148
$job->setAttempts($job->attempts() + 1);
149149

150-
app('queue.worker')->process($this->config['connection'], $job, new WorkerOptions());
150+
app('queue.worker')->process($this->config['connection'], $job, $this->getWorkerOptions());
151151
}
152152

153153
private function loadQueueRetryConfig(CloudTasksJob $job): void
@@ -171,4 +171,13 @@ public static function getCommandProperties(string $command): array
171171

172172
return [];
173173
}
174+
175+
public function getWorkerOptions(): WorkerOptions
176+
{
177+
$options = new WorkerOptions();
178+
179+
$options->backoff = $this->config['backoff'] ?? 0;
180+
181+
return $options;
182+
}
174183
}

tests/QueueTest.php

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,23 @@
55
namespace Tests;
66

77
use Google\Cloud\Tasks\V2\HttpMethod;
8+
use Google\Cloud\Tasks\V2\RetryConfig;
89
use Google\Cloud\Tasks\V2\Task;
10+
use Illuminate\Queue\Events\JobProcessed;
11+
use Illuminate\Queue\Events\JobProcessing;
912
use Illuminate\Queue\Events\JobQueued;
1013
use Illuminate\Support\Carbon;
1114
use Illuminate\Support\Facades\DB;
1215
use Illuminate\Support\Facades\Event;
16+
use Illuminate\Support\Facades\Log;
17+
use Illuminate\Support\Facades\Queue;
1318
use Stackkit\LaravelGoogleCloudTasksQueue\CloudTasksApi;
1419
use Stackkit\LaravelGoogleCloudTasksQueue\Events\JobReleased;
20+
use Stackkit\LaravelGoogleCloudTasksQueue\LogFake;
1521
use Stackkit\LaravelGoogleCloudTasksQueue\OpenIdVerificator;
1622
use Stackkit\LaravelGoogleCloudTasksQueue\TaskHandler;
1723
use Tests\Support\FailingJob;
24+
use Tests\Support\FailingJobWithExponentialBackoff;
1825
use Tests\Support\JobThatWillBeReleased;
1926
use Tests\Support\SimpleJob;
2027

@@ -286,4 +293,158 @@ public function jobs_can_be_released_with_a_delay()
286293
&& $scheduleTime === now()->getTimestamp() + 15;
287294
});
288295
}
296+
297+
/** @test */
298+
public function test_default_backoff()
299+
{
300+
// Arrange
301+
CloudTasksApi::fake();
302+
OpenIdVerificator::fake();
303+
Event::fake($this->getJobReleasedAfterExceptionEvent());
304+
305+
// Act
306+
$this->dispatch(new FailingJob())->run();
307+
308+
// Assert
309+
CloudTasksApi::assertTaskCreated(function (Task $task) {
310+
return is_null($task->getScheduleTime());
311+
});
312+
}
313+
314+
/** @test */
315+
public function test_backoff_from_queue_config()
316+
{
317+
// Arrange
318+
Carbon::setTestNow(now()->addDay());
319+
$this->setConfigValue('backoff', 123);
320+
CloudTasksApi::fake();
321+
OpenIdVerificator::fake();
322+
Event::fake($this->getJobReleasedAfterExceptionEvent());
323+
324+
// Act
325+
$this->dispatch(new FailingJob())->run();
326+
327+
// Assert
328+
CloudTasksApi::assertTaskCreated(function (Task $task) {
329+
return $task->getScheduleTime()
330+
&& $task->getScheduleTime()->getSeconds() === now()->getTimestamp() + 123;
331+
});
332+
}
333+
334+
/** @test */
335+
public function test_backoff_from_job()
336+
{
337+
// Arrange
338+
Carbon::setTestNow(now()->addDay());
339+
CloudTasksApi::fake();
340+
OpenIdVerificator::fake();
341+
Event::fake($this->getJobReleasedAfterExceptionEvent());
342+
343+
// Act
344+
$failingJob = new FailingJob();
345+
$failingJob->backoff = 123;
346+
$this->dispatch($failingJob)->run();
347+
348+
// Assert
349+
CloudTasksApi::assertTaskCreated(function (Task $task) {
350+
return $task->getScheduleTime()
351+
&& $task->getScheduleTime()->getSeconds() === now()->getTimestamp() + 123;
352+
});
353+
}
354+
355+
/** @test */
356+
public function test_exponential_backoff_from_job_method()
357+
{
358+
// Arrange
359+
Carbon::setTestNow(now()->addDay());
360+
CloudTasksApi::fake();
361+
OpenIdVerificator::fake();
362+
363+
// Act
364+
$releasedJob = $this->dispatch(new FailingJobWithExponentialBackoff())
365+
->runAndGetReleasedJob();
366+
$releasedJob = $releasedJob->runAndGetReleasedJob();
367+
$releasedJob->run();
368+
369+
// Assert
370+
CloudTasksApi::assertTaskCreated(function (Task $task) {
371+
return $task->getScheduleTime()
372+
&& $task->getScheduleTime()->getSeconds() === now()->getTimestamp() + 50;
373+
});
374+
CloudTasksApi::assertTaskCreated(function (Task $task) {
375+
return $task->getScheduleTime()
376+
&& $task->getScheduleTime()->getSeconds() === now()->getTimestamp() + 60;
377+
});
378+
CloudTasksApi::assertTaskCreated(function (Task $task) {
379+
return $task->getScheduleTime()
380+
&& $task->getScheduleTime()->getSeconds() === now()->getTimestamp() + 70;
381+
});
382+
}
383+
384+
/** @test */
385+
public function test_failing_method_on_job()
386+
{
387+
// Arrange
388+
CloudTasksApi::fake();
389+
CloudTasksApi::partialMock()->shouldReceive('getRetryConfig')->andReturn(
390+
// -1 is a valid option in Cloud Tasks to indicate there is no max.
391+
(new RetryConfig())->setMaxAttempts(1)
392+
);
393+
394+
OpenIdVerificator::fake();
395+
Log::swap(new LogFake());
396+
397+
// Act
398+
$this->dispatch(new FailingJob())->run();
399+
400+
// Assert
401+
Log::assertLogged('FailingJob:failed');
402+
}
403+
404+
/** @test */
405+
public function test_queue_before_and_after_hooks()
406+
{
407+
// Arrange
408+
CloudTasksApi::fake();
409+
OpenIdVerificator::fake();
410+
Log::swap(new LogFake());
411+
412+
// Act
413+
Queue::before(function (JobProcessing $event) {
414+
logger('Queue::before:' . $event->job->payload()['data']['commandName']);
415+
});
416+
Queue::after(function (JobProcessed $event) {
417+
logger('Queue::after:' . $event->job->payload()['data']['commandName']);
418+
});
419+
$this->dispatch(new SimpleJob())->run();
420+
421+
// Assert
422+
Log::assertLogged('Queue::before:Tests\Support\SimpleJob');
423+
Log::assertLogged('Queue::after:Tests\Support\SimpleJob');
424+
}
425+
426+
/** @test */
427+
public function test_queue_looping_hook_not_supported_with_this_package()
428+
{
429+
// Arrange
430+
CloudTasksApi::fake();
431+
OpenIdVerificator::fake();
432+
Log::swap(new LogFake());
433+
434+
// Act
435+
Queue::looping(function () {
436+
logger('Queue::looping');
437+
});
438+
$this->dispatch(new SimpleJob())->run();
439+
440+
// Assert
441+
Log::assertNotLogged('Queue::looping');
442+
}
443+
444+
/** @test */
445+
public function test_ignoring_jobs_with_deleted_models()
446+
{
447+
// todo
448+
$this->assertTrue(true);
449+
}
289450
}

tests/Support/FailingJob.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@ public function handle()
3131
{
3232
throw new \Error('simulating a failing job');
3333
}
34+
35+
public function failed(\Throwable $throwable)
36+
{
37+
logger('FailingJob:failed');
38+
}
3439
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Tests\Support;
4+
5+
use Illuminate\Bus\Queueable;
6+
use Illuminate\Contracts\Queue\ShouldQueue;
7+
use Illuminate\Foundation\Bus\Dispatchable;
8+
use Illuminate\Queue\InteractsWithQueue;
9+
use Illuminate\Queue\SerializesModels;
10+
11+
class FailingJobWithExponentialBackoff implements ShouldQueue
12+
{
13+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
14+
15+
public function handle()
16+
{
17+
throw new \Error('simulating a failing job');
18+
}
19+
20+
public function backoff(): array
21+
{
22+
return [50, 60, 70];
23+
}
24+
}

0 commit comments

Comments
 (0)