Skip to content

Commit 02c61c3

Browse files
[10.x] Add serializeAndRestore() to QueueFake andBusFake (#48131)
* serialize and restore model * move to a trait * make name more generic * remove references to `job` * formatting * remove hint * formatting * fix docblock comment for QueueFake * add serialization/restore functionality to BusFake * add serialization tests for BusFake * formatting --------- Co-authored-by: Taylor Otwell <[email protected]>
1 parent 8426f87 commit 02c61c3

File tree

4 files changed

+187
-6
lines changed

4 files changed

+187
-6
lines changed

src/Illuminate/Support/Testing/Fakes/BusFake.php

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ class BusFake implements Fake, QueueingDispatcher
7171
*/
7272
protected $batches = [];
7373

74+
/**
75+
* Indicates if commands should be serialized and restored when pushed to the Bus.
76+
*
77+
* @var bool
78+
*/
79+
protected bool $serializeAndRestore = false;
80+
7481
/**
7582
* Create a new bus fake instance.
7683
*
@@ -585,7 +592,7 @@ public function hasDispatchedAfterResponse($command)
585592
public function dispatch($command)
586593
{
587594
if ($this->shouldFakeJob($command)) {
588-
$this->commands[get_class($command)][] = $command;
595+
$this->commands[get_class($command)][] = $this->getCommandRepresentation($command);
589596
} else {
590597
return $this->dispatcher->dispatch($command);
591598
}
@@ -603,7 +610,7 @@ public function dispatch($command)
603610
public function dispatchSync($command, $handler = null)
604611
{
605612
if ($this->shouldFakeJob($command)) {
606-
$this->commandsSync[get_class($command)][] = $command;
613+
$this->commandsSync[get_class($command)][] = $this->getCommandRepresentation($command);
607614
} else {
608615
return $this->dispatcher->dispatchSync($command, $handler);
609616
}
@@ -619,7 +626,7 @@ public function dispatchSync($command, $handler = null)
619626
public function dispatchNow($command, $handler = null)
620627
{
621628
if ($this->shouldFakeJob($command)) {
622-
$this->commands[get_class($command)][] = $command;
629+
$this->commands[get_class($command)][] = $this->getCommandRepresentation($command);
623630
} else {
624631
return $this->dispatcher->dispatchNow($command, $handler);
625632
}
@@ -634,7 +641,7 @@ public function dispatchNow($command, $handler = null)
634641
public function dispatchToQueue($command)
635642
{
636643
if ($this->shouldFakeJob($command)) {
637-
$this->commands[get_class($command)][] = $command;
644+
$this->commands[get_class($command)][] = $this->getCommandRepresentation($command);
638645
} else {
639646
return $this->dispatcher->dispatchToQueue($command);
640647
}
@@ -649,7 +656,7 @@ public function dispatchToQueue($command)
649656
public function dispatchAfterResponse($command)
650657
{
651658
if ($this->shouldFakeJob($command)) {
652-
$this->commandsAfterResponse[get_class($command)][] = $command;
659+
$this->commandsAfterResponse[get_class($command)][] = $this->getCommandRepresentation($command);
653660
} else {
654661
return $this->dispatcher->dispatch($command);
655662
}
@@ -754,6 +761,41 @@ protected function shouldDispatchCommand($command)
754761
})->isNotEmpty();
755762
}
756763

764+
/**
765+
* Specify if commands should be serialized and restored when being batched.
766+
*
767+
* @param bool $serializeAndRestore
768+
* @return $this
769+
*/
770+
public function serializeAndRestore(bool $serializeAndRestore = true)
771+
{
772+
$this->serializeAndRestore = $serializeAndRestore;
773+
774+
return $this;
775+
}
776+
777+
/**
778+
* Serialize and unserialize the command to simulate the queueing process.
779+
*
780+
* @param mixed $command
781+
* @return mixed
782+
*/
783+
protected function serializeAndRestoreCommand($command)
784+
{
785+
return unserialize(serialize($command));
786+
}
787+
788+
/**
789+
* Return the command representation that should be stored.
790+
*
791+
* @param mixed $command
792+
* @return mixed
793+
*/
794+
protected function getCommandRepresentation($command)
795+
{
796+
return $this->serializeAndRestore ? $this->serializeAndRestoreCommand($command) : $command;
797+
}
798+
757799
/**
758800
* Set the pipes commands should be piped through before dispatching.
759801
*

src/Illuminate/Support/Testing/Fakes/QueueFake.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ class QueueFake extends QueueManager implements Fake, Queue
4343
*/
4444
protected $jobs = [];
4545

46+
/**
47+
* Indicates if items should be serialized and restored when pushed to the queue.
48+
*
49+
* @var bool
50+
*/
51+
protected bool $serializeAndRestore = false;
52+
4653
/**
4754
* Create a new fake queue instance.
4855
*
@@ -352,7 +359,7 @@ public function push($job, $data = '', $queue = null)
352359
}
353360

354361
$this->jobs[is_object($job) ? get_class($job) : $job][] = [
355-
'job' => $job,
362+
'job' => $this->serializeAndRestore ? $this->serializeAndRestoreJob($job) : $job,
356363
'queue' => $queue,
357364
'data' => $data,
358365
];
@@ -491,6 +498,30 @@ public function pushedJobs()
491498
return $this->jobs;
492499
}
493500

501+
/**
502+
* Specify if jobs should be serialized and restored when being "pushed" to the queue.
503+
*
504+
* @param bool $serializeAndRestore
505+
* @return $this
506+
*/
507+
public function serializeAndRestore(bool $serializeAndRestore = true)
508+
{
509+
$this->serializeAndRestore = $serializeAndRestore;
510+
511+
return $this;
512+
}
513+
514+
/**
515+
* Serialize and unserialize the job to simulate the queueing process.
516+
*
517+
* @param mixed $job
518+
* @return mixed
519+
*/
520+
protected function serializeAndRestoreJob($job)
521+
{
522+
return unserialize(serialize($job));
523+
}
524+
494525
/**
495526
* Get the connection name for the queue.
496527
*

tests/Support/SupportTestingBusFakeTest.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use Illuminate\Contracts\Bus\QueueingDispatcher;
88
use Illuminate\Support\Testing\Fakes\BatchRepositoryFake;
99
use Illuminate\Support\Testing\Fakes\BusFake;
10+
use Illuminate\Support\Testing\Fakes\PendingBatchFake;
1011
use Mockery as m;
12+
use PHPUnit\Framework\Attributes\DataProvider;
1113
use PHPUnit\Framework\ExpectationFailedException;
1214
use PHPUnit\Framework\TestCase;
1315

@@ -666,6 +668,55 @@ public function testDecrementPendingJobsInFakeBatch()
666668
$this->assertSame(0, $batch->failedJobs);
667669
$this->assertSame(0, $batch->pendingJobs);
668670
}
671+
672+
#[DataProvider('serializeAndRestoreCommandMethodsDataProvider')]
673+
public function testCanSerializeAndRestoreCommands($commandFunctionName, $assertionFunctionName)
674+
{
675+
$serializingBusFake = (clone $this->fake)->serializeAndRestore();
676+
677+
// without setting the serialization, the job should return the value passed in
678+
$this->fake->{$commandFunctionName}(new BusFakeJobWithSerialization('hello'));
679+
$this->fake->{$assertionFunctionName}(BusFakeJobWithSerialization::class, fn($command) => $command->value === 'hello');
680+
681+
// when enabling the serializeAndRestore property, job has value modified
682+
$serializingBusFake->{$commandFunctionName}(new BusFakeJobWithSerialization('hello'));
683+
$serializingBusFake->{$assertionFunctionName}(
684+
BusFakeJobWithSerialization::class,
685+
fn($command) => $command->value === 'hello-serialized-unserialized'
686+
);
687+
}
688+
689+
public static function serializeAndRestoreCommandMethodsDataProvider(): array
690+
{
691+
return [
692+
'dispatch' => ['dispatch', 'assertDispatched'],
693+
'dispatchSync' => ['dispatchSync', 'assertDispatchedSync'],
694+
'dispatchNow' => ['dispatchNow', 'assertDispatched'],
695+
'dispatchAfterResponse' => ['dispatchAfterResponse', 'assertDispatchedAfterResponse'],
696+
];
697+
}
698+
699+
public function testCanSerializeAndRestoreCommandsInBatch()
700+
{
701+
$serializingBusFake = (clone $this->fake)->serializeAndRestore();
702+
703+
// without setting the serialization, the batch should return the value passed in
704+
$this->fake->batch([
705+
new BusFakeJobWithSerialization('hello'),
706+
])->dispatch();
707+
$this->fake->assertBatched(function(PendingBatchFake $batchedCollection) {
708+
return $batchedCollection->jobs->count() === 1 && $batchedCollection->jobs->first()->value === 'hello';
709+
});
710+
711+
// when enabling the serializeAndRestore property, each batch jobs will each be serialized/restored
712+
$serializingBusFake->batch([
713+
new BusFakeJobWithSerialization('hello'),
714+
])->dispatch();
715+
716+
$serializingBusFake->assertBatched(function(PendingBatchFake $batchedCollection) {
717+
return $batchedCollection->jobs->count() === 1 && $batchedCollection->jobs->first()->value === 'hello';
718+
});
719+
}
669720
}
670721

671722
class BusJobStub
@@ -692,3 +743,23 @@ class ThirdJob
692743
{
693744
//
694745
}
746+
747+
748+
class BusFakeJobWithSerialization
749+
{
750+
use Queueable;
751+
752+
public function __construct(public $value)
753+
{
754+
}
755+
756+
public function __serialize(): array
757+
{
758+
return ['value' => $this->value .'-serialized'];
759+
}
760+
761+
public function __unserialize(array $data): void
762+
{
763+
$this->value = $data['value'] .'-unserialized';
764+
}
765+
}

tests/Support/SupportTestingQueueFakeTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,24 @@ public function testItDoesntFakeJobsPassedViaExcept()
374374
$fake->assertNotPushed(JobStub::class);
375375
$fake->assertPushed(JobToFakeStub::class);
376376
}
377+
378+
public function testItCanSerializeAndRestoreJobs()
379+
{
380+
// confirm that the default behavior is maintained
381+
$this->fake->push(new JobWithSerialization('hello'));
382+
$this->fake->assertPushed(JobWithSerialization::class, fn($job) => $job->value === 'hello');
383+
384+
$job = new JobWithSerialization('hello');
385+
386+
$fake = new QueueFake(new Application);
387+
$fake->serializeAndRestore();
388+
$fake->push($job);
389+
390+
$fake->assertPushed(
391+
JobWithSerialization::class,
392+
fn($job) => $job->value === 'hello-serialized-unserialized'
393+
);
394+
}
377395
}
378396

379397
class JobStub
@@ -424,3 +442,22 @@ public function handle()
424442
//
425443
}
426444
}
445+
446+
class JobWithSerialization
447+
{
448+
use Queueable;
449+
450+
public function __construct(public $value)
451+
{
452+
}
453+
454+
public function __serialize(): array
455+
{
456+
return ['value' => $this->value .'-serialized'];
457+
}
458+
459+
public function __unserialize(array $data): void
460+
{
461+
$this->value = $data['value'] .'-unserialized';
462+
}
463+
}

0 commit comments

Comments
 (0)