Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[10.x] Add serializeAndRestore() to QueueFake andBusFake #48131

Merged
merged 11 commits into from
Aug 25, 2023
52 changes: 47 additions & 5 deletions src/Illuminate/Support/Testing/Fakes/BusFake.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ class BusFake implements Fake, QueueingDispatcher
*/
protected $batches = [];

/**
* Indicates if commands should be serialized and restored when pushed to the Bus.
*
* @var bool
*/
protected bool $serializeAndRestore = false;

/**
* Create a new bus fake instance.
*
Expand Down Expand Up @@ -585,7 +592,7 @@ public function hasDispatchedAfterResponse($command)
public function dispatch($command)
{
if ($this->shouldFakeJob($command)) {
$this->commands[get_class($command)][] = $command;
$this->commands[get_class($command)][] = $this->getCommandRepresentation($command);
} else {
return $this->dispatcher->dispatch($command);
}
Expand All @@ -603,7 +610,7 @@ public function dispatch($command)
public function dispatchSync($command, $handler = null)
{
if ($this->shouldFakeJob($command)) {
$this->commandsSync[get_class($command)][] = $command;
$this->commandsSync[get_class($command)][] = $this->getCommandRepresentation($command);
} else {
return $this->dispatcher->dispatchSync($command, $handler);
}
Expand All @@ -619,7 +626,7 @@ public function dispatchSync($command, $handler = null)
public function dispatchNow($command, $handler = null)
{
if ($this->shouldFakeJob($command)) {
$this->commands[get_class($command)][] = $command;
$this->commands[get_class($command)][] = $this->getCommandRepresentation($command);
} else {
return $this->dispatcher->dispatchNow($command, $handler);
}
Expand All @@ -634,7 +641,7 @@ public function dispatchNow($command, $handler = null)
public function dispatchToQueue($command)
{
if ($this->shouldFakeJob($command)) {
$this->commands[get_class($command)][] = $command;
$this->commands[get_class($command)][] = $this->getCommandRepresentation($command);
} else {
return $this->dispatcher->dispatchToQueue($command);
}
Expand All @@ -649,7 +656,7 @@ public function dispatchToQueue($command)
public function dispatchAfterResponse($command)
{
if ($this->shouldFakeJob($command)) {
$this->commandsAfterResponse[get_class($command)][] = $command;
$this->commandsAfterResponse[get_class($command)][] = $this->getCommandRepresentation($command);
} else {
return $this->dispatcher->dispatch($command);
}
Expand Down Expand Up @@ -754,6 +761,41 @@ protected function shouldDispatchCommand($command)
})->isNotEmpty();
}

/**
* Specify if commands should be serialized and restored when being batched.
*
* @param bool $serializeAndRestore
* @return $this
*/
public function serializeAndRestore(bool $serializeAndRestore = true)
{
$this->serializeAndRestore = $serializeAndRestore;

return $this;
}

/**
* Serialize and unserialize the command to simulate the queueing process.
*
* @param mixed $command
* @return mixed
*/
protected function serializeAndRestoreCommand($command)
{
return unserialize(serialize($command));
}

/**
* Return the command representation that should be stored.
*
* @param mixed $command
* @return mixed
*/
protected function getCommandRepresentation($command)
{
return $this->serializeAndRestore ? $this->serializeAndRestoreCommand($command) : $command;
}

/**
* Set the pipes commands should be piped through before dispatching.
*
Expand Down
33 changes: 32 additions & 1 deletion src/Illuminate/Support/Testing/Fakes/QueueFake.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ class QueueFake extends QueueManager implements Fake, Queue
*/
protected $jobs = [];

/**
* Indicates if items should be serialized and restored when pushed to the queue.
*
* @var bool
*/
protected bool $serializeAndRestore = false;

/**
* Create a new fake queue instance.
*
Expand Down Expand Up @@ -352,7 +359,7 @@ public function push($job, $data = '', $queue = null)
}

$this->jobs[is_object($job) ? get_class($job) : $job][] = [
'job' => $job,
'job' => $this->serializeAndRestore ? $this->serializeAndRestoreJob($job) : $job,
'queue' => $queue,
'data' => $data,
];
Expand Down Expand Up @@ -491,6 +498,30 @@ public function pushedJobs()
return $this->jobs;
}

/**
* Specify if jobs should be serialized and restored when being "pushed" to the queue.
*
* @param bool $serializeAndRestore
* @return $this
*/
public function serializeAndRestore(bool $serializeAndRestore = true)
{
$this->serializeAndRestore = $serializeAndRestore;

return $this;
}

/**
* Serialize and unserialize the job to simulate the queueing process.
*
* @param mixed $job
* @return mixed
*/
protected function serializeAndRestoreJob($job)
{
return unserialize(serialize($job));
}

/**
* Get the connection name for the queue.
*
Expand Down
71 changes: 71 additions & 0 deletions tests/Support/SupportTestingBusFakeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
use Illuminate\Contracts\Bus\QueueingDispatcher;
use Illuminate\Support\Testing\Fakes\BatchRepositoryFake;
use Illuminate\Support\Testing\Fakes\BusFake;
use Illuminate\Support\Testing\Fakes\PendingBatchFake;
use Mockery as m;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\TestCase;

Expand Down Expand Up @@ -666,6 +668,55 @@ public function testDecrementPendingJobsInFakeBatch()
$this->assertSame(0, $batch->failedJobs);
$this->assertSame(0, $batch->pendingJobs);
}

#[DataProvider('serializeAndRestoreCommandMethodsDataProvider')]
public function testCanSerializeAndRestoreCommands($commandFunctionName, $assertionFunctionName)
{
$serializingBusFake = (clone $this->fake)->serializeAndRestore();

// without setting the serialization, the job should return the value passed in
$this->fake->{$commandFunctionName}(new BusFakeJobWithSerialization('hello'));
$this->fake->{$assertionFunctionName}(BusFakeJobWithSerialization::class, fn($command) => $command->value === 'hello');

// when enabling the serializeAndRestore property, job has value modified
$serializingBusFake->{$commandFunctionName}(new BusFakeJobWithSerialization('hello'));
$serializingBusFake->{$assertionFunctionName}(
BusFakeJobWithSerialization::class,
fn($command) => $command->value === 'hello-serialized-unserialized'
);
}

public static function serializeAndRestoreCommandMethodsDataProvider(): array
{
return [
'dispatch' => ['dispatch', 'assertDispatched'],
'dispatchSync' => ['dispatchSync', 'assertDispatchedSync'],
'dispatchNow' => ['dispatchNow', 'assertDispatched'],
'dispatchAfterResponse' => ['dispatchAfterResponse', 'assertDispatchedAfterResponse'],
];
}

public function testCanSerializeAndRestoreCommandsInBatch()
{
$serializingBusFake = (clone $this->fake)->serializeAndRestore();

// without setting the serialization, the batch should return the value passed in
$this->fake->batch([
new BusFakeJobWithSerialization('hello'),
])->dispatch();
$this->fake->assertBatched(function(PendingBatchFake $batchedCollection) {
return $batchedCollection->jobs->count() === 1 && $batchedCollection->jobs->first()->value === 'hello';
});

// when enabling the serializeAndRestore property, each batch jobs will each be serialized/restored
$serializingBusFake->batch([
new BusFakeJobWithSerialization('hello'),
])->dispatch();

$serializingBusFake->assertBatched(function(PendingBatchFake $batchedCollection) {
return $batchedCollection->jobs->count() === 1 && $batchedCollection->jobs->first()->value === 'hello';
});
}
}

class BusJobStub
Expand All @@ -692,3 +743,23 @@ class ThirdJob
{
//
}


class BusFakeJobWithSerialization
{
use Queueable;

public function __construct(public $value)
{
}

public function __serialize(): array
{
return ['value' => $this->value .'-serialized'];
}

public function __unserialize(array $data): void
{
$this->value = $data['value'] .'-unserialized';
}
}
37 changes: 37 additions & 0 deletions tests/Support/SupportTestingQueueFakeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,24 @@ public function testItDoesntFakeJobsPassedViaExcept()
$fake->assertNotPushed(JobStub::class);
$fake->assertPushed(JobToFakeStub::class);
}

public function testItCanSerializeAndRestoreJobs()
{
// confirm that the default behavior is maintained
$this->fake->push(new JobWithSerialization('hello'));
$this->fake->assertPushed(JobWithSerialization::class, fn($job) => $job->value === 'hello');

$job = new JobWithSerialization('hello');

$fake = new QueueFake(new Application);
$fake->serializeAndRestore();
$fake->push($job);

$fake->assertPushed(
JobWithSerialization::class,
fn($job) => $job->value === 'hello-serialized-unserialized'
);
}
}

class JobStub
Expand Down Expand Up @@ -424,3 +442,22 @@ public function handle()
//
}
}

class JobWithSerialization
{
use Queueable;

public function __construct(public $value)
{
}

public function __serialize(): array
{
return ['value' => $this->value .'-serialized'];
}

public function __unserialize(array $data): void
{
$this->value = $data['value'] .'-unserialized';
}
}