diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fec2798df..ef11da538 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -48,6 +48,27 @@ jobs: command: composer update --prefer-lowest - name: Run Script run: vendor/bin/phpunit + guzzle6: + runs-on: ubuntu-latest + strategy: + matrix: + operating-system: [ ubuntu-latest ] + php: [ "5.6", "7.2" ] + name: PHP ${{ matrix.php }} Unit Test Guzzle 6 + steps: + - uses: actions/checkout@v2 + - name: Setup PHP + uses: nanasess/setup-php@v3.0.4 + with: + php-version: ${{ matrix.php }} + - name: Install Dependencies + uses: nick-invision/retry@v1 + with: + timeout_minutes: 10 + max_attempts: 3 + command: composer require guzzlehttp/guzzle:^6 && composer update + - name: Run Script + run: vendor/bin/phpunit # use dockerfiles for oooooolllllldddd versions of php, setup-php times out for those. test_php55: name: "PHP 5.5 Unit Test" diff --git a/composer.json b/composer.json index b6bbe384b..ca22fa795 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "require": { "php": ">=5.4", "firebase/php-jwt": "~2.0|~3.0|~4.0|~5.0", - "guzzlehttp/guzzle": "~5.3.1|~6.0", + "guzzlehttp/guzzle": "^5.3.1|^6.2.1|^7.0", "guzzlehttp/psr7": "^1.2", "psr/http-message": "^1.0", "psr/cache": "^1.0" diff --git a/src/CredentialsLoader.php b/src/CredentialsLoader.php index fdc7d9432..7cc5aa9e3 100644 --- a/src/CredentialsLoader.php +++ b/src/CredentialsLoader.php @@ -20,6 +20,7 @@ use Google\Auth\Credentials\InsecureCredentials; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\Credentials\UserRefreshCredentials; +use GuzzleHttp\ClientInterface; /** * CredentialsLoader contains the behaviour used to locate and find default @@ -54,6 +55,24 @@ private static function isOnWindows() return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; } + /** + * Returns the currently available major Guzzle version. + * + * @return int + */ + private static function getGuzzleMajorVersion() + { + if (defined('GuzzleHttp\ClientInterface::MAJOR_VERSION')) { + return ClientInterface::MAJOR_VERSION; + } + + if (defined('GuzzleHttp\ClientInterface::VERSION')) { + return (int) substr(ClientInterface::VERSION, 0, 1); + } + + throw new \Exception('Version not supported'); + } + /** * Load a JSON key from the path specified in the environment. * @@ -145,35 +164,30 @@ public static function makeHttpClient( callable $httpHandler = null, callable $tokenCallback = null ) { - $version = \GuzzleHttp\ClientInterface::VERSION; - - switch ($version[0]) { - case '5': - $client = new \GuzzleHttp\Client($httpClientOptions); - $client->setDefaultOption('auth', 'google_auth'); - $subscriber = new Subscriber\AuthTokenSubscriber( - $fetcher, - $httpHandler, - $tokenCallback - ); - $client->getEmitter()->attach($subscriber); - return $client; - case '6': - $middleware = new Middleware\AuthTokenMiddleware( - $fetcher, - $httpHandler, - $tokenCallback - ); - $stack = \GuzzleHttp\HandlerStack::create(); - $stack->push($middleware); - - return new \GuzzleHttp\Client([ - 'handler' => $stack, - 'auth' => 'google_auth', - ] + $httpClientOptions); - default: - throw new \Exception('Version not supported'); + if (self::getGuzzleMajorVersion() === 5) { + $client = new \GuzzleHttp\Client($httpClientOptions); + $client->setDefaultOption('auth', 'google_auth'); + $subscriber = new Subscriber\AuthTokenSubscriber( + $fetcher, + $httpHandler, + $tokenCallback + ); + $client->getEmitter()->attach($subscriber); + return $client; } + + $middleware = new Middleware\AuthTokenMiddleware( + $fetcher, + $httpHandler, + $tokenCallback + ); + $stack = \GuzzleHttp\HandlerStack::create(); + $stack->push($middleware); + + return new \GuzzleHttp\Client([ + 'handler' => $stack, + 'auth' => 'google_auth', + ] + $httpClientOptions); } /** diff --git a/src/HttpHandler/Guzzle6HttpHandler.php b/src/HttpHandler/Guzzle6HttpHandler.php index ecf78e078..aaa7b4385 100644 --- a/src/HttpHandler/Guzzle6HttpHandler.php +++ b/src/HttpHandler/Guzzle6HttpHandler.php @@ -1,5 +1,19 @@ getGuzzleMajorVersion() !== 5) { + $this->markTestSkipped('Guzzle 5 only'); + } + } + + protected function onlyGuzzle6() + { + if ($this->getGuzzleMajorVersion() !== 6) { $this->markTestSkipped('Guzzle 6 only'); } } - public function onlyGuzzle5() + protected function onlyGuzzle6And7() { - $version = ClientInterface::VERSION; - if ('5' !== $version[0]) { - $this->markTestSkipped('Guzzle 5 only'); + if (!in_array($this->getGuzzleMajorVersion(), [6, 7])) { + $this->markTestSkipped('Guzzle 6 and 7 only'); } } + protected function onlyGuzzle7() + { + if ($this->getGuzzleMajorVersion() !== 7) { + $this->markTestSkipped('Guzzle 7 only'); + } + } + + protected function getGuzzleMajorVersion() + { + if (defined('GuzzleHttp\ClientInterface::MAJOR_VERSION')) { + return ClientInterface::MAJOR_VERSION; + } + + if (defined('GuzzleHttp\ClientInterface::VERSION')) { + return (int) substr(ClientInterface::VERSION, 0, 1); + } + + $this->fail('Unable to determine the currently used Guzzle Version'); + } + /** * @see Google\Auth\$this->getValidKeyName */ diff --git a/tests/Credentials/GCECredentialsTest.php b/tests/Credentials/GCECredentialsTest.php index 358ca4ab6..144382da5 100644 --- a/tests/Credentials/GCECredentialsTest.php +++ b/tests/Credentials/GCECredentialsTest.php @@ -19,16 +19,15 @@ use Google\Auth\Credentials\GCECredentials; use Google\Auth\HttpHandler\HttpClientCache; -use GuzzleHttp\ClientInterface; +use Google\Auth\Tests\BaseTest; use GuzzleHttp\Psr7; -use PHPUnit\Framework\TestCase; use Prophecy\Argument; /** * @group credentials * @group credentials-gce */ -class GCECredentialsTest extends TestCase +class GCECredentialsTest extends BaseTest { public function testOnGceMetadataFlavorHeader() { @@ -182,10 +181,7 @@ public function testSettingBothScopeAndTargetAudienceThrowsException() */ public function testFetchAuthTokenCustomScope($scope, $expected) { - $guzzleVersion = ClientInterface::VERSION; - if ($guzzleVersion[0] === '5') { - $this->markTestSkipped('Only compatible with guzzle 6+'); - } + $this->onlyGuzzle6And7(); $uri = null; $client = $this->prophesize('GuzzleHttp\ClientInterface'); @@ -258,10 +254,7 @@ public function testGetClientNameShouldBeEmptyIfNotOnGCE() public function testSignBlob() { - $guzzleVersion = ClientInterface::VERSION; - if ($guzzleVersion[0] === '5') { - $this->markTestSkipped('Only compatible with guzzle 6+'); - } + $this->onlyGuzzle6And7(); $expectedEmail = 'test@test.com'; $expectedAccessToken = 'token'; @@ -294,10 +287,7 @@ public function testSignBlob() public function testSignBlobWithLastReceivedAccessToken() { - $guzzleVersion = ClientInterface::VERSION; - if ($guzzleVersion[0] === '5') { - $this->markTestSkipped('Only compatible with guzzle 6+'); - } + $this->onlyGuzzle6And7(); $expectedEmail = 'test@test.com'; $expectedAccessToken = 'token'; @@ -340,10 +330,7 @@ public function testSignBlobWithLastReceivedAccessToken() public function testGetProjectId() { - $guzzleVersion = ClientInterface::VERSION; - if ($guzzleVersion[0] === '5') { - $this->markTestSkipped('Only compatible with guzzle 6+'); - } + $this->onlyGuzzle6And7(); $expected = 'foobar'; @@ -366,10 +353,7 @@ public function testGetProjectId() public function testGetProjectIdShouldBeEmptyIfNotOnGCE() { - $guzzleVersion = ClientInterface::VERSION; - if ($guzzleVersion[0] === '5') { - $this->markTestSkipped('Only compatible with guzzle 6+'); - } + $this->onlyGuzzle6And7(); // simulate retry attempts by returning multiple 500s $client = $this->prophesize('GuzzleHttp\ClientInterface'); diff --git a/tests/FetchAuthTokenTest.php b/tests/FetchAuthTokenTest.php index aa6182cc1..dcd983a98 100644 --- a/tests/FetchAuthTokenTest.php +++ b/tests/FetchAuthTokenTest.php @@ -61,14 +61,21 @@ class_implements($fetcherClass) $this->assertEquals('xyz', $accessToken); }; - $client = CredentialsLoader::makeHttpClient( - $mockFetcher->reveal(), - [ + if ($this->getGuzzleMajorVersion() === 5) { + $clientOptions = [ 'base_url' => 'https://www.googleapis.com/books/v1/', + 'defaults' => ['exceptions' => false], + ]; + } else { + $clientOptions = [ 'base_uri' => 'https://www.googleapis.com/books/v1/', - 'exceptions' => false, - 'defaults' => ['exceptions' => false] - ], + 'http_errors' => false, + ]; + } + + $client = CredentialsLoader::makeHttpClient( + $mockFetcher->reveal(), + $clientOptions, $httpHandler, $tokenCallback ); diff --git a/tests/HttpHandler/Guzzle6HttpHandlerTest.php b/tests/HttpHandler/Guzzle6HttpHandlerTest.php index 3f46bb433..b86d94d68 100644 --- a/tests/HttpHandler/Guzzle6HttpHandlerTest.php +++ b/tests/HttpHandler/Guzzle6HttpHandlerTest.php @@ -19,45 +19,50 @@ use Google\Auth\HttpHandler\Guzzle6HttpHandler; use Google\Auth\Tests\BaseTest; -use GuzzleHttp\Promise\Promise; +use GuzzleHttp\Promise\FulfilledPromise; +use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Response; -use Prophecy\Argument; /** * @group http-handler */ class Guzzle6HttpHandlerTest extends BaseTest { + protected $client; + protected $handler; + public function setUp() { $this->onlyGuzzle6(); - $this->mockRequest = $this->prophesize('Psr\Http\Message\RequestInterface'); - $this->mockClient = $this->prophesize('GuzzleHttp\Client'); + $this->client = $this->prophesize('GuzzleHttp\ClientInterface'); + $this->handler = new Guzzle6HttpHandler($this->client->reveal()); } public function testSuccessfullySendsRequest() { - $this->mockClient->send(Argument::type('Psr\Http\Message\RequestInterface'), []) - ->willReturn(new Response(200)); + $request = new Request('GET', 'https://domain.tld'); + $options = ['key' => 'value']; + $response = new Response(200); + + $this->client->send($request, $options)->willReturn($response); + + $handler = $this->handler; - $handler = new Guzzle6HttpHandler($this->mockClient->reveal()); - $response = $handler($this->mockRequest->reveal()); - $this->assertInstanceOf('Psr\Http\Message\ResponseInterface', $response); + $this->assertSame($response, $handler($request, $options)); } public function testSuccessfullySendsRequestAsync() { - $this->mockClient->sendAsync(Argument::type('Psr\Http\Message\RequestInterface'), []) - ->willReturn(new Promise(function () use (&$promise) { - return $promise->resolve(new Response(200, [], 'Body Text')); - })); - - $handler = new Guzzle6HttpHandler($this->mockClient->reveal()); - $promise = $handler->async($this->mockRequest->reveal()); - $response = $promise->wait(); - $this->assertInstanceOf('Psr\Http\Message\ResponseInterface', $response); - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals('Body Text', (string) $response->getBody()); + $request = new Request('GET', 'https://domain.tld'); + $options = ['key' => 'value']; + $response = new Response(200); + $promise = new FulfilledPromise($response); + + $this->client->sendAsync($request, $options)->willReturn($promise); + + $handler = $this->handler; + + $this->assertSame($response, $handler->async($request, $options)->wait()); } } diff --git a/tests/HttpHandler/Guzzle7HttpHandlerTest.php b/tests/HttpHandler/Guzzle7HttpHandlerTest.php new file mode 100644 index 000000000..f6eaa6360 --- /dev/null +++ b/tests/HttpHandler/Guzzle7HttpHandlerTest.php @@ -0,0 +1,34 @@ +onlyGuzzle7(); + + $this->client = $this->prophesize('GuzzleHttp\ClientInterface'); + $this->handler = new Guzzle7HttpHandler($this->client->reveal()); + } +} diff --git a/tests/HttpHandler/HttpHandlerFactoryTest.php b/tests/HttpHandler/HttpHandlerFactoryTest.php index c7796241e..f0673f819 100644 --- a/tests/HttpHandler/HttpHandlerFactoryTest.php +++ b/tests/HttpHandler/HttpHandlerFactoryTest.php @@ -40,4 +40,13 @@ public function testBuildsGuzzle6Handler() $handler = HttpHandlerFactory::build(); $this->assertInstanceOf('Google\Auth\HttpHandler\Guzzle6HttpHandler', $handler); } + + public function testBuildsGuzzle7Handler() + { + $this->onlyGuzzle7(); + + HttpClientCache::setHttpClient(null); + $handler = HttpHandlerFactory::build(); + $this->assertInstanceOf('Google\Auth\HttpHandler\Guzzle7HttpHandler', $handler); + } } diff --git a/tests/Middleware/AuthTokenMiddlewareTest.php b/tests/Middleware/AuthTokenMiddlewareTest.php index 7af984ab5..2cb3ee0b1 100644 --- a/tests/Middleware/AuthTokenMiddlewareTest.php +++ b/tests/Middleware/AuthTokenMiddlewareTest.php @@ -33,7 +33,7 @@ class AuthTokenMiddlewareTest extends BaseTest protected function setUp() { - $this->onlyGuzzle6(); + $this->onlyGuzzle6And7(); $this->mockFetcher = $this->prophesize('Google\Auth\FetchAuthTokenInterface'); $this->mockCacheItem = $this->prophesize('Psr\Cache\CacheItemInterface'); diff --git a/tests/Middleware/ScopedAccessTokenMiddlewareTest.php b/tests/Middleware/ScopedAccessTokenMiddlewareTest.php index cc2ca7a6a..174efbf11 100644 --- a/tests/Middleware/ScopedAccessTokenMiddlewareTest.php +++ b/tests/Middleware/ScopedAccessTokenMiddlewareTest.php @@ -33,7 +33,7 @@ class ScopedAccessTokenMiddlewareTest extends BaseTest protected function setUp() { - $this->onlyGuzzle6(); + $this->onlyGuzzle6And7(); $this->mockCacheItem = $this->prophesize('Psr\Cache\CacheItemInterface'); $this->mockCache = $this->prophesize('Psr\Cache\CacheItemPoolInterface'); diff --git a/tests/Middleware/SimpleMiddlewareTest.php b/tests/Middleware/SimpleMiddlewareTest.php index 280bb9f2c..ab34ff739 100644 --- a/tests/Middleware/SimpleMiddlewareTest.php +++ b/tests/Middleware/SimpleMiddlewareTest.php @@ -28,7 +28,7 @@ class SimpleMiddlewareTest extends BaseTest */ protected function setUp() { - $this->onlyGuzzle6(); + $this->onlyGuzzle6And7(); $this->mockRequest = $this->prophesize('GuzzleHttp\Psr7\Request'); }