Files
myep-team/tests/MyEp/Api/AccessTokenProviderTest.php
T

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',
],
);
}
}