Skip to content

Commit

Permalink
✨ Support Sentry V4
Browse files Browse the repository at this point in the history
  • Loading branch information
B-Galati committed Mar 2, 2024
1 parent fa21c6b commit 098e9b2
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 101 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
- php: 8.1 # should use monolog v3
- php: 8.2 # should use monolog v3
- php: 8.3 # should use monolog v3
# TODO matrix should support Both versions of Sentry SDK
steps:
- uses: actions/checkout@v2

Expand Down
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@
"require": {
"php": "^7.4 || ^8.0",
"monolog/monolog": "^1.6 || ^2.0 || ^3.0",
"sentry/sentry": "^3.1"
"sentry/sentry": "^3.1 || ^4.0"
},
"require-dev": {
"coduo/php-matcher": "^6.0.8",
"friendsofphp/php-cs-fixer": "^3.16",
"friendsofphp/php-cs-fixer": "3.51.0",
"jangregor/phpstan-prophecy": "1.0.0",
"phpstan/phpstan": "1.10.14",
"phpstan/phpstan-phpunit": "1.3.11",
"phpstan/phpstan": "1.10.59",
"phpstan/phpstan-phpunit": "1.3.16",
"phpunit/phpunit": "^9.6.7",
"symfony/phpunit-bridge": "^6.2.10",
"symfony/var-dumper": ">4.3"
Expand Down
1 change: 1 addition & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ parameters:
inferPrivatePropertyTypeFromConstructor: true
tipsOfTheDay: false
checkMissingIterableValueType: false
treatPhpDocTypesAsCertain: false

level: 8
paths: [ src, tests ]
Expand Down
111 changes: 14 additions & 97 deletions tests/SentryHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,25 @@

namespace BGalati\MonologSentryHandler\Tests;

use BGalati\MonologSentryHandler\SentryHandler;
use Coduo\PHPMatcher\PHPUnit\PHPMatcherAssertions;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\PromiseInterface;
use Monolog\Formatter\LineFormatter;
use Monolog\Level;
use Monolog\Logger;
use Monolog\LogRecord;
use PHPUnit\Framework\TestCase;
use Sentry\Breadcrumb;
use Sentry\Client;
use Sentry\ClientBuilder;
use Sentry\Event;
use Sentry\Integration\EnvironmentIntegration;
use Sentry\Options;
use Sentry\Response;
use Sentry\ResponseStatus;
use Sentry\SentrySdk;
use Sentry\Severity;
use Sentry\State\HubInterface;
use Sentry\State\Scope;
use Sentry\Transport\TransportFactoryInterface;
use Sentry\Transport\TransportInterface;

if (defined(Client::class.'::SDK_VERSION') && version_compare(Client::SDK_VERSION, '4.0.0') >= 0) {
require __DIR__.'/SentryStubV4.php';
} else {
require __DIR__.'/SentryStubV3.php';
}

final class SentryHandlerTest extends TestCase
{
Expand All @@ -47,7 +44,12 @@ protected function setUp(): void
],
]
);
$clientBuilder->setTransportFactory(new FakeTransportFactory($this->transport));

if (defined(Client::class.'::SDK_VERSION') && version_compare(Client::SDK_VERSION, '4.0.0') >= 0) {
$clientBuilder->setTransport($this->transport);
} else {
$clientBuilder->setTransportFactory(new FakeTransportFactory($this->transport));

Check failure on line 51 in tests/SentryHandlerTest.php

View workflow job for this annotation

GitHub Actions / Static analysis

Call to an undefined method Sentry\ClientBuilder::setTransportFactory().
}

$client = $clientBuilder->getClient();

Expand Down Expand Up @@ -492,7 +494,7 @@ private function assertCapturedEvent(Severity $severity, string $message, array

if ($breadcrumbs) {
$this->assertMatchesPattern(
json_encode($breadcrumbs),
json_encode($breadcrumbs, JSON_THROW_ON_ERROR),
json_encode(
array_map(
static function (Breadcrumb $breadcrumb) {
Expand Down Expand Up @@ -544,88 +546,3 @@ private function createSentryHandler(?int $level = null): SpySentryHandler
return $handler;
}
}

class SpySentryHandler extends SentryHandler
{
/**
* @var bool
*/
public $afterWriteCalled = false;

protected function processScope(Scope $scope, $record, Event $sentryEvent): void
{
$scope->setExtra('processScope', 'called');
}

protected function afterWrite(): void
{
$this->afterWriteCalled = true;

parent::afterWrite();
}

public function resetSpy(): void
{
$this->afterWriteCalled = false;
}
}

class SpyTransport implements TransportInterface
{
/**
* @var Event|null
*/
public $spiedEvent;

/**
* @var bool
*/
public $isFlushed = false;

public function send(Event $event): PromiseInterface
{
$this->spiedEvent = $event;

return new FulfilledPromise(new Response(ResponseStatus::skipped(), $event));
}

public function resetSpy(): void
{
$this->spiedEvent = null;
$this->isFlushed = false;
}

public function getSpiedEvent(): Event
{
if (null === $this->spiedEvent) {
throw new \RuntimeException('No spied scope');
}

return $this->spiedEvent;
}

public function close(?int $timeout = null): PromiseInterface
{
$this->isFlushed = true;

return new FulfilledPromise(true);
}
}

class FakeTransportFactory implements TransportFactoryInterface
{
/**
* @var SpyTransport
*/
private $transport;

public function __construct(SpyTransport $transport)
{
$this->transport = $transport;
}

public function create(Options $options): TransportInterface
{
return $this->transport;
}
}
74 changes: 74 additions & 0 deletions tests/SentryStubV3.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

declare(strict_types=1);

namespace BGalati\MonologSentryHandler\Tests;

use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\PromiseInterface;
use Sentry\Event;
use Sentry\Options;
use Sentry\Response;
use Sentry\ResponseStatus;
use Sentry\Transport\TransportFactoryInterface;
use Sentry\Transport\TransportInterface;

class SpyTransport implements TransportInterface
{
/**
* @var Event|null
*/
public $spiedEvent;

/**
* @var bool
*/
public $isFlushed = false;

public function send(Event $event): PromiseInterface

Check failure on line 28 in tests/SentryStubV3.php

View workflow job for this annotation

GitHub Actions / Static analysis

Method BGalati\MonologSentryHandler\Tests\SpyTransport::send() has invalid return type GuzzleHttp\Promise\PromiseInterface.

Check failure on line 28 in tests/SentryStubV3.php

View workflow job for this annotation

GitHub Actions / Static analysis

Return type GuzzleHttp\Promise\PromiseInterface of method BGalati\MonologSentryHandler\Tests\SpyTransport::send() is not covariant with return type Sentry\Transport\Result of method Sentry\Transport\TransportInterface::send().
{
$this->spiedEvent = $event;

return new FulfilledPromise(new Response(ResponseStatus::skipped(), $event));

Check failure on line 32 in tests/SentryStubV3.php

View workflow job for this annotation

GitHub Actions / Static analysis

Call to static method skipped() on an unknown class Sentry\ResponseStatus.

Check failure on line 32 in tests/SentryStubV3.php

View workflow job for this annotation

GitHub Actions / Static analysis

Instantiated class GuzzleHttp\Promise\FulfilledPromise not found.

Check failure on line 32 in tests/SentryStubV3.php

View workflow job for this annotation

GitHub Actions / Static analysis

Instantiated class Sentry\Response not found.

Check failure on line 32 in tests/SentryStubV3.php

View workflow job for this annotation

GitHub Actions / Static analysis

Method BGalati\MonologSentryHandler\Tests\SpyTransport::send() should return GuzzleHttp\Promise\PromiseInterface but returns GuzzleHttp\Promise\FulfilledPromise.
}

public function resetSpy(): void
{
$this->spiedEvent = null;
$this->isFlushed = false;
}

public function getSpiedEvent(): Event
{
if (null === $this->spiedEvent) {
throw new \RuntimeException('No spied scope');
}

return $this->spiedEvent;
}

public function close(?int $timeout = null): PromiseInterface

Check failure on line 50 in tests/SentryStubV3.php

View workflow job for this annotation

GitHub Actions / Static analysis

Method BGalati\MonologSentryHandler\Tests\SpyTransport::close() has invalid return type GuzzleHttp\Promise\PromiseInterface.

Check failure on line 50 in tests/SentryStubV3.php

View workflow job for this annotation

GitHub Actions / Static analysis

Return type GuzzleHttp\Promise\PromiseInterface of method BGalati\MonologSentryHandler\Tests\SpyTransport::close() is not covariant with return type Sentry\Transport\Result of method Sentry\Transport\TransportInterface::close().
{
$this->isFlushed = true;

return new FulfilledPromise(true);

Check failure on line 54 in tests/SentryStubV3.php

View workflow job for this annotation

GitHub Actions / Static analysis

Instantiated class GuzzleHttp\Promise\FulfilledPromise not found.
}
}

class FakeTransportFactory implements TransportFactoryInterface
{
/**
* @var SpyTransport
*/
private $transport;

public function __construct(SpyTransport $transport)
{
$this->transport = $transport;
}

public function create(Options $options): TransportInterface
{
return $this->transport;
}
}
52 changes: 52 additions & 0 deletions tests/SentryStubV4.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace BGalati\MonologSentryHandler\Tests;

use Sentry\Event;
use Sentry\Transport\Result;
use Sentry\Transport\ResultStatus;
use Sentry\Transport\TransportInterface;

class SpyTransport implements TransportInterface
{
/**
* @var Event|null
*/
public $spiedEvent;

/**
* @var bool
*/
public $isFlushed = false;

public function send(Event $event): Result
{
$this->spiedEvent = $event;

return new Result(ResultStatus::skipped(), $event);
}

public function resetSpy(): void
{
$this->spiedEvent = null;
$this->isFlushed = false;
}

public function getSpiedEvent(): Event
{
if (null === $this->spiedEvent) {
throw new \RuntimeException('No spied scope');
}

return $this->spiedEvent;
}

public function close(?int $timeout = null): Result
{
$this->isFlushed = true;

return new Result(ResultStatus::success());
}
}
34 changes: 34 additions & 0 deletions tests/SpySentryHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace BGalati\MonologSentryHandler\Tests;

use BGalati\MonologSentryHandler\SentryHandler;
use Sentry\Event;
use Sentry\State\Scope;

class SpySentryHandler extends SentryHandler
{
/**
* @var bool
*/
public $afterWriteCalled = false;

protected function processScope(Scope $scope, $record, Event $sentryEvent): void
{
$scope->setExtra('processScope', 'called');
}

protected function afterWrite(): void
{
$this->afterWriteCalled = true;

parent::afterWrite();
}

public function resetSpy(): void
{
$this->afterWriteCalled = false;
}
}

0 comments on commit 098e9b2

Please sign in to comment.