From a7d07be1be5eaacd42a0e9b1cca8be2151830448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Fri, 17 Oct 2025 12:39:40 +0200 Subject: [PATCH] test: add gandi provider test --- .env.test | 3 ++ .github/workflows/lint-and-tests.yml | 2 + config/services.yaml | 4 ++ src/MessageHandler/OrderDomainHandler.php | 1 + src/Service/Provider/GandiProvider.php | 13 +++-- src/Service/Provider/NamecheapProvider.php | 4 +- tests/Controller/ConnectorControllerTest.php | 21 +++++++- tests/Service/Provider/GandiProviderTest.php | 55 ++++++++++++++++++++ tests/State/WatchListUpdateProcessorTest.php | 4 +- 9 files changed, 98 insertions(+), 9 deletions(-) create mode 100644 tests/Service/Provider/GandiProviderTest.php diff --git a/.env.test b/.env.test index 0a8ac7b..3cdd207 100644 --- a/.env.test +++ b/.env.test @@ -9,3 +9,6 @@ LIMITED_FEATURES=true LIMIT_MAX_WATCHLIST=10 LIMIT_MAX_WATCHLIST_DOMAINS=10 LIMIT_MAX_WATCHLIST_WEBHOOKS=10 + +# TEST +GANDI_PAT_TOKEN= diff --git a/.github/workflows/lint-and-tests.yml b/.github/workflows/lint-and-tests.yml index 6514972..aab215a 100644 --- a/.github/workflows/lint-and-tests.yml +++ b/.github/workflows/lint-and-tests.yml @@ -102,6 +102,8 @@ jobs: name: Tests runs-on: ubuntu-latest needs: [ php-setup, cs-fixer, phpstan ] + env: + GANDI_PAT_TOKEN: ${{ secrets.GANDI_PAT_TOKEN }} services: postgres: image: postgres diff --git a/config/services.yaml b/config/services.yaml index 1214757..cf5b596 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -46,3 +46,7 @@ services: # add more service definitions when explicit configuration is needed # please note that last definitions always *replace* previous ones + +when@test: + parameters: + gandi_pat_token: '%env(string:GANDI_PAT_TOKEN)%' diff --git a/src/MessageHandler/OrderDomainHandler.php b/src/MessageHandler/OrderDomainHandler.php index 551b432..c4faab0 100644 --- a/src/MessageHandler/OrderDomainHandler.php +++ b/src/MessageHandler/OrderDomainHandler.php @@ -93,6 +93,7 @@ final readonly class OrderDomainHandler * The user is authenticated to ensure that the credentials are still valid. * If no errors occur, the purchase is attempted. */ + $connectorProvider->authenticate($connector->getAuthData()); $connectorProvider->orderDomain($domain, $this->kernel->isDebug()); diff --git a/src/Service/Provider/GandiProvider.php b/src/Service/Provider/GandiProvider.php index 6bfe0f9..652f25d 100644 --- a/src/Service/Provider/GandiProvider.php +++ b/src/Service/Provider/GandiProvider.php @@ -12,6 +12,7 @@ use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use Symfony\Component\HttpClient\HttpOptions; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -31,12 +32,14 @@ class GandiProvider extends AbstractProvider protected DefaultProviderDto $authData; private const BASE_URL = 'https://api.gandi.net'; + private const SANDBOX_BASE_URL = 'https://api.sandbox.gandi.net'; public function __construct( CacheItemPoolInterface $cacheItemPool, private readonly HttpClientInterface $client, DenormalizerInterface&NormalizerInterface $serializer, ValidatorInterface $validator, + private readonly KernelInterface $kernel, ) { parent::__construct($cacheItemPool, $serializer, $validator); } @@ -58,14 +61,14 @@ class GandiProvider extends AbstractProvider $user = $this->client->request('GET', '/v5/organization/user-info', (new HttpOptions()) ->setAuthBearer($this->authData->token) ->setHeader('Accept', 'application/json') - ->setBaseUri(self::BASE_URL) + ->setBaseUri($this->kernel->isDebug() ? self::SANDBOX_BASE_URL : self::BASE_URL) ->toArray() )->toArray(); $httpOptions = (new HttpOptions()) ->setAuthBearer($this->authData->token) ->setHeader('Accept', 'application/json') - ->setBaseUri(self::BASE_URL) + ->setBaseUri($this->kernel->isDebug() ? self::SANDBOX_BASE_URL : self::BASE_URL) ->setHeader('Dry-Run', $dryRun ? '1' : '0') ->setJson([ 'fqdn' => $ldhName, @@ -90,7 +93,7 @@ class GandiProvider extends AbstractProvider ]); } - $res = $this->client->request('POST', '/domain/domains', $httpOptions->toArray()); + $res = $this->client->request('POST', '/v5/domain/domains', $httpOptions->toArray()); if ((!$dryRun && Response::HTTP_ACCEPTED !== $res->getStatusCode()) || ($dryRun && Response::HTTP_OK !== $res->getStatusCode())) { @@ -107,7 +110,7 @@ class GandiProvider extends AbstractProvider $response = $this->client->request('GET', '/v5/organization/user-info', (new HttpOptions()) ->setAuthBearer($this->authData->token) ->setHeader('Accept', 'application/json') - ->setBaseUri(self::BASE_URL) + ->setBaseUri($this->kernel->isDebug() ? self::SANDBOX_BASE_URL : self::BASE_URL) ->toArray() ); @@ -128,7 +131,7 @@ class GandiProvider extends AbstractProvider $response = $this->client->request('GET', '/v5/domain/tlds', (new HttpOptions()) ->setAuthBearer($this->authData->token) ->setHeader('Accept', 'application/json') - ->setBaseUri(self::BASE_URL) + ->setBaseUri($this->kernel->isDebug() ? self::SANDBOX_BASE_URL : self::BASE_URL) ->toArray())->toArray(); return array_map(fn ($tld) => $tld['name'], $response); diff --git a/src/Service/Provider/NamecheapProvider.php b/src/Service/Provider/NamecheapProvider.php index 1a0a5eb..f2ee9b1 100644 --- a/src/Service/Provider/NamecheapProvider.php +++ b/src/Service/Provider/NamecheapProvider.php @@ -28,8 +28,8 @@ class NamecheapProvider extends AbstractProvider /** @var NamecheapProviderDto */ protected DefaultProviderDto $authData; - public const BASE_URL = 'https://api.namecheap.com/xml.response'; - public const SANDBOX_BASE_URL = 'https://api.sandbox.namecheap.com/xml.response'; + private const BASE_URL = 'https://api.namecheap.com/xml.response'; + private const SANDBOX_BASE_URL = 'https://api.sandbox.namecheap.com/xml.response'; public function __construct( CacheItemPoolInterface $cacheItemPool, diff --git a/tests/Controller/ConnectorControllerTest.php b/tests/Controller/ConnectorControllerTest.php index b25a129..493742b 100644 --- a/tests/Controller/ConnectorControllerTest.php +++ b/tests/Controller/ConnectorControllerTest.php @@ -32,7 +32,7 @@ final class ConnectorControllerTest extends ApiTestCase 'waiveRetractationPeriod' => true, 'acceptConditions' => true, 'ownerLegalAge' => true, - 'token' => '', + 'token' => 'test', ], 'provider' => 'gandi', ]]); @@ -69,4 +69,23 @@ final class ConnectorControllerTest extends ApiTestCase ]]); $this->assertResponseStatusCodeSame(400); } + + public function testCreateConnectorValidAuthData(): void + { + $gandiToken = static::getContainer()->getParameter('gandi_pat_token'); + if (!$gandiToken) { + $this->markTestSkipped('Missing Gandi PAT token'); + } + $client = ConnectorControllerTest::createClientWithCredentials(ConnectorControllerTest::getToken(UserFactory::createOne())); + $client->request('POST', '/api/connectors', ['json' => [ + 'authData' => [ + 'waiveRetractationPeriod' => true, + 'acceptConditions' => true, + 'ownerLegalAge' => true, + 'token' => $gandiToken, + ], + 'provider' => 'gandi', + ]]); + $this->assertResponseStatusCodeSame(201); + } } diff --git a/tests/Service/Provider/GandiProviderTest.php b/tests/Service/Provider/GandiProviderTest.php new file mode 100644 index 0000000..b1165b3 --- /dev/null +++ b/tests/Service/Provider/GandiProviderTest.php @@ -0,0 +1,55 @@ +getParameter('gandi_pat_token'); + if (!$gandiToken) { + $this->markTestSkipped('Missing Gandi PAT token'); + } + + // Create a GANDI Connector + $client = ConnectorControllerTest::createClientWithCredentials(ConnectorControllerTest::getToken(UserFactory::createOne())); + $response = $client->request('POST', '/api/connectors', ['json' => [ + 'authData' => [ + 'waiveRetractationPeriod' => true, + 'acceptConditions' => true, + 'ownerLegalAge' => true, + 'token' => $gandiToken, + ], + 'provider' => 'gandi', + ]]); + $this->assertResponseStatusCodeSame(201); + + // Create a Watchlist with a single domain name + WatchListUpdateProcessorTest::createUserAndWatchlist($client, ['/api/domains/example.com'], '/api/connectors/'.$response->toArray()['id']); + + $response = $client->request('GET', '/api/watchlists'); + $watchlistId = $response->toArray()['hydra:member'][0]['token']; + + // Set the domain as deleted + $domain = self::getContainer()->get(DomainRepository::class)->findOneBy(['ldhName' => 'example.com']); + $domain->setDeleted(true); + + // Trigger the Order Domain message + $orderDomainHandler = self::getContainer()->get(OrderDomainHandler::class); + $message = new OrderDomain($watchlistId, 'example.com'); + $orderDomainHandler($message); + + $this->assertResponseStatusCodeSame(200); + } +} diff --git a/tests/State/WatchListUpdateProcessorTest.php b/tests/State/WatchListUpdateProcessorTest.php index 88fdc76..0c1eefc 100644 --- a/tests/State/WatchListUpdateProcessorTest.php +++ b/tests/State/WatchListUpdateProcessorTest.php @@ -53,13 +53,15 @@ final class WatchListUpdateProcessorTest extends ApiTestCase $this->assertCount(1, $data['trackedEvents']); } - public static function createUserAndWatchlist(?Client $client = null, array $domains = ['/api/domains/example.com']): Client + public static function createUserAndWatchlist(?Client $client = null, array $domains = ['/api/domains/example.com'], ?string $connectorId = null): Client { $client = $client ?? self::createClientWithCredentials(self::getToken(UserFactory::createOne())); + $client->request('POST', '/api/watchlists', ['json' => [ 'domains' => $domains, 'name' => 'My Watchlist', 'trackedEvents' => ['last changed', 'transfer', 'expiration', 'deletion'], + 'connector' => $connectorId, ]]); return $client;