Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Illuminate/Queue/CallQueuedHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Illuminate\Log\Context\Repository as ContextRepository;
use Illuminate\Pipeline\Pipeline;
use RuntimeException;
use Throwable;

class CallQueuedHandler
{
Expand Down Expand Up @@ -343,7 +344,7 @@ public function failed(array $data, $e, string $uuid, ?Job $job = null)
$this->ensureChainCatchCallbacksAreInvoked($uuid, $command, $e);

if (method_exists($command, 'failed')) {
$command->failed($e);
$this->container->call([$command, 'failed'], [Throwable::class => $e]);
}
}

Expand Down
98 changes: 90 additions & 8 deletions tests/Integration/Queue/CallQueuedHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
use Illuminate\Support\Facades\Event;
use Mockery as m;
use Orchestra\Testbench\TestCase;
use RuntimeException;
use Throwable;

class CallQueuedHandlerTest extends TestCase
{
public function testJobCanBeDispatched()
public function test_job_can_be_dispatched()
{
CallQueuedHandlerTestJob::$handled = false;

Expand All @@ -39,7 +41,7 @@ public function testJobCanBeDispatched()
$this->assertTrue(CallQueuedHandlerTestJob::$handled);
}

public function testJobCanBeDispatchedThroughMiddleware()
public function test_job_can_be_dispatched_through_middleware()
{
CallQueuedHandlerTestJobWithMiddleware::$handled = false;
CallQueuedHandlerTestJobWithMiddleware::$middlewareCommand = null;
Expand All @@ -61,7 +63,7 @@ public function testJobCanBeDispatchedThroughMiddleware()
$this->assertTrue(CallQueuedHandlerTestJobWithMiddleware::$handled);
}

public function testJobCanBeDispatchedThroughMiddlewareOnDispatch()
public function test_job_can_be_dispatched_through_middleware_on_dispatch()
{
$_SERVER['__test.dispatchMiddleware'] = false;
CallQueuedHandlerTestJobWithMiddleware::$handled = false;
Expand All @@ -88,7 +90,7 @@ public function testJobCanBeDispatchedThroughMiddlewareOnDispatch()
$this->assertTrue($_SERVER['__test.dispatchMiddleware']);
}

public function testJobIsMarkedAsFailedIfModelNotFoundExceptionIsThrown()
public function test_job_is_marked_as_failed_if_model_not_found_exception_is_thrown()
{
$instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app);

Expand All @@ -101,7 +103,7 @@ public function testJobIsMarkedAsFailedIfModelNotFoundExceptionIsThrown()
]);
}

public function testJobIsDeletedIfHasDeleteProperty()
public function test_job_is_deleted_if_has_delete_property()
{
Event::fake();

Expand All @@ -123,7 +125,7 @@ public function testJobIsDeletedIfHasDeleteProperty()
Event::assertNotDispatched(JobFailed::class);
}

public function testJobIsDeletedIfHasDeleteAttribute()
public function test_job_is_deleted_if_has_delete_attribute()
{
Event::fake();

Expand All @@ -139,13 +141,13 @@ public function testJobIsDeletedIfHasDeleteAttribute()
$job->shouldReceive('failed')->never();

$instance->call($job, [
'command' => serialize(new CallQueuedHandlerAttributeExceptionThrower()),
'command' => serialize(new CallQueuedHandlerAttributeExceptionThrower),
]);

Event::assertNotDispatched(JobFailed::class);
}

public function testBatchJobIsRecordedWhenDeletedDueToMissingModel()
public function test_batch_job_is_recorded_when_deleted_due_to_missing_model()
{
Event::fake();

Expand Down Expand Up @@ -181,6 +183,44 @@ public function testBatchJobIsRecordedWhenDeletedDueToMissingModel()

Event::assertNotDispatched(JobFailed::class);
}

public function test_failed_method_receives_injected_dependencies(): void
{
CallQueuedHandlerJobWithFailedHook::$capturedServiceValue = null;
CallQueuedHandlerJobWithFailedHook::$capturedException = null;

$this->app->bind(CallQueuedHandlerTestService::class, fn () => new CallQueuedHandlerTestService('injected'));

$instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app);
$exception = new RuntimeException('something went wrong');

$instance->failed(
['command' => serialize(new CallQueuedHandlerJobWithFailedHook)],
$exception,
'test-uuid',
m::mock(Job::class),
);

$this->assertSame('injected', CallQueuedHandlerJobWithFailedHook::$capturedServiceValue);
$this->assertSame($exception, CallQueuedHandlerJobWithFailedHook::$capturedException);
}

public function test_failed_method_without_dependency_injection_still_works(): void
{
CallQueuedHandlerJobWithFailedHookNoDI::$capturedException = null;

$instance = new CallQueuedHandler(new Dispatcher($this->app), $this->app);
$exception = new RuntimeException('simple failure');

$instance->failed(
['command' => serialize(new CallQueuedHandlerJobWithFailedHookNoDI)],
$exception,
'test-uuid',
m::mock(Job::class),
);

$this->assertSame($exception, CallQueuedHandlerJobWithFailedHookNoDI::$capturedException);
}
}

class CallQueuedHandlerTestJob
Expand Down Expand Up @@ -295,3 +335,45 @@ public function handle($command, $next)
return $next($command);
}
}

readonly class CallQueuedHandlerTestService
{
public function __construct(public string $value)
{
}
}

class CallQueuedHandlerJobWithFailedHook
{
use InteractsWithQueue, Queueable;

public static ?string $capturedServiceValue = null;

public static ?Throwable $capturedException = null;

public function handle(): void
{
}

public function failed(Throwable $e, CallQueuedHandlerTestService $service): void
{
static::$capturedServiceValue = $service->value;
static::$capturedException = $e;
}
}

class CallQueuedHandlerJobWithFailedHookNoDI
{
use InteractsWithQueue, Queueable;

public static ?Throwable $capturedException = null;

public function handle(): void
{
}

public function failed(Throwable $e): void
{
static::$capturedException = $e;
}
}
Loading