origMaxNetworkRetries = \Telnyx\Telnyx::getMaxNetworkRetries(); $this->origMaxNetworkRetryDelay = \Telnyx\Telnyx::getMaxNetworkRetryDelay(); $this->origInitialNetworkRetryDelay = \Telnyx\Telnyx::getInitialNetworkRetryDelay(); } /** * @before */ public function setUpReflectors() { $telnyxReflector = new \ReflectionClass('\Telnyx\Telnyx'); $this->maxNetworkRetryDelayProperty = $telnyxReflector->getProperty('maxNetworkRetryDelay'); $this->maxNetworkRetryDelayProperty->setAccessible(true); $this->initialNetworkRetryDelayProperty = $telnyxReflector->getProperty('initialNetworkRetryDelay'); $this->initialNetworkRetryDelayProperty->setAccessible(true); $curlClientReflector = new \ReflectionClass('\Telnyx\HttpClient\CurlClient'); $this->shouldRetryMethod = $curlClientReflector->getMethod('shouldRetry'); $this->shouldRetryMethod->setAccessible(true); $this->sleepTimeMethod = $curlClientReflector->getMethod('sleepTime'); $this->sleepTimeMethod->setAccessible(true); } /** * @after */ public function restoreOriginalNetworkValues() { \Telnyx\Telnyx::setMaxNetworkRetries($this->origMaxNetworkRetries); $this->setMaxNetworkRetryDelay($this->origMaxNetworkRetryDelay); $this->setInitialNetworkRetryDelay($this->origInitialNetworkRetryDelay); } private function setMaxNetworkRetryDelay($maxNetworkRetryDelay) { $this->maxNetworkRetryDelayProperty->setValue(null, $maxNetworkRetryDelay); } private function setInitialNetworkRetryDelay($initialNetworkRetryDelay) { $this->initialNetworkRetryDelayProperty->setValue(null, $initialNetworkRetryDelay); } private function createFakeRandomGenerator($returnValue = 1.0) { $fakeRandomGenerator = $this->createMock('\Telnyx\Util\RandomGenerator'); $fakeRandomGenerator->method('randFloat')->willReturn($returnValue); return $fakeRandomGenerator; } public function testTimeout() { $curl = new CurlClient(); static::assertSame(CurlClient::DEFAULT_TIMEOUT, $curl->getTimeout()); static::assertSame(CurlClient::DEFAULT_CONNECT_TIMEOUT, $curl->getConnectTimeout()); // implicitly tests whether we're returning the CurlClient instance $curl = $curl->setConnectTimeout(1)->setTimeout(10); static::assertSame(1, $curl->getConnectTimeout()); static::assertSame(10, $curl->getTimeout()); $curl->setTimeout(-1); $curl->setConnectTimeout(-999); static::assertSame(0, $curl->getTimeout()); static::assertSame(0, $curl->getConnectTimeout()); } public function testUserAgentInfo() { $curl = new CurlClient(); $uaInfo = $curl->getUserAgentInfo(); static::assertNotNull($uaInfo); static::assertNotNull($uaInfo['httplib']); static::assertNotNull($uaInfo['ssllib']); } public function testDefaultOptions() { // make sure options array loads/saves properly $optionsArray = [\CURLOPT_PROXY => 'localhost:80']; $withOptionsArray = new CurlClient($optionsArray); static::assertSame($withOptionsArray->getDefaultOptions(), $optionsArray); // make sure closure-based options work properly, including argument passing $ref = null; $withClosure = new CurlClient(function ($method, $absUrl, $headers, $params, $hasFile) use (&$ref) { $ref = \func_get_args(); return []; }); $withClosure->request('get', 'https://httpbin.org/status/200', [], [], false); static::assertSame($ref, ['get', 'https://httpbin.org/status/200', [], [], false]); // this is the last test case that will run, since it'll throw an exception at the end $withBadClosure = new CurlClient(function () { return 'thisShouldNotWork'; }); $this->expectException('Telnyx\Exception\UnexpectedValueException'); $this->expectExceptionMessage('Non-array value returned by defaultOptions CurlClient callback'); $withBadClosure->request('get', 'https://httpbin.org/status/200', [], [], false); } public function testSslOption() { // make sure options array loads/saves properly $optionsArray = [\CURLOPT_SSLVERSION => \CURL_SSLVERSION_TLSv1]; $withOptionsArray = new CurlClient($optionsArray); static::assertSame($withOptionsArray->getDefaultOptions(), $optionsArray); } public function testShouldRetryOnTimeout() { \Telnyx\Telnyx::setMaxNetworkRetries(2); $curlClient = new CurlClient(); static::assertTrue($this->shouldRetryMethod->invoke($curlClient, \CURLE_OPERATION_TIMEOUTED, 0, [], 0)); } public function testShouldRetryOnConnectionFailure() { \Telnyx\Telnyx::setMaxNetworkRetries(2); $curlClient = new CurlClient(); static::assertTrue($this->shouldRetryMethod->invoke($curlClient, \CURLE_COULDNT_CONNECT, 0, [], 0)); } public function testShouldRetryOnConflict() { \Telnyx\Telnyx::setMaxNetworkRetries(2); $curlClient = new CurlClient(); static::assertTrue($this->shouldRetryMethod->invoke($curlClient, 0, 409, [], 0)); } public function testShouldNotRetryOn429() { \Telnyx\Telnyx::setMaxNetworkRetries(2); $curlClient = new CurlClient(); static::assertFalse($this->shouldRetryMethod->invoke($curlClient, 0, 429, [], 0)); } public function testShouldRetryOn500() { \Telnyx\Telnyx::setMaxNetworkRetries(2); $curlClient = new CurlClient(); static::assertTrue($this->shouldRetryMethod->invoke($curlClient, 0, 500, [], 0)); } public function testShouldRetryOn503() { \Telnyx\Telnyx::setMaxNetworkRetries(2); $curlClient = new CurlClient(); static::assertTrue($this->shouldRetryMethod->invoke($curlClient, 0, 503, [], 0)); } public function testShouldRetryOnStripeShouldRetryTrue() { \Telnyx\Telnyx::setMaxNetworkRetries(2); $curlClient = new CurlClient(); static::assertFalse($this->shouldRetryMethod->invoke($curlClient, 0, 400, [], 0)); static::assertTrue($this->shouldRetryMethod->invoke($curlClient, 0, 400, ['telnyx-should-retry' => 'true'], 0)); } public function testShouldNotRetryOnStripeShouldRetryFalse() { \Telnyx\Telnyx::setMaxNetworkRetries(2); $curlClient = new CurlClient(); static::assertTrue($this->shouldRetryMethod->invoke($curlClient, 0, 500, [], 0)); static::assertFalse($this->shouldRetryMethod->invoke($curlClient, 0, 500, ['telnyx-should-retry' => 'false'], 0)); } public function testShouldNotRetryAtMaximumCount() { \Telnyx\Telnyx::setMaxNetworkRetries(2); $curlClient = new CurlClient(); static::assertFalse($this->shouldRetryMethod->invoke($curlClient, 0, 0, [], \Telnyx\Telnyx::getMaxNetworkRetries())); } public function testShouldNotRetryOnCertValidationError() { \Telnyx\Telnyx::setMaxNetworkRetries(2); $curlClient = new CurlClient(); static::assertFalse($this->shouldRetryMethod->invoke($curlClient, \CURLE_SSL_PEER_CERTIFICATE, -1, [], 0)); } public function testSleepTimeShouldGrowExponentially() { $this->setMaxNetworkRetryDelay(999.0); $curlClient = new CurlClient(null, $this->createFakeRandomGenerator()); static::assertSame( \Telnyx\Telnyx::getInitialNetworkRetryDelay() * 1, $this->sleepTimeMethod->invoke($curlClient, 1, []) ); static::assertSame( \Telnyx\Telnyx::getInitialNetworkRetryDelay() * 2, $this->sleepTimeMethod->invoke($curlClient, 2, []) ); static::assertSame( \Telnyx\Telnyx::getInitialNetworkRetryDelay() * 4, $this->sleepTimeMethod->invoke($curlClient, 3, []) ); static::assertSame( \Telnyx\Telnyx::getInitialNetworkRetryDelay() * 8, $this->sleepTimeMethod->invoke($curlClient, 4, []) ); } public function testSleepTimeShouldEnforceMaxNetworkRetryDelay() { $this->setInitialNetworkRetryDelay(1.0); $this->setMaxNetworkRetryDelay(2); $curlClient = new CurlClient(null, $this->createFakeRandomGenerator()); static::assertSame(1.0, $this->sleepTimeMethod->invoke($curlClient, 1, [])); static::assertSame(2.0, $this->sleepTimeMethod->invoke($curlClient, 2, [])); static::assertSame(2.0, $this->sleepTimeMethod->invoke($curlClient, 3, [])); static::assertSame(2.0, $this->sleepTimeMethod->invoke($curlClient, 4, [])); } public function testSleepTimeShouldRespectRetryAfter() { $this->setInitialNetworkRetryDelay(1.0); $this->setMaxNetworkRetryDelay(2.0); $curlClient = new CurlClient(null, $this->createFakeRandomGenerator()); // Uses max of default and header. static::assertSame(10.0, $this->sleepTimeMethod->invoke($curlClient, 1, ['retry-after' => '10'])); static::assertSame(2.0, $this->sleepTimeMethod->invoke($curlClient, 2, ['retry-after' => '1'])); // Ignores excessively large values. static::assertSame(2.0, $this->sleepTimeMethod->invoke($curlClient, 2, ['retry-after' => '100'])); } public function testSleepTimeShouldAddSomeRandomness() { $randomValue = 0.8; $this->setInitialNetworkRetryDelay(1.0); $this->setMaxNetworkRetryDelay(8.0); $curlClient = new CurlClient(null, $this->createFakeRandomGenerator($randomValue)); $baseValue = \Telnyx\Telnyx::getInitialNetworkRetryDelay() * (0.5 * (1 + $randomValue)); // the initial value cannot be smaller than the base, // so the randomness is ignored static::assertSame(\Telnyx\Telnyx::getInitialNetworkRetryDelay(), $this->sleepTimeMethod->invoke($curlClient, 1, [])); // after the first one, the randomness is applied static::assertSame($baseValue * 2, $this->sleepTimeMethod->invoke($curlClient, 2, [])); static::assertSame($baseValue * 4, $this->sleepTimeMethod->invoke($curlClient, 3, [])); static::assertSame($baseValue * 8, $this->sleepTimeMethod->invoke($curlClient, 4, [])); } public function testResponseHeadersCaseInsensitive() { $profiles = \Telnyx\MessagingProfile::all(); $headers = $profiles->getLastResponse()->headers; static::assertNotNull($headers['request-id']); static::assertSame($headers['request-id'], $headers['Request-Id']); } public function testSetRequestStatusCallback() { try { $called = false; $curl = new CurlClient(); $curl->setRequestStatusCallback(function ($rbody, $rcode, $rheaders, $errno, $message, $willBeRetried, $numRetries) use (&$called) { $called = true; $this->assertInternalType('string', $rbody); $this->assertSame(200, $rcode); $this->assertSame(0, $errno); $this->assertNull($message); $this->assertFalse($willBeRetried); $this->assertSame(0, $numRetries); }); \Telnyx\ApiRequestor::setHttpClient($curl); \Telnyx\MessagingProfile::all(); static::assertTrue($called); } finally { \Telnyx\ApiRequestor::setHttpClient(null); } } public function testInvalidMethod() { $curl = new CurlClient(); $this->expectException('Telnyx\Exception\UnexpectedValueException'); $this->expectExceptionMessage('Unrecognized method invalidmethod'); $curl->request('invalidmethod', 'https://httpbin.org/status/200', [], [], false); } public function testGetSets() { $curl = new CurlClient(); $curl->setEnablePersistentConnections(false); static::assertSame(false, $curl->getEnablePersistentConnections()); $curl->setEnablePersistentConnections(true); static::assertSame(true, $curl->getEnablePersistentConnections()); $curl->setEnableHttp2(false); static::assertSame(false, $curl->getEnableHttp2()); $curl->setEnableHttp2(true); static::assertSame(true, $curl->getEnableHttp2()); } }