diff --git a/src/Client.php b/src/Client.php index 927982da..c6a718dd 100644 --- a/src/Client.php +++ b/src/Client.php @@ -17,8 +17,7 @@ use Bugsnag\Middleware\SessionData; use Bugsnag\Request\BasicResolver; use Bugsnag\Request\ResolverInterface; -use Composer\CaBundle\CaBundle; -use GuzzleHttp\Client as Guzzle; +use Bugsnag\Utils; use GuzzleHttp\ClientInterface; use ReflectionClass; use ReflectionException; @@ -30,7 +29,7 @@ class Client * * @var string */ - const ENDPOINT = 'https://notify.bugsnag.com'; + const ENDPOINT = Configuration::DEFAULT_NOTIFY_ENDPOINT; /** * The config instance. @@ -88,10 +87,13 @@ class Client public static function make($apiKey = null, $endpoint = null, $defaults = true) { $config = new Configuration($apiKey ?: getenv('BUGSNAG_API_KEY')); - $guzzle = static::makeGuzzle($endpoint ?: getenv('BUGSNAG_ENDPOINT')); - $client = new static($config, null, $guzzle); + if ($endpoint = $endpoint ?: getenv('BUGSNAG_ENDPOINT')) { + $sessionEndpoint = getenv('BUGSNAG_SESSION_ENDPOINT'); + $config->setEndpoints($endpoint, $sessionEndpoint); + } + $client = new static($config, null, null); if ($defaults) { $client->registerDefaultCallbacks(); } @@ -111,10 +113,20 @@ public static function make($apiKey = null, $endpoint = null, $defaults = true) public function __construct(Configuration $config, ResolverInterface $resolver = null, ClientInterface $guzzle = null) { $this->config = $config; + if ($guzzle) { + $this->config->setGuzzleClient($guzzle); + if (version_compare(ClientInterface::VERSION, '6') === 1) { + $endpoint = $guzzle->getConfig('base_uri'); + } else { + $endpoint = $guzzle->getBaseUrl(); + } + $this->config->setEndpoints((string) $endpoint, null); + } + $this->resolver = $resolver ?: new BasicResolver(); $this->recorder = new Recorder(); $this->pipeline = new Pipeline(); - $this->http = new HttpClient($config, $guzzle ?: static::makeGuzzle()); + $this->http = new HttpClient($config); $this->sessionTracker = new SessionTracker($config); $this->registerMiddleware(new NotificationSkipper($config)); @@ -135,28 +147,8 @@ public function __construct(Configuration $config, ResolverInterface $resolver = public static function makeGuzzle($base = null, array $options = []) { $key = version_compare(ClientInterface::VERSION, '6') === 1 ? 'base_uri' : 'base_url'; - $options[$key] = $base ?: static::ENDPOINT; - - if ($path = static::getCaBundlePath()) { - $options['verify'] = $path; - } - - return new Guzzle($options); - } - - /** - * Get the ca bundle path if one exists. - * - * @return string|false - */ - protected static function getCaBundlePath() - { - if (!class_exists(CaBundle::class)) { - return false; - } - - return realpath(CaBundle::getSystemCaRootBundlePath()); + return Utils::makeGuzzle($options); } /** @@ -784,6 +776,41 @@ public function setAutoCaptureSessions($track) return $this; } + /** + * Sets the notify and session endpoints + * + * @param string $notifyEndpoint the notify endpoint + * @param string $sessionEndpoint the session endpoint + * + * @return $this + */ + public function setEndpoints($notifyEndpoint, $sessionEndpoint) + { + $this->config->setEndpoints($notifyEndpoint, $sessionEndpoint); + + return $this; + } + + /** + * Gets the notify endpoint + * + * @return string + */ + public function getNotifyEndpoint() + { + return $this->config->getNotifyEndpoint(); + } + + /** + * Gets the session endpoint + * + * @return string + */ + public function getSessionEndpoint() + { + return $this->config->getSessionEndpoint(); + } + /** * Set session delivery endpoint. * @@ -808,6 +835,41 @@ public function getSessionClient() return $this->config->getSessionClient(); } + /** + * Gets the current guzzle client. + * + * @return GuzzleHttp\ClientInterface + */ + public function getGuzzleClient() + { + return $this->config->getGuzzleClient(); + } + + /** + * Sets the guzzle client + * + * Delivery URLs should be set using the "setEndpoints" method + * + * @param GuzzleHttp\ClientInterface $guzzleClient the new guzzle client + * + * @return $this + */ + public function setGuzzleClient($guzzleClient) + { + $this->config->setGuzzleClient($guzzleClient); + return $this; + } + + /** + * Whether any sessions are enabled. + * + * @return bool + */ + public function sessionsEnabled() + { + return $this->config->sessionsEnabled(); + } + /** * Whether should be auto-capturing sessions. * diff --git a/src/Configuration.php b/src/Configuration.php index 51201fa8..a7581e5c 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -3,22 +3,30 @@ namespace Bugsnag; use InvalidArgumentException; +use Bugsnag\Utils; class Configuration { /** - * The default endpoint. + * The default notification endpoint. * * @var string */ - const SESSION_ENDPOINT = 'https://sessions.bugsnag.com'; + const DEFAULT_NOTIFY_ENDPOINT = 'https://notify.bugsnag.com'; + + /** + * The default session endpoint. + * + * @var string + */ + const DEFAULT_SESSION_ENDPOINT = 'https://sessions.bugsnag.com'; /** * The default build endpoint. * * @var string */ - const BUILD_ENDPOINT = 'https://build.bugsnag.com'; + const DEFAULT_BUILD_ENDPOINT = 'https://build.bugsnag.com'; /** * The Bugsnag API Key. @@ -116,25 +124,39 @@ class Configuration protected $errorReportingLevel; /** - * Whether to track sessions. + * Whether to track sessions automatically. + * + * @var bool + */ + protected $autoCaptureSessions = true; + + /** + * Whether to allow any sessions to be tracked. * * @var bool */ - protected $autoCaptureSessions = false; + protected $enableSessions = true; /** - * A client to use to send sessions. + * The client for making http requests * - * @var \Guzzle\ClientInterface + * @var GuzzleHttp\ClientInterface|null */ - protected $sessionClient; + protected $guzzleClient = null; + + /** + * The endpoint to deliver notifications to. + * + * @var string + */ + protected $notifyEndpoint = self::DEFAULT_NOTIFY_ENDPOINT; /** * The endpoint to deliver sessions to. * * @var string */ - protected $sessionEndpoint = self::SESSION_ENDPOINT; + protected $sessionEndpoint = self::DEFAULT_SESSION_ENDPOINT; /** * The endpoint to deliver build notifications to. @@ -578,6 +600,75 @@ public function setAutoCaptureSessions($track) return $this; } + /** + * Whether any sessions are enabled. + * + * @return bool + */ + public function sessionsEnabled() + { + if ($this->enableSessions) { + $notifyEndpointSet = $this->notifyEndpoint !== static::DEFAULT_NOTIFY_ENDPOINT; + $sessionEndpointSet = $this->sessionEndpoint !== static::DEFAULT_SESSION_ENDPOINT; + if ($notifyEndpointSet && !$sessionEndpointSet) { + syslog(LOG_WARNING, 'The session endpoint has not been set, all further session capturing will be disabled'); + $this->enableSessions = false; + } elseif (!$notifyEndpointSet && $sessionEndpointSet) { + throw new InvalidArgumentException('The session endpoint cannot be modified without the notify endpoint'); + } + } + return $this->enableSessions; + } + + /** + * Whether should be auto-capturing sessions. + * + * @return bool + */ + public function shouldCaptureSessions() + { + return $this->autoCaptureSessions && $this->sessionsEnabled(); + } + + /** + * Sets the notify and session endpoints + * + * @param string $notifyEndpoint the notify endpoint + * @param string $sessionEndpoint the session endpoint + * + * @return $this + */ + public function setEndpoints($notifyEndpoint, $sessionEndpoint) + { + if ($notifyEndpoint) { + $this->notifyEndpoint = $notifyEndpoint; + } + if ($sessionEndpoint) { + $this->sessionEndpoint = $sessionEndpoint; + } + return $this; + } + + /** + * Gets the notify endpoint + * + * @return string + */ + public function getNotifyEndpoint() + { + return $this->notifyEndpoint; + } + + /** + * Gets the session endpoint + * + * @return string + */ + public function getSessionEndpoint() + { + return $this->sessionEndpoint; + } + /** * Set session delivery endpoint. * @@ -587,9 +678,7 @@ public function setAutoCaptureSessions($track) */ public function setSessionEndpoint($endpoint) { - $this->sessionEndpoint = $endpoint; - - $this->sessionClient = Client::makeGuzzle($this->sessionEndpoint); + $this->setEndpoints(null, $endpoint); return $this; } @@ -601,21 +690,35 @@ public function setSessionEndpoint($endpoint) */ public function getSessionClient() { - if (is_null($this->sessionClient)) { - $this->sessionClient = Client::makeGuzzle($this->sessionEndpoint); - } + return $this->getGuzzleClient(); + } - return $this->sessionClient; + /** + * Sets the guzzle client + * + * Delivery URLs should be set using the "setEndpoints" method + * + * @param GuzzleHttp\ClientInterface $guzzleClient the new guzzle client + * + * @return $this + */ + public function setGuzzleClient($guzzleClient) + { + $this->guzzleClient = $guzzleClient; + return $this; } /** - * Whether should be auto-capturing sessions. + * Gets the current guzzle client, making one if necessary * - * @return bool + * @return GuzzleHttp\ClientInterface */ - public function shouldCaptureSessions() + public function getGuzzleClient() { - return $this->autoCaptureSessions; + if (!$this->guzzleClient) { + $this->guzzleClient = Utils::makeGuzzle(); + } + return $this->guzzleClient; } /** @@ -643,6 +746,6 @@ public function getBuildEndpoint() return $this->buildEndpoint; } - return self::BUILD_ENDPOINT; + return self::DEFAULT_BUILD_ENDPOINT; } } diff --git a/src/HttpClient.php b/src/HttpClient.php index 37a6419c..76f981a4 100644 --- a/src/HttpClient.php +++ b/src/HttpClient.php @@ -15,13 +15,6 @@ class HttpClient */ protected $config; - /** - * The guzzle client instance. - * - * @var \GuzzleHttp\ClientInterface - */ - protected $guzzle; - /** * The queue of reports to send. * @@ -47,14 +40,12 @@ class HttpClient * Create a new http client instance. * * @param \Bugsnag\Configuration $config the configuration instance - * @param \GuzzleHttp\ClientInterface $guzzle the guzzle client instance * * @return void */ - public function __construct(Configuration $config, ClientInterface $guzzle) + public function __construct(Configuration $config) { $this->config = $config; - $this->guzzle = $guzzle; } /** @@ -149,7 +140,9 @@ public function sendBuildReport(array $buildInfo) $endpoint = $this->config->getBuildEndpoint(); - $this->guzzle->post($endpoint, ['json' => $data]); + $guzzleClient = $this->config->getGuzzleClient(); + + $guzzleClient->post($endpoint, ['json' => $data]); } /** @@ -163,7 +156,7 @@ public function send() return; } - $this->postJson('', $this->build()); + $this->postJson($this->config->getNotifyEndpoint(), $this->build()); $this->queue = []; } @@ -236,8 +229,9 @@ protected function postJSON($url, $data) } // Send via guzzle and log any failures + $guzzleClient = $this->config->getGuzzleClient(); try { - $this->guzzle->post($url, [ + $guzzleClient->post($url, [ 'json' => $normalized, 'headers' => $this->getHeaders(), ]); diff --git a/src/SessionTracker.php b/src/SessionTracker.php index 8e3f1238..53617acf 100644 --- a/src/SessionTracker.php +++ b/src/SessionTracker.php @@ -105,13 +105,11 @@ public function __construct(Configuration $config) $this->lastSent = 0; } - public function setConfig(Configuration $config) - { - $this->config = $config; - } - public function startSession() { + if (!$this->config->sessionsEnabled()) { + return; + } $currentTime = strftime('%Y-%m-%dT%H:%M:00'); $session = [ 'id' => uniqid('', true), @@ -285,7 +283,7 @@ protected function deliverSessions() if (count($sessions) == 0) { return; } - $http = $this->config->getSessionClient(); + $guzzle = $this->config->getGuzzleClient(); $payload = $this->constructPayload($sessions); $headers = [ 'Bugsnag-Api-Key' => $this->config->getApiKey(), @@ -295,7 +293,7 @@ protected function deliverSessions() $this->setLastSent(); try { - $http->post('', [ + $guzzle->post($this->config->getSessionEndpoint(), [ 'json' => $payload, 'headers' => $headers, ]); diff --git a/src/Utils.php b/src/Utils.php index 5529061e..88be7296 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -2,6 +2,9 @@ namespace Bugsnag; +use Composer\CaBundle\CaBundle; +use GuzzleHttp\Client as Guzzle; + class Utils { /** @@ -40,4 +43,34 @@ public static function getBuilderName() return $builderName; } + + /** + * Make a new guzzle client instance. + * + * @param array $options + * + * @return \GuzzleHttp\ClientInterface + */ + public static function makeGuzzle(array $options = []) + { + if ($path = static::getCaBundlePath()) { + $options['verify'] = $path; + } + + return new Guzzle($options); + } + + /** + * Get the ca bundle path if one exists. + * + * @return string|false + */ + protected static function getCaBundlePath() + { + if (!class_exists(CaBundle::class)) { + return false; + } + + return realpath(CaBundle::getSystemCaRootBundlePath()); + } } diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 20d396c4..e9eda21e 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -30,7 +30,7 @@ protected function setUp() $this->client = $this->getMockBuilder(Client::class) ->setMethods(['notify']) - ->setConstructorArgs([$this->config = new Configuration('example-api-key'), null, $this->guzzle]) + ->setConstructorArgs([$this->config = new Configuration('example-api-key'), null]) ->getMock(); } @@ -43,13 +43,13 @@ public function testManualErrorNotification() public function testManualErrorNotificationWithSeverity() { - $client = new Client($this->config, null, $this->guzzle); + $client = new Client($this->config, null); $prop = (new ReflectionClass($client))->getProperty('http'); $prop->setAccessible(true); $http = $this->getMockBuilder(HttpClient::class) ->setMethods(['queue']) - ->setConstructorArgs([$this->config, $this->guzzle]) + ->setConstructorArgs([$this->config]) ->getMock(); $prop->setValue($client, $http); @@ -80,26 +80,12 @@ public function testManualExceptionNotificationWithSeverity() }); } - protected function getGuzzle(Client $client) - { - $prop = (new ReflectionClass($client))->getProperty('http'); - $prop->setAccessible(true); - - $http = $prop->getValue($client); - - $prop = (new ReflectionClass($http))->getProperty('guzzle'); - $prop->setAccessible(true); - - return $prop->getValue($http); - } - public function testDefaultSetup() { - if (version_compare(ClientInterface::VERSION, '6') === 1) { - $this->assertEquals(new Uri('https://notify.bugsnag.com'), $this->getGuzzle(Client::make('123'))->getConfig('base_uri')); - } else { - $this->assertSame('https://notify.bugsnag.com', $this->getGuzzle(Client::make('123'))->getBaseUrl()); - } + $client = Client::make('123'); + + $this->assertEquals(Configuration::DEFAULT_NOTIFY_ENDPOINT, $client->getNotifyEndpoint()); + $this->assertEquals(Configuration::DEFAULT_SESSION_ENDPOINT, $client->getSessionEndpoint()); } public function testCanMake() @@ -107,33 +93,51 @@ public function testCanMake() $client = Client::make('123', 'https://example.com'); $this->assertInstanceOf(Client::class, $client); - - if (version_compare(ClientInterface::VERSION, '6') === 1) { - $this->assertEquals(new Uri('https://example.com'), $this->getGuzzle($client)->getConfig('base_uri')); - } else { - $this->assertSame('https://example.com', $this->getGuzzle($client)->getBaseUrl()); - } + $this->assertEquals('https://example.com', $client->getNotifyEndpoint()); } public function testCanMakeFromEnv() { + $endpoint = 'endpoint'; $env = $this->getFunctionMock('Bugsnag', 'getenv'); - $env->expects($this->exactly(2))->will($this->returnValue('http://foo.com')); + $env->expects($this->exactly(3))->will($this->returnValue($endpoint)); $client = Client::make(); $this->assertInstanceOf(Client::class, $client); + $this->assertSame($endpoint, $client->getNotifyEndpoint()); + $this->assertSame($endpoint, $client->getSessionEndpoint()); + } + + public function testCanConstructWithGuzzle() + { + $guzzle = Client::makeGuzzle("https://example.com"); - if (version_compare(ClientInterface::VERSION, '6') === 1) { - $this->assertEquals(new Uri('http://foo.com'), $this->getGuzzle($client)->getConfig('base_uri')); - } else { - $this->assertSame('http://foo.com', $this->getGuzzle($client)->getBaseUrl()); - } + $this->assertSame(Guzzle::class, get_class($guzzle)); + + $client = new Client(new Configuration('123'), null, $guzzle); + + $this->assertSame($guzzle, $client->getGuzzleClient()); + $this->assertEquals('https://example.com', $client->getNotifyEndpoint()); + } + + public function testCanSetEndpointsIndependently() + { + $guzzle = Client::makeGuzzle("https://example.com"); + + $client = new Client(new Configuration('123'), null, $guzzle); + + $client->setSessionEndpoint("https://sessions-example.com"); + + $this->assertEquals('https://example.com', $client->getNotifyEndpoint()); + $this->assertEquals('https://sessions-example.com', $client->getSessionEndpoint()); + $this->assertTrue($client->sessionsEnabled()); } public function testBeforeNotifySkipsError() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->setBatchSending(false); @@ -150,8 +154,8 @@ public function testBeforeNotifySkipsError() public function testBeforeNotifyCanModifyReportFrames() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); - + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->setBatchSending(false); $this->client->notify($report = Report::fromNamedError($this->config, 'Magic', 'oh no')); @@ -172,7 +176,8 @@ public function testBeforeNotifyCanModifyReportFrames() public function testDirectCallbackSkipsError() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->setBatchSending(false); @@ -187,7 +192,8 @@ public function testDirectCallbackSkipsError() public function testMetaDataWorks() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->notify($report = Report::fromNamedError($this->config, 'Name'), function ($report) { $report->setMetaData(['foo' => 'baz']); @@ -198,7 +204,8 @@ public function testMetaDataWorks() public function testCustomMiddlewareWorks() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->registerMiddleware(function ($report, callable $next) { $report->setMetaData(['middleware' => 'registered']); @@ -212,7 +219,8 @@ public function testCustomMiddlewareWorks() public function testMiddlewareCanModifySeverity() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->registerMiddleware(function ($report, callable $next) { $report->setSeverity('info'); @@ -229,7 +237,8 @@ public function testMiddlewareCanModifySeverity() public function testMiddlewareCanModifyUnhandled() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->registerMiddleware(function ($report, callable $next) { $report->setUnhandled(true); @@ -246,7 +255,8 @@ public function testMiddlewareCanModifyUnhandled() public function testMiddlewareCanModifySeverityReason() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->registerMiddleware(function ($report, callable $next) { $report->setSeverityReason([ @@ -267,7 +277,8 @@ public function testMiddlewareCanModifySeverityReason() public function testNotOverriddenByCallbacks() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->registerMiddleware(function ($report, callable $next) { $report->setUnhandled(true); @@ -315,7 +326,8 @@ public function testBreadcrumbsWorks() public function testBreadcrumbsFallback() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->leaveBreadcrumb('Foo Bar Baz', 'bla'); @@ -334,7 +346,8 @@ public function testBreadcrumbsFallback() public function testBreadcrumbsNoName() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); // notify with an empty report name $this->client->notify(Report::fromNamedError($this->config, '')); @@ -355,7 +368,8 @@ public function testBreadcrumbsNoName() public function testBreadcrumbsGetShortNameClass() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->config->setGuzzleClient($this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); $this->client->leaveBreadcrumb(Client::class, 'state'); @@ -374,7 +388,8 @@ public function testBreadcrumbsGetShortNameClass() public function testBreadcrumbsLong() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->leaveBreadcrumb('This error name is far too long to be allowed through.', 'user', ['foo' => 'bar']); @@ -393,7 +408,8 @@ public function testBreadcrumbsLong() public function testBreadcrumbsLarge() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->leaveBreadcrumb('Test', 'user', ['foo' => str_repeat('A', 5000)]); @@ -412,8 +428,9 @@ public function testBreadcrumbsLarge() public function testBreadcrumbsAgain() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->leaveBreadcrumb('Test', 'user', ['foo' => 'bar']); $this->client->notify($report = Report::fromNamedError($this->config, 'Name')); @@ -459,7 +476,8 @@ public function testNoEnvironmentByDefault() { $_ENV['SOMETHING'] = 'blah'; - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->registerDefaultCallbacks(); @@ -472,9 +490,11 @@ public function testBatchingDoesNotFlush() { $this->client = $this->getMockBuilder(Client::class) ->setMethods(['flush']) - ->setConstructorArgs([$this->config, null, $this->guzzle]) + ->setConstructorArgs([$this->config, null]) ->getMock(); + $this->config->setGuzzleClient($this->guzzle); + $this->client->expects($this->never())->method('flush'); $this->client->notify($report = Report::fromNamedError($this->config, 'Name')); @@ -484,9 +504,11 @@ public function testFlushesWhenNotBatching() { $this->client = $this->getMockBuilder(Client::class) ->setMethods(['flush']) - ->setConstructorArgs([$this->config, null, $this->guzzle]) + ->setConstructorArgs([$this->config, null]) ->getMock(); + $this->config->setGuzzleClient($this->guzzle); + $this->client->expects($this->once())->method('flush'); $this->client->setBatchSending(false); @@ -496,7 +518,8 @@ public function testFlushesWhenNotBatching() public function testCanManuallyFlush() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->setBatchSending(false); @@ -512,82 +535,61 @@ public function testCanManuallyFlush() public function testDeployWorksOutOfTheBox() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['releaseStage' => 'production', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); $this->config->setAppVersion('1.3.1'); - - $this->client->deploy(); + $this->client->deploy(); } - - public function testDeployWorksWithReleaseStage() + public function testDeployWorksWithReleaseStage() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['releaseStage' => 'staging', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); $this->config->setAppVersion('1.3.1'); - - $this->config->setReleaseStage('staging'); - - $this->client->deploy(); + $this->config->setReleaseStage('staging'); + $this->client->deploy(); } - - public function testDeployWorksWithAppVersion() + public function testDeployWorksWithAppVersion() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['releaseStage' => 'production', 'appVersion' => '1.1.0', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); $this->config->setAppVersion('1.3.1'); - - $this->client->deploy(); + $this->client->deploy(); } - - public function testDeployWorksWithRepository() + public function testDeployWorksWithRepository() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['sourceControl' => ['repository' => 'foo'], 'releaseStage' => 'production', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); $this->config->setAppVersion('1.3.1'); - - $this->client->deploy('foo'); + $this->client->deploy('foo'); } - - public function testDeployWorksWithBranch() + public function testDeployWorksWithBranch() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['releaseStage' => 'production', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); $this->config->setAppVersion('1.3.1'); - - $this->client->deploy(null, 'master'); + $this->client->deploy(null, 'master'); } - - public function testDeployWorksWithRevision() + public function testDeployWorksWithRevision() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['sourceControl' => ['revision' => 'bar'], 'releaseStage' => 'production', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); $this->config->setAppVersion('1.3.1'); - - $this->client->deploy(null, null, 'bar'); + $this->client->deploy(null, null, 'bar'); } - - public function testDeployWorksWithEverything() + public function testDeployWorksWithEverything() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['sourceControl' => ['repository' => 'baz', 'revision' => 'foo'], 'releaseStage' => 'development', 'appVersion' => '1.3.1', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); - - $this->config->setReleaseStage('development'); + $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->config->setReleaseStage('development'); $this->config->setAppVersion('1.3.1'); - - $this->client->deploy('baz', 'develop', 'foo'); + $this->client->deploy('baz', 'develop', 'foo'); } public function testBuildWorksOutOfTheBox() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['releaseStage' => 'production', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->config->setAppVersion('1.3.1'); $this->client->build(); @@ -597,7 +599,8 @@ public function testBuildWorksWithReleaseStage() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['releaseStage' => 'staging', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->config->setAppVersion('1.3.1'); $this->config->setReleaseStage('staging'); @@ -609,7 +612,8 @@ public function testBuildWorksWithRepository() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['sourceControl' => ['repository' => 'foo'], 'releaseStage' => 'production', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->config->setAppVersion('1.3.1'); $this->client->build('foo'); @@ -619,8 +623,9 @@ public function testBuildWorksWithProvider() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['sourceControl' => ['provider' => 'github'], 'releaseStage' => 'production', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); $this->config->setAppVersion('1.3.1'); + $this->config->setGuzzleClient($this->guzzle); $this->client->build(null, null, 'github'); } @@ -629,8 +634,9 @@ public function testBuildWorksWithRevision() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['sourceControl' => ['revision' => 'bar'], 'releaseStage' => 'production', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); $this->config->setAppVersion('1.3.1'); + $this->config->setGuzzleClient($this->guzzle); $this->client->build(null, 'bar'); } @@ -639,8 +645,9 @@ public function testBuildWorksWithBuilderName() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['builderName' => 'me', 'releaseStage' => 'production', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'appVersion' => '1.3.1']])); - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); $this->config->setAppVersion('1.3.1'); + $this->config->setGuzzleClient($this->guzzle); $this->client->build(null, null, null, 'me'); } @@ -649,8 +656,9 @@ public function testBuildWorksWithBuildTool() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['releaseStage' => 'production', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php', 'builderName' => exec('whoami'), 'appVersion' => '1.3.1']])); - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); $this->config->setAppVersion('1.3.1'); + $this->config->setGuzzleClient($this->guzzle); $this->client->build(null, null, null, null); } @@ -659,7 +667,8 @@ public function testBuildWorksWithEverything() { $this->guzzle->expects($this->once())->method('post')->with($this->equalTo('https://build.bugsnag.com'), $this->equalTo(['json' => ['builderName' => 'me', 'sourceControl' => ['repository' => 'baz', 'revision' => 'foo', 'provider' => 'github'], 'releaseStage' => 'development', 'appVersion' => '1.3.1', 'apiKey' => 'example-api-key', 'buildTool' => 'bugsnag-php']])); - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->config->setReleaseStage('development'); $this->config->setAppVersion('1.3.1'); @@ -669,7 +678,8 @@ public function testBuildWorksWithEverything() public function testBuildFailsWithoutAPIKey() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); // Setup error_log mocking $log = $this->getFunctionMock('Bugsnag', 'error_log'); @@ -680,7 +690,8 @@ public function testBuildFailsWithoutAPIKey() public function testSeverityReasonUnmodified() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->notify($report = Report::fromNamedError($this->config, 'Name')); @@ -691,7 +702,8 @@ public function testSeverityReasonUnmodified() public function testSeverityModifiedByCallback() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $report = Report::fromNamedError($this->config, 'Name'); @@ -707,7 +719,8 @@ public function testSeverityModifiedByCallback() public function testSeverityReasonNotModifiedByCallback() { - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $report = Report::fromNamedError($this->config, 'Name', null, false, ['type' => 'handledError']); @@ -727,7 +740,8 @@ public function testUrlModifiableByCallback() $_SERVER['HTTP_HOST'] = 'test.com'; $_SERVER['REQUEST_URI'] = '/blah/blah.php?user=anon&password=hunter2'; - $this->client = new Client($this->config = new Configuration('example-api-key'), null, $this->guzzle); + $this->client = new Client($this->config = new Configuration('example-api-key'), null); + $this->config->setGuzzleClient($this->guzzle); $this->client->registerDefaultCallbacks(); $report = Report::fromNamedError($this->config, 'Name'); @@ -836,15 +850,8 @@ public function testSessionClient() $this->assertSame($client, $client->setSessionEndpoint('https://example')); $sessionClient = $client->getSessionClient(); $this->assertSame(Guzzle::class, get_class($sessionClient)); - - if (substr(ClientInterface::VERSION, 0, 1) == '5') { - $clientUri = $sessionClient->getBaseUrl(); - } else { - $baseUri = $sessionClient->getConfig('base_uri'); - $clientUri = $baseUri->getScheme().'://'.$baseUri->getHost(); - } - - $this->assertSame('https://example', $clientUri); + $this->assertSame($client->getGuzzleClient(), $sessionClient); + $this->assertSame('https://example', $client->getSessionEndpoint()); } public function testSetAutoCaptureSessions() @@ -899,4 +906,39 @@ public function testNotifier() $this->assertSame($client, $client->setNotifier(['foo' => 'bar'])); $this->assertSame(['foo' => 'bar'], $client->getNotifier()); } + + public function testSetEndpoints() + { + $client = Client::make('foo'); + $this->assertSame(\Bugsnag\Configuration::DEFAULT_NOTIFY_ENDPOINT, $client->getNotifyEndpoint()); + $this->assertSame(\Bugsnag\Configuration::DEFAULT_SESSION_ENDPOINT, $client->getSessionEndpoint()); + + $notify = "notify"; + $session = "session"; + $this->assertSame($client, $client->setEndpoints($notify, $session)); + + $this->assertSame($notify, $client->getNotifyEndpoint()); + $this->assertSame($session, $client->getSessionEndpoint()); + } + + public function testSessionsEnabled() + { + $client = Client::make('foo'); + $this->assertTrue($client->sessionsEnabled()); + + $client->setEndpoints("notify", null); + + $this->assertFalse($client->sessionsEnabled()); + $this->assertFalse($client->shouldCaptureSessions()); + } + + public function testSetGuzzleClient() + { + $client = Client::make('foo'); + $this->assertInstanceOf(Guzzle::class, $client->getGuzzleClient()); + + $guzzle = new Guzzle(); + $this->assertSame($client, $client->setGuzzleClient($guzzle)); + $this->assertSame($guzzle, $client->getGuzzleClient()); + } } diff --git a/tests/ConfigurationTest.php b/tests/ConfigurationTest.php index 90d9ce11..314cc718 100644 --- a/tests/ConfigurationTest.php +++ b/tests/ConfigurationTest.php @@ -5,10 +5,14 @@ use Bugsnag\Configuration; use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\ClientInterface; +use phpmock\phpunit\PHPMock; use PHPUnit_Framework_TestCase as TestCase; class ConfigurationTest extends TestCase { + + use PHPMock; + protected $config; protected function setUp() @@ -227,54 +231,93 @@ public function testDeviceData() public function testSessionTrackingDefaults() { - $this->assertFalse($this->config->shouldCaptureSessions()); + $this->assertTrue($this->config->shouldCaptureSessions()); + $this->assertTrue($this->config->sessionsEnabled()); } - public function testSessionTrackingSetTrue() + public function testSessionTrackingSetFalse() { + $this->assertTrue($this->config->shouldCaptureSessions()); + + $this->config->setAutoCaptureSessions(false); + $this->assertFalse($this->config->shouldCaptureSessions()); + } - $this->config->setAutoCaptureSessions(true); + public function testSessionTrackingSetEndpoint() + { + $testUrl = 'https://testurl.com'; + $this->config->setSessionEndpoint($testUrl); - $this->assertTrue($this->config->shouldCaptureSessions()); + $this->assertSame($testUrl, $this->config->getSessionEndpoint()); + } - $client = $this->config->getSessionClient(); + public function testEndpointDefaults() + { + $this->assertSame(\Bugsnag\Configuration::DEFAULT_NOTIFY_ENDPOINT, $this->config->getNotifyEndpoint()); + $this->assertSame(\Bugsnag\Configuration::DEFAULT_SESSION_ENDPOINT, $this->config->getSessionEndpoint()); + $this->assertSame(\Bugsnag\Configuration::DEFAULT_BUILD_ENDPOINT, $this->config->getBuildEndpoint()); + } - $this->assertSame(GuzzleClient::class, get_class($client)); + public function testSetEndpointsBothValid() + { + $notifyUrl = 'notify'; + $sessionUrl = 'session'; - if (substr(ClientInterface::VERSION, 0, 1) == '5') { - $clientUri = $client->getBaseUrl(); - } else { - $baseUri = $client->getConfig('base_uri'); - $clientUri = $baseUri->getScheme().'://'.$baseUri->getHost(); - } + $this->config->setEndpoints($notifyUrl, $sessionUrl); - $this->assertSame(Configuration::SESSION_ENDPOINT, $clientUri); + $this->assertSame($notifyUrl, $this->config->getNotifyEndpoint()); + $this->assertSame($sessionUrl, $this->config->getSessionEndpoint()); } - public function testSessionTrackingSetEndpoint() + public function testSetEndpointsNoChange() { - $testUrl = 'https://testurl.com'; + // If this throws or logs, something has gone wrong + $this->config->setEndpoints(null, null); - $this->assertFalse($this->config->shouldCaptureSessions()); + $this->assertSame(\Bugsnag\Configuration::DEFAULT_NOTIFY_ENDPOINT, $this->config->getNotifyEndpoint()); + $this->assertSame(\Bugsnag\Configuration::DEFAULT_SESSION_ENDPOINT, $this->config->getSessionEndpoint()); + } - $this->config->setAutoCaptureSessions(true); + public function testSetEndpointsNotifyNotSession() + { + $notifyUrl = 'notify'; - $this->assertTrue($this->config->shouldCaptureSessions()); + $env = $this->getFunctionMock('Bugsnag', 'syslog'); + $env->expects($this->once())->with(LOG_WARNING, 'The session endpoint has not been set, all further session capturing will be disabled'); - $this->config->setSessionEndpoint($testUrl); + $this->config->setEndpoints($notifyUrl, null); + + $this->assertSame($notifyUrl, $this->config->getNotifyEndpoint()); + $this->assertSame(\Bugsnag\Configuration::DEFAULT_SESSION_ENDPOINT, $this->config->getSessionEndpoint()); + $this->assertFalse($this->config->sessionsEnabled()); + $this->assertFalse($this->config->shouldCaptureSessions()); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The session endpoint cannot be modified without the notify endpoint + */ + public function testSetEndpointsSessionNotNotify() + { + $sessionUrl = 'session'; - $client = $this->config->getSessionClient(); + $this->config->setEndpoints(null, $sessionUrl); + $this->config->sessionsEnabled(); + } - $this->assertSame(GuzzleClient::class, get_class($client)); + public function testSetGuzzleClient() + { + $guzzleClient = new GuzzleClient(); - if (substr(ClientInterface::VERSION, 0, 1) == '5') { - $clientUri = $client->getBaseUrl(); - } else { - $baseUri = $client->getConfig('base_uri'); - $clientUri = $baseUri->getScheme().'://'.$baseUri->getHost(); - } + $this->config->setGuzzleClient($guzzleClient); + $this->assertSame($guzzleClient, $this->config->getGuzzleClient()); + } - $this->assertSame($testUrl, $clientUri); + public function testGetGuzzleClientCreation() + { + $guzzle = $this->config->getGuzzleClient(); + $this->assertInstanceOf(GuzzleClient::class, $guzzle); } + } diff --git a/tests/HttpClientTest.php b/tests/HttpClientTest.php index 7854ba0e..fb6174a0 100644 --- a/tests/HttpClientTest.php +++ b/tests/HttpClientTest.php @@ -20,13 +20,13 @@ class HttpClientTest extends TestCase protected function setUp() { - $this->config = new Configuration('6015a72ff14038114c3d12623dfb018f'); - $this->guzzle = $this->getMockBuilder(Client::class) ->setMethods(['post']) ->getMock(); + $this->config = new Configuration('6015a72ff14038114c3d12623dfb018f'); + $this->config->setGuzzleClient($this->guzzle); - $this->http = new HttpClient($this->config, $this->guzzle); + $this->http = new HttpClient($this->config); } public function testHttpClient() @@ -41,7 +41,7 @@ public function testHttpClient() $this->assertCount(1, $invocations = $spy->getInvocations()); $params = $invocations[0]->parameters; $this->assertCount(2, $params); - $this->assertSame('', $params[0]); + $this->assertSame(\Bugsnag\Configuration::DEFAULT_NOTIFY_ENDPOINT, $params[0]); $this->assertInternalType('array', $params[1]); $this->assertInternalType('array', $params[1]['json']['notifier']); $this->assertInternalType('array', $params[1]['json']['events']); @@ -56,6 +56,25 @@ public function testHttpClient() $this->assertSame('4.0', $headers['Bugsnag-Payload-Version']); } + public function testHttpClientUsesConfigSettings() + { + $config = $this->getMockBuilder(Configuration::class) + ->disableOriginalConstructor() + ->setMethods(['getNotifyEndpoint', 'getGuzzleClient']) + ->getMock(); + + // Expect Client to get the guzzleClient and endpoint from Config + $config->expects($this->once())->method('getGuzzleClient')->willReturn($this->guzzle); + $config->expects($this->once())->method('getNotifyEndpoint')->willReturn('foo'); + + // Expect post to be called + $this->guzzle->expects($this->any())->method('post'); + + $http = new HttpClient($config); + $http->queue(Report::fromNamedError($this->config, 'Name')); + $http->send(); + } + public function testHttpClientMultipleSend() { // Expect request to be called @@ -85,7 +104,7 @@ public function testMassiveMetaDataHttpClient() $this->assertCount(1, $invocations = $spy->getInvocations()); $params = $invocations[0]->parameters; $this->assertCount(2, $params); - $this->assertSame('', $params[0]); + $this->assertSame(\Bugsnag\Configuration::DEFAULT_NOTIFY_ENDPOINT, $params[0]); $this->assertInternalType('array', $params[1]); $this->assertInternalType('array', $params[1]['json']['notifier']); $this->assertInternalType('array', $params[1]['json']['events']); @@ -133,7 +152,7 @@ public function testPartialHttpClient() $this->assertCount(1, $invocations = $spy->getInvocations()); $params = $invocations[0]->parameters; $this->assertCount(2, $params); - $this->assertSame('', $params[0]); + $this->assertSame(\Bugsnag\Configuration::DEFAULT_NOTIFY_ENDPOINT, $params[0]); $this->assertInternalType('array', $params[1]); $this->assertInternalType('array', $params[1]['json']['notifier']); $this->assertInternalType('array', $params[1]['json']['events']);