Skip to content

[VarDumper] Add functional test for ServerDumpCommand #53737

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

Open
wants to merge 1 commit into
base: 7.4
Choose a base branch
from
Open
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
25 changes: 18 additions & 7 deletions src/Symfony/Component/VarDumper/Command/ServerDumpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\Stub;
use Symfony\Component\VarDumper\Command\Descriptor\CliDescriptor;
use Symfony\Component\VarDumper\Command\Descriptor\DumpDescriptorInterface;
use Symfony\Component\VarDumper\Command\Descriptor\HtmlDescriptor;
Expand Down Expand Up @@ -85,15 +86,25 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$errorIo = $io->getErrorStyle();
$errorIo->title('Symfony Var Dumper Server');

$this->server->start();

$errorIo->success(sprintf('Server listening on %s', $this->server->getHost()));
$errorIo->comment('Quit the server with CONTROL-C.');

$this->server->listen(function (Data $data, array $context, int $clientId) use ($descriptor, $io) {
$descriptor->describe($io, $data, $context, $clientId);
});
$this->server->listen(
function (int $clientId, string $message) use ($descriptor, $io) {
$payload = @unserialize(base64_decode($message), ['allowed_classes' => [Data::class, Stub::class]]);

// Impossible to decode the message, give up.
if (false === $payload) {
return;
}

if (!\is_array($payload) || \count($payload) < 2 || !$payload[0] instanceof Data || !\is_array($payload[1])) {
return;
}
[$data, $context] = $payload;
$descriptor->describe($io, $data, $context, $clientId);
},
$input,
);

return 0;
}
Expand Down
44 changes: 22 additions & 22 deletions src/Symfony/Component/VarDumper/Server/DumpServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\VarDumper\Server;

use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Input\StreamableInputInterface;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\Stub;

Expand Down Expand Up @@ -49,33 +50,20 @@ public function start(): void
}
}

public function listen(callable $callback): void
public function listen(callable $callback, ?StreamableInputInterface $streamInput = null): void
{
if (null === $this->socket) {
$inputStream = null;

if ($streamInput instanceof StreamableInputInterface && $stream = $streamInput->getStream()) {
$inputStream = $stream;
} elseif (null === $this->socket) {
$this->start();
}

foreach ($this->getMessages() as $clientId => $message) {
foreach ($this->getMessages($inputStream) as $clientId => $message) {
$this->logger?->info('Received a payload from client {clientId}', ['clientId' => $clientId]);

$payload = @unserialize(base64_decode($message), ['allowed_classes' => [Data::class, Stub::class]]);

// Impossible to decode the message, give up.
if (false === $payload) {
$this->logger?->warning('Unable to decode a message from {clientId} client.', ['clientId' => $clientId]);

continue;
}

if (!\is_array($payload) || \count($payload) < 2 || !$payload[0] instanceof Data || !\is_array($payload[1])) {
$this->logger?->warning('Invalid payload from {clientId} client. Expected an array of two elements (Data $data, array $context)', ['clientId' => $clientId]);

continue;
}

[$data, $context] = $payload;

$callback($data, $context, $clientId);
$callback($clientId, $message);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a BC break as this changes the contract of the callback.
Also I'm not sure this makes sense it terms of responsibility.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this following your comment in the PR #53518.
Do you have an idea ?
To help you, here a try of usage on the monolog bridge to see possibilities.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry we should try to keep the existing signature callback.
It's fine to me if we don't factorize the code with ServerLogCommand
The motivation for this PR is testing. Can't we do an integration test instead, where we start a real process?

}
}

Expand All @@ -84,8 +72,20 @@ public function getHost(): string
return $this->host;
}

private function getMessages(): iterable
/**
* @param ?resource
*/
private function getMessages($inputStream): iterable
{
if (null !== $inputStream) {
while (!feof($inputStream)) {
$stream = fgets($inputStream);
yield (int) $stream => $stream;
}

return;
}

$sockets = [(int) $this->socket => $this->socket];
$write = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandCompletionTester;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Command\ServerDumpCommand;
use Symfony\Component\VarDumper\Server\DumpServer;

Expand All @@ -28,6 +30,24 @@ public function testComplete(array $input, array $expectedSuggestions)
$this->assertSame($expectedSuggestions, $tester->complete($input));
}

public function testServerDumpSuccess()
{
$command = $this->createCommand();
$commandTester = new CommandTester($command);

$data = new Data([['my dump']]);
$input = base64_encode(serialize([$data, ['timestamp' => time(), 'source' => ['name' => 'sourceName', 'line' => 222, 'file' => 'myFile']]]))."\n";

$commandTester->setInputs([$input]);

$commandTester->execute(['--format' => 'html']);

$commandTester->assertCommandIsSuccessful();

$output = $commandTester->getDisplay();
$this->assertStringContainsString('my dump', $output);
}

public static function provideCompletionSuggestions()
{
yield 'option --format' => [
Expand All @@ -38,6 +58,6 @@ public static function provideCompletionSuggestions()

private function createCommand(): ServerDumpCommand
{
return new ServerDumpCommand($this->createMock(DumpServer::class));
return new ServerDumpCommand(new DumpServer(''));
}
}