143 lines
4.6 KiB
PHP
143 lines
4.6 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\MyEp\Api;
|
|
|
|
use App\MyEp\Api\AccessTokenProvider;
|
|
use App\MyEp\Api\ApiException;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Cache\CacheItemPoolInterface;
|
|
use Psr\Log\NullLogger;
|
|
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
|
use Symfony\Component\HttpClient\MockHttpClient;
|
|
use Symfony\Component\HttpClient\Response\MockResponse;
|
|
|
|
class AccessTokenProviderTest extends TestCase
|
|
{
|
|
private const CACHE_KEY = 'myep.api.access_token';
|
|
|
|
public function testTokenIsReturnedFromTheTokenEndpoint(): void
|
|
{
|
|
$httpClient = new MockHttpClient([$this->tokenResponse('abc123')]);
|
|
|
|
$this->assertEquals('abc123', $this->getProviderInstance($httpClient)->getToken());
|
|
}
|
|
|
|
public function testTheClientCredentialsGrantIsRequested(): void
|
|
{
|
|
$body = null;
|
|
$httpClient = new MockHttpClient(function (string $method, string $url, array $options) use (&$body) {
|
|
$this->assertEquals('POST', $method);
|
|
$this->assertEquals('https://myep.example/token', $url);
|
|
$body = $options['body'];
|
|
|
|
return $this->tokenResponse('abc123');
|
|
});
|
|
|
|
$this->getProviderInstance($httpClient)->getToken();
|
|
|
|
$this->assertStringContainsString('grant_type=client_credentials', $body);
|
|
$this->assertStringContainsString('scope=api', $body);
|
|
$this->assertStringContainsString('client_secret=secret', $body);
|
|
}
|
|
|
|
public function testTheTokenIsCachedRatherThanRequestedPerCall(): void
|
|
{
|
|
$httpClient = new MockHttpClient([$this->tokenResponse('abc123')]);
|
|
$cache = new ArrayAdapter();
|
|
$provider = $this->getProviderInstance($httpClient, $cache);
|
|
|
|
$provider->getToken();
|
|
$provider->getToken();
|
|
|
|
$this->assertEquals(1, $httpClient->getRequestsCount());
|
|
$this->assertTrue($cache->getItem(self::CACHE_KEY)->isHit());
|
|
}
|
|
|
|
public function testACachedTokenIsUsedWithoutAskingForANewOne(): void
|
|
{
|
|
$cache = new ArrayAdapter();
|
|
$item = $cache->getItem(self::CACHE_KEY);
|
|
$item->set('cached-token');
|
|
$cache->save($item);
|
|
|
|
$httpClient = new MockHttpClient([]);
|
|
|
|
$this->assertEquals('cached-token', $this->getProviderInstance($httpClient, $cache)->getToken());
|
|
$this->assertEquals(0, $httpClient->getRequestsCount());
|
|
}
|
|
|
|
public function testAnInvalidatedTokenIsRequestedAgain(): void
|
|
{
|
|
$httpClient = new MockHttpClient([$this->tokenResponse('abc123'), $this->tokenResponse('def456')]);
|
|
$provider = $this->getProviderInstance($httpClient);
|
|
|
|
$provider->getToken();
|
|
$provider->invalidate();
|
|
|
|
$this->assertEquals('def456', $provider->getToken());
|
|
$this->assertEquals(2, $httpClient->getRequestsCount());
|
|
}
|
|
|
|
public function testARejectedRequestFails(): void
|
|
{
|
|
$httpClient = new MockHttpClient([
|
|
new MockResponse('{"error":"invalid_client"}', ['http_code' => 401]),
|
|
]);
|
|
|
|
$this->expectException(ApiException::class);
|
|
|
|
$this->getProviderInstance($httpClient)->getToken();
|
|
}
|
|
|
|
public function testAResponseWithoutATokenFails(): void
|
|
{
|
|
$httpClient = new MockHttpClient([new MockResponse('{"expires_in":600}')]);
|
|
|
|
$this->expectException(ApiException::class);
|
|
|
|
$this->getProviderInstance($httpClient)->getToken();
|
|
}
|
|
|
|
public function testAnUnreachableTokenEndpointFails(): void
|
|
{
|
|
$httpClient = new MockHttpClient([new MockResponse('', ['error' => 'connection refused'])]);
|
|
|
|
$this->expectException(ApiException::class);
|
|
|
|
$this->getProviderInstance($httpClient)->getToken();
|
|
}
|
|
|
|
public function testAnUnparsableResponseFails(): void
|
|
{
|
|
$httpClient = new MockHttpClient([new MockResponse('<html>gateway timeout</html>')]);
|
|
|
|
$this->expectException(ApiException::class);
|
|
|
|
$this->getProviderInstance($httpClient)->getToken();
|
|
}
|
|
|
|
private function tokenResponse(string $token, int $expiresIn = 600): MockResponse
|
|
{
|
|
return new MockResponse(json_encode([
|
|
'access_token' => $token,
|
|
'token_type' => 'Bearer',
|
|
'expires_in' => $expiresIn,
|
|
]));
|
|
}
|
|
|
|
private function getProviderInstance(MockHttpClient $httpClient, ?CacheItemPoolInterface $cache = null): AccessTokenProvider
|
|
{
|
|
return new AccessTokenProvider(
|
|
$httpClient,
|
|
$cache ?? new ArrayAdapter(),
|
|
new NullLogger(),
|
|
[
|
|
'client_id' => 'team-app',
|
|
'client_secret' => 'secret',
|
|
'token_path' => 'https://myep.example/token',
|
|
'scope' => 'api',
|
|
],
|
|
);
|
|
}
|
|
}
|