Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
- Add the `sentry:test` command, to test if the Sentry SDK is functioning properly.

## 3.0.0-beta2 - 2019-03-22
- Disable Sentry's ErrorHandler, and report all errors using Symfony's events (#204)
Expand Down
55 changes: 55 additions & 0 deletions src/Command/SentryTestCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace Sentry\SentryBundle\Command;

use Sentry\State\Hub;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class SentryTestCommand extends Command
{
public function __construct()
{
parent::__construct('sentry:test');
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$currentHub = Hub::getCurrent();
$client = $currentHub->getClient();

if (! $client) {
$output->writeln('<error>No client found</error>');
$output->writeln('<info>Your DSN is probably missing, check your configuration</info>');

return 1;
}

$dsn = $client->getOptions()->getDsn();

if ($dsn) {
$output->writeln('<info>DSN correctly configured in the current client</info>');
} else {
$output->writeln('<error>No DSN configured in the current client, please check your configuration</error>');
$output->writeln('<info>To debug further, try bin/console debug:config sentry</info>');

return 1;
}

$output->writeln('Sending test message...');

$eventId = $currentHub->captureMessage('This is a test message from the Sentry bundle');

if ($eventId) {
$output->writeln("<info>Message sent successfully with ID $eventId</info>");
} else {
$output->writeln('<error>Message not sent!</error>');
$output->writeln('<warning>Check your DSN or your before_send callback if used</warning>');

return 1;
}

return 0;
}
}
4 changes: 4 additions & 0 deletions src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,9 @@
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="%sentry.listener_priorities.sub_request%" />
<tag name="kernel.event_listener" event="kernel.finish_request" method="onKernelFinishRequest" priority="%sentry.listener_priorities.sub_request%" />
</service>

<service id="Sentry\SentryBundle\Command\SentryTestCommand" class="Sentry\SentryBundle\Command\SentryTestCommand" public="false">
<tag name="console.command" />
</service>
</services>
</container>
118 changes: 118 additions & 0 deletions test/Command/SentryTestCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

namespace Sentry\SentryBundle\Test\Command;

use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Sentry\ClientInterface;
use Sentry\Options;
use Sentry\SentryBundle\Command\SentryTestCommand;
use Sentry\State\Hub;
use Sentry\State\HubInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;

class SentryTestCommandTest extends TestCase
{
public function testExecuteSuccessfully(): void
{
$options = new Options(['dsn' => 'http://public:secret@example.com/sentry/1']);
$client = $this->prophesize(ClientInterface::class);
$client->getOptions()
->willReturn($options);

$hub = $this->prophesize(HubInterface::class);
$hub->getClient()
->willReturn($client->reveal());
$lastEventId = 'abcdef0123456';
$hub->captureMessage(Argument::containingString('test'), Argument::cetera())
->shouldBeCalled()
->willReturn($lastEventId);

Hub::setCurrent($hub->reveal());

$commandTester = $this->executeCommand();

$output = $commandTester->getDisplay();
$this->assertContains('DSN correctly configured', $output);
$this->assertContains('Sending test message', $output);
$this->assertContains('Message sent', $output);
$this->assertContains($lastEventId, $output);
$this->assertSame(0, $commandTester->getStatusCode());
}

public function testExecuteFailsDueToMissingDSN(): void
{
$client = $this->prophesize(ClientInterface::class);
$client->getOptions()
->willReturn(new Options());

$hub = $this->prophesize(HubInterface::class);
$hub->getClient()
->willReturn($client->reveal());

Hub::setCurrent($hub->reveal());

$commandTester = $this->executeCommand();

$this->assertNotSame(0, $commandTester->getStatusCode());
$output = $commandTester->getDisplay();
$this->assertContains('No DSN configured', $output);
$this->assertContains('try bin/console debug:config sentry', $output);
}

public function testExecuteFailsDueToMessageNotSent(): void
{
$options = new Options(['dsn' => 'http://public:secret@example.com/sentry/1']);
$client = $this->prophesize(ClientInterface::class);
$client->getOptions()
->willReturn($options);

$hub = $this->prophesize(HubInterface::class);
$hub->getClient()
->willReturn($client->reveal());
$hub->captureMessage(Argument::containingString('test'), Argument::cetera())
->shouldBeCalled()
->willReturn(null);

Hub::setCurrent($hub->reveal());

$commandTester = $this->executeCommand();

$this->assertNotSame(0, $commandTester->getStatusCode());
$output = $commandTester->getDisplay();
$this->assertContains('DSN correctly configured', $output);
$this->assertContains('Sending test message', $output);
$this->assertContains('Message not sent', $output);
}

public function testExecuteFailsDueToMissingClient(): void
{
$hub = $this->prophesize(HubInterface::class);
$hub->getClient()
->willReturn(null);

Hub::setCurrent($hub->reveal());

$commandTester = $this->executeCommand();

$this->assertNotSame(0, $commandTester->getStatusCode());
$output = $commandTester->getDisplay();
$this->assertContains('No client found', $output);
$this->assertContains('DSN is probably missing', $output);
}

private function executeCommand(): CommandTester
{
$application = new Application();
$application->add(new SentryTestCommand());

$command = $application->find('sentry:test');
$commandTester = new CommandTester($command);
$commandTester->execute([
'command' => $command->getName(),
]);

return $commandTester;
}
}
10 changes: 10 additions & 0 deletions test/SentryBundleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Sentry\Integration\ExceptionListenerIntegration;
use Sentry\Integration\IntegrationInterface;
use Sentry\Integration\RequestIntegration;
use Sentry\SentryBundle\Command\SentryTestCommand;
use Sentry\SentryBundle\DependencyInjection\SentryExtension;
use Sentry\SentryBundle\EventListener\ConsoleListener;
use Sentry\SentryBundle\EventListener\ErrorListener;
Expand Down Expand Up @@ -121,6 +122,15 @@ public function testContainerHasErrorListenerConfiguredCorrectly(): void
$this->assertSame($expectedTag, $consoleListener->getTags());
}

public function testContainerHasTestCommandRegisteredCorrectly(): void
{
$container = $this->getContainer();

$consoleListener = $container->getDefinition(SentryTestCommand::class);

$this->assertArrayHasKey('console.command', $consoleListener->getTags());
}

public function testIntegrationsListenersAreDisabledByDefault(): void
{
$container = $this->getContainer();
Expand Down