diff --git a/tests/ClientBuilderTest.php b/tests/ClientBuilderTest.php index 3c8eb5ce6..f9be538b9 100644 --- a/tests/ClientBuilderTest.php +++ b/tests/ClientBuilderTest.php @@ -4,12 +4,14 @@ namespace Sentry\Tests; -use Http\Client\Common\Plugin; -use Http\Client\Common\PluginClient; -use Http\Client\HttpAsyncClient; -use Http\Message\MessageFactory; -use Http\Message\UriFactory; -use Http\Promise\Promise; +use Http\Client\Common\Plugin as PluginInterface; +use Http\Client\HttpAsyncClient as HttpAsyncClientInterface; +use Http\Discovery\MessageFactoryDiscovery; +use Http\Discovery\UriFactoryDiscovery; +use Http\Message\MessageFactory as MessageFactoryInterface; +use Http\Message\UriFactory as UriFactoryInterface; +use Http\Promise\FulfilledPromise; +use Http\Promise\Promise as PromiseInterface; use Jean85\PrettyVersions; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -17,6 +19,7 @@ use Sentry\Client; use Sentry\ClientBuilder; use Sentry\Event; +use Sentry\FlushableClientInterface; use Sentry\Integration\ErrorListenerIntegration; use Sentry\Integration\ExceptionListenerIntegration; use Sentry\Integration\FatalErrorListenerIntegration; @@ -60,13 +63,17 @@ public function testNullTransportIsUsedWhenNoServerIsConfigured(): void */ public function testSetUriFactory(): void { - /** @var UriFactory|MockObject $uriFactory */ - $uriFactory = $this->createMock(UriFactory::class); + /** @var UriFactoryInterface&MockObject $uriFactory */ + $uriFactory = $this->createMock(UriFactoryInterface::class); + $uriFactory->expects($this->once()) + ->method('createUri') + ->willReturn(UriFactoryDiscovery::find()->createUri('http://www.example.com')); - $clientBuilder = ClientBuilder::create(['dsn' => 'http://public:secret@example.com/sentry/1']); - $clientBuilder->setUriFactory($uriFactory); + $client = ClientBuilder::create(['dsn' => 'http://public@example.com/sentry/1']) + ->setUriFactory($uriFactory) + ->getClient(); - $this->assertAttributeSame($uriFactory, 'uriFactory', $clientBuilder); + $client->captureMessage('foo'); } /** @@ -76,17 +83,17 @@ public function testSetUriFactory(): void */ public function testSetMessageFactory(): void { - /** @var MessageFactory|MockObject $messageFactory */ - $messageFactory = $this->createMock(MessageFactory::class); - - $clientBuilder = ClientBuilder::create(['dsn' => 'http://public:secret@example.com/sentry/1']); - $clientBuilder->setMessageFactory($messageFactory); + /** @var MessageFactoryInterface&MockObject $messageFactory */ + $messageFactory = $this->createMock(MessageFactoryInterface::class); + $messageFactory->expects($this->once()) + ->method('createRequest') + ->willReturn(MessageFactoryDiscovery::find()->createRequest('POST', 'http://www.example.com')); - $this->assertAttributeSame($messageFactory, 'messageFactory', $clientBuilder); - - $transport = $this->getObjectAttribute($clientBuilder->getClient(), 'transport'); + $client = ClientBuilder::create(['dsn' => 'http://public@example.com/sentry/1']) + ->setMessageFactory($messageFactory) + ->getClient(); - $this->assertAttributeSame($messageFactory, 'requestFactory', $transport); + $client->captureMessage('foo'); } /** @@ -96,14 +103,17 @@ public function testSetMessageFactory(): void */ public function testSetTransport(): void { - /** @var TransportInterface|MockObject $transport */ + /** @var TransportInterface&MockObject $transport */ $transport = $this->createMock(TransportInterface::class); + $transport->expects($this->once()) + ->method('send') + ->willReturn('ddb4a0b9ab1941bf92bd2520063663e3'); - $clientBuilder = ClientBuilder::create(['dsn' => 'http://public:secret@example.com/sentry/1']); - $clientBuilder->setTransport($transport); + $client = ClientBuilder::create(['dsn' => 'http://public@example.com/sentry/1']) + ->setTransport($transport) + ->getClient(); - $this->assertAttributeSame($transport, 'transport', $clientBuilder); - $this->assertAttributeSame($transport, 'transport', $clientBuilder->getClient()); + $this->assertSame('ddb4a0b9ab1941bf92bd2520063663e3', $client->captureMessage('foo')); } /** @@ -113,17 +123,19 @@ public function testSetTransport(): void */ public function testSetHttpClient(): void { - /** @var HttpAsyncClient|MockObject $httpClient */ - $httpClient = $this->createMock(HttpAsyncClient::class); - - $clientBuilder = ClientBuilder::create(['dsn' => 'http://public:secret@example.com/sentry/1']); - $clientBuilder->setHttpClient($httpClient); - - $this->assertAttributeSame($httpClient, 'httpClient', $clientBuilder); - - $transport = $this->getObjectAttribute($clientBuilder->getClient(), 'transport'); - - $this->assertAttributeSame($httpClient, 'client', $this->getObjectAttribute($transport, 'httpClient')); + /** @var HttpAsyncClientInterface&MockObject $httpClient */ + $httpClient = $this->createMock(HttpAsyncClientInterface::class); + $httpClient->expects($this->once()) + ->method('sendAsyncRequest') + ->willReturn(new FulfilledPromise(true)); + + /** @var FlushableClientInterface $client */ + $client = ClientBuilder::create(['dsn' => 'http://public@example.com/sentry/1']) + ->setHttpClient($httpClient) + ->getClient(); + + $client->captureMessage('foo'); + $client->flush(); } /** @@ -133,16 +145,19 @@ public function testSetHttpClient(): void */ public function testAddHttpClientPlugin(): void { - /** @var Plugin|MockObject $plugin */ - $plugin = $this->createMock(Plugin::class); - - $clientBuilder = new ClientBuilder(); - $clientBuilder->addHttpClientPlugin($plugin); - - $plugins = $this->getObjectAttribute($clientBuilder, 'httpClientPlugins'); - - $this->assertCount(1, $plugins); - $this->assertSame($plugin, $plugins[0]); + /** @var PluginInterface&MockObject $plugin */ + $plugin = $this->createMock(PluginInterface::class); + $plugin->expects($this->once()) + ->method('handleRequest') + ->willReturn(new FulfilledPromise(true)); + + /** @var FlushableClientInterface $client */ + $client = ClientBuilder::create(['dsn' => 'http://public@example.com/sentry/1']) + ->addHttpClientPlugin($plugin) + ->getClient(); + + $client->captureMessage('foo'); + $client->flush(); } /** @@ -153,36 +168,30 @@ public function testAddHttpClientPlugin(): void */ public function testRemoveHttpClientPlugin(): void { - $plugin = new PluginStub1(); - $plugin2 = new PluginStub2(); - - $clientBuilder = new ClientBuilder(); - $clientBuilder->addHttpClientPlugin($plugin); - $clientBuilder->addHttpClientPlugin($plugin); - $clientBuilder->addHttpClientPlugin($plugin2); - - $this->assertAttributeCount(3, 'httpClientPlugins', $clientBuilder); - - $clientBuilder->removeHttpClientPlugin(PluginStub1::class); - - $plugins = $this->getObjectAttribute($clientBuilder, 'httpClientPlugins'); - - $this->assertCount(1, $plugins); - $this->assertSame($plugin2, reset($plugins)); - } - - public function testGetClient(): void - { - $clientBuilder = ClientBuilder::create(['dsn' => 'http://public:secret@example.com/sentry/1']); - $client = $clientBuilder->getClient(); - - $this->assertInstanceOf(Client::class, $client); - $this->assertAttributeInstanceOf(HttpTransport::class, 'transport', $client); - - $transport = $this->getObjectAttribute($client, 'transport'); - - $this->assertAttributeSame($this->getObjectAttribute($clientBuilder, 'messageFactory'), 'requestFactory', $transport); - $this->assertAttributeInstanceOf(PluginClient::class, 'httpClient', $transport); + $plugin = new class() implements PluginInterface { + public function handleRequest(RequestInterface $request, callable $next, callable $first): PromiseInterface + { + return new FulfilledPromise(true); + } + }; + + $plugin2 = new class() implements PluginInterface { + public function handleRequest(RequestInterface $request, callable $next, callable $first): PromiseInterface + { + return new FulfilledPromise(true); + } + }; + + /** @var FlushableClientInterface $client */ + $client = ClientBuilder::create() + ->addHttpClientPlugin($plugin) + ->addHttpClientPlugin($plugin) + ->addHttpClientPlugin($plugin2) + ->removeHttpClientPlugin(\get_class($plugin2)) + ->getClient(); + + $client->captureMessage('foo'); + $client->flush(); } /** @@ -194,8 +203,7 @@ public function testIntegrationsAreAddedToClientCorrectly(bool $defaultIntegrati $options->setDefaultIntegrations($defaultIntegrations); $options->setIntegrations($integrations); - $clientBuilder = new ClientBuilder($options); - $client = $clientBuilder->getClient(); + $client = (new ClientBuilder($options))->getClient(); $actualIntegrationsClassNames = array_map('\get_class', $client->getOptions()->getIntegrations()); @@ -299,17 +307,3 @@ public function setupOnce(): void { } } - -final class PluginStub1 implements Plugin -{ - public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise - { - } -} - -final class PluginStub2 implements Plugin -{ - public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise - { - } -} diff --git a/tests/Context/AbstractContextTest.php b/tests/Context/AbstractContextTest.php index 2237f9012..8e1b82fe7 100644 --- a/tests/Context/AbstractContextTest.php +++ b/tests/Context/AbstractContextTest.php @@ -100,7 +100,8 @@ public function testOffsetSet(string $key, $value, ?string $expectedExceptionCla $context = $this->createContext(); $context[$key] = $value; - $this->assertArraySubset([$key => $value], $context->toArray()); + $this->assertArrayHasKey($key, $context); + $this->assertSame($value, $context[$key]); } /** diff --git a/tests/Context/ContextTest.php b/tests/Context/ContextTest.php index 79085e214..76a418776 100644 --- a/tests/Context/ContextTest.php +++ b/tests/Context/ContextTest.php @@ -9,14 +9,14 @@ class ContextTest extends TestCase { - public function testConstructor() + public function testConstructor(): void { $context = new Context(['foo' => 'bar']); - $this->assertAttributeEquals(['foo' => 'bar'], 'data', $context); + $this->assertSame(['foo' => 'bar'], $context->toArray()); } - public function testMerge() + public function testMerge(): void { $context = new Context([ 'foo' => 'bar', @@ -27,45 +27,45 @@ public function testMerge() $context->merge(['bar' => ['barfoo' => 'foobar']], true); - $this->assertAttributeEquals(['foo' => 'bar', 'bar' => ['foobar' => 'barfoo', 'barfoo' => 'foobar']], 'data', $context); + $this->assertSame(['foo' => 'bar', 'bar' => ['foobar' => 'barfoo', 'barfoo' => 'foobar']], $context->toArray()); $context->merge(['bar' => 'foo']); - $this->assertAttributeEquals(['foo' => 'bar', 'bar' => 'foo'], 'data', $context); + $this->assertSame(['foo' => 'bar', 'bar' => 'foo'], $context->toArray()); } - public function testSetData() + public function testSetData(): void { $context = new Context(['foo' => 'bar']); $context->setData(['bar' => 'foo']); - $this->assertAttributeEquals(['foo' => 'bar', 'bar' => 'foo'], 'data', $context); + $this->assertSame(['foo' => 'bar', 'bar' => 'foo'], $context->toArray()); $context->setData(['foo' => ['bar' => 'baz']]); - $this->assertAttributeEquals(['foo' => ['bar' => 'baz'], 'bar' => 'foo'], 'data', $context); + $this->assertSame(['foo' => ['bar' => 'baz'], 'bar' => 'foo'], $context->toArray()); } - public function testReplaceData() + public function testReplaceData(): void { $context = new Context(['foo' => 'bar']); $context->replaceData(['bar' => 'foo']); - $this->assertAttributeEquals(['bar' => 'foo'], 'data', $context); + $this->assertSame(['bar' => 'foo'], $context->toArray()); } - public function testClear() + public function testClear(): void { $context = new Context(['foo' => 'bar']); - $this->assertAttributeEquals(['foo' => 'bar'], 'data', $context); + $this->assertSame(['foo' => 'bar'], $context->toArray()); $context->clear(); - $this->assertAttributeEmpty('data', $context); + $this->assertSame([], $context->toArray()); } - public function testIsEmpty() + public function testIsEmpty(): void { $context = new Context(); @@ -76,51 +76,40 @@ public function testIsEmpty() $this->assertFalse($context->isEmpty()); } - public function testToArray() + public function testJsonSerialize(): void { $context = new Context(['foo' => 'bar']); - $this->assertEquals(['foo' => 'bar'], $context->toArray()); + $this->assertSame('{"foo":"bar"}', json_encode($context)); } - public function testJsonSerialize() - { - $context = new Context(['foo' => 'bar']); - - $this->assertEquals('{"foo":"bar"}', json_encode($context)); - } - - public function testArrayLikeBehaviour() + public function testArrayLikeBehaviour(): void { $context = new Context(); - $this->assertAttributeEquals([], 'data', $context); - $this->assertArrayNotHasKey('foo', $context); - // Accessing a key that does not exists in the data object should behave // like accessing a non-existent key of an array @$context['foo']; $error = error_get_last(); - $this->assertInternalType('array', $error); - $this->assertEquals('Undefined index: foo', $error['message']); + $this->assertIsArray($error); + $this->assertSame('Undefined index: foo', $error['message']); $context['foo'] = 'bar'; - $this->assertAttributeEquals(['foo' => 'bar'], 'data', $context); $this->assertTrue(isset($context['foo'])); - $this->assertEquals('bar', $context['foo']); + $this->assertSame('bar', $context['foo']); unset($context['foo']); $this->assertArrayNotHasKey('foo', $context); } - public function testGetIterator() + public function testGetIterator(): void { $context = new Context(['foo' => 'bar', 'bar' => 'foo']); - $this->assertEquals($context->toArray(), iterator_to_array($context)); + $this->assertSame($context->toArray(), iterator_to_array($context)); } } diff --git a/tests/Transport/HttpTransportTest.php b/tests/Transport/HttpTransportTest.php index 9f8d3df99..f5a8505ed 100644 --- a/tests/Transport/HttpTransportTest.php +++ b/tests/Transport/HttpTransportTest.php @@ -6,7 +6,6 @@ use Http\Client\HttpAsyncClient; use Http\Discovery\MessageFactoryDiscovery; -use Http\Promise\FulfilledPromise; use Http\Promise\RejectedPromise; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -18,39 +17,6 @@ final class HttpTransportTest extends TestCase { - /** - * @group legacy - * - * @expectedDeprecationMessage Delaying the sending of the events using the "Sentry\Transport\HttpTransport" class is deprecated since version 2.2 and will not work in 3.0. - */ - public function testSendDelaysExecutionUntilShutdown(): void - { - $promise = new FulfilledPromise('foo'); - - /** @var HttpAsyncClient&MockObject $httpClient */ - $httpClient = $this->createMock(HttpAsyncClient::class); - $httpClient->expects($this->once()) - ->method('sendAsyncRequest') - ->willReturn($promise); - - $transport = new HttpTransport( - new Options(['dsn' => 'http://public@example.com/sentry/1']), - $httpClient, - MessageFactoryDiscovery::find(), - true - ); - - $this->assertAttributeEmpty('pendingRequests', $transport); - - $transport->send(new Event()); - - $this->assertAttributeNotEmpty('pendingRequests', $transport); - - $transport->close(); - - $this->assertAttributeEmpty('pendingRequests', $transport); - } - public function testSendDoesNotDelayExecutionUntilShutdownWhenConfiguredToNotDoIt(): void { $promise = new RejectedPromise(new \Exception()); @@ -69,8 +35,6 @@ public function testSendDoesNotDelayExecutionUntilShutdownWhenConfiguredToNotDoI ); $transport->send(new Event()); - - $this->assertAttributeEmpty('pendingRequests', $transport); } public function testSendThrowsOnMissingProjectIdCredential(): void diff --git a/tests/Transport/SpoolTransportTest.php b/tests/Transport/SpoolTransportTest.php index 11b5e808d..501eefa61 100644 --- a/tests/Transport/SpoolTransportTest.php +++ b/tests/Transport/SpoolTransportTest.php @@ -33,14 +33,30 @@ public function testGetSpool(): void $this->assertSame($this->spool, $this->transport->getSpool()); } - public function testSend(): void + /** + * @dataProvider sendDataProvider + */ + public function testSend(bool $isSendingSuccessful): void { $event = new Event(); $this->spool->expects($this->once()) ->method('queueEvent') - ->with($event); + ->with($event) + ->willReturn($isSendingSuccessful); + + $eventId = $this->transport->send($event); - $this->transport->send($event); + if ($isSendingSuccessful) { + $this->assertSame($event->getId(), $eventId); + } else { + $this->assertNull($eventId); + } + } + + public function sendDataProvider(): \Generator + { + yield [true]; + yield [false]; } } diff --git a/tests/phpt/http_transport_send_event_delayed.phpt b/tests/phpt/http_transport_send_event_delayed.phpt new file mode 100644 index 000000000..b64a44028 --- /dev/null +++ b/tests/phpt/http_transport_send_event_delayed.phpt @@ -0,0 +1,59 @@ +--TEST-- +Test that the HttpTransport transport delays the event sending until the shutdown +--FILE-- +httpClientInvokationCount = &$httpClientInvokationCount; + } + + public function sendAsyncRequest(RequestInterface $request) + { + ++$this->httpClientInvokationCount; + + return new RejectedPromise(new \Exception()); + } +}; + +$transport = new HttpTransport( + new Options(['dsn' => 'http://public@example.com/sentry/1']), + $httpClient, + MessageFactoryDiscovery::find() +); + +$transport->send(new Event()); + +var_dump($httpClientInvokationCount); + +register_shutdown_function('register_shutdown_function', static function () use (&$httpClientInvokationCount): void { + var_dump($httpClientInvokationCount); +}); +?> +--EXPECT-- +int(0) +int(1) diff --git a/tests/phpt/spool_drain.phpt b/tests/phpt/spool_drain.phpt deleted file mode 100644 index 882361f9f..000000000 --- a/tests/phpt/spool_drain.phpt +++ /dev/null @@ -1,68 +0,0 @@ ---TEST-- -Test emptying spool transport ---FILE-- -spool = $spool; - } - - public function create(Options $options): TransportInterface - { - return new SpoolTransport($this->spool); - } -}; - -$client = ClientBuilder::create() - ->setTransportFactory($transportFactory) - ->getClient(); - -SentrySdk::getCurrentHub()->bindClient($client); - -register_shutdown_function('register_shutdown_function', static function () use ($spool, $nullTransport): void { - Assert::assertAttributeCount(1, 'events', $spool); - - $spool->flushQueue($nullTransport); - - Assert::assertAttributeCount(0, 'events', $spool); - - echo 'Shutdown function called'; -}); - -\Foo\Bar::baz(); -?> ---EXPECTF-- -Fatal error: Uncaught Error: Class '%s' not found in %s:%d -Stack trace: -%a -Shutdown function called