Forráskód Böngészése

add unit tests for MailHub, Typo3service, ApiRequestService

Olivier Massot 3 éve
szülő
commit
40313886d6

+ 0 - 89
src/Service/ApiRequestService.php

@@ -1,89 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace App\Service;
-
-use App\Service\Utils\UrlBuilder;
-use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
-use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
-use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
-use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
-use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
-use Symfony\Contracts\HttpClient\HttpClientInterface;
-use Symfony\Contracts\HttpClient\ResponseInterface;
-
-/**
- * Base class for services sending requests to an external API
- */
-class ApiRequestService
-{
-    function __construct(
-        protected HttpClientInterface $client
-    ) {}
-
-    /**
-     * Sends a GET request and returns the response's body decoded as json
-     * @param string $path
-     * @param array $parameters
-     * @param array $options
-     * @return array
-     */
-    public function getJsonContent(string $path, array $parameters = [], array $options = []): array {
-        return json_decode($this->getContent($path, $parameters, $options), true);
-    }
-
-    /**
-     * Sends a GET request and returns the response's body
-     *
-     * @param string $path
-     * @param array $parameters
-     * @param array $options
-     * @return string
-     */
-    public function getContent(string $path, array $parameters = [], array $options = []): string {
-        try {
-            return $this->get($path, $parameters, $options)->getContent();
-        } catch (ClientExceptionInterface | TransportExceptionInterface | RedirectionExceptionInterface | ServerExceptionInterface $e) {
-            throw new NotFoundHttpException('ApiRequestService->getContent: an error occurred', $e, 404);
-        }
-    }
-
-    /**
-     * Sends a GET request and returns the response
-     *
-     * @param string $path
-     * @param array $parameters
-     * @param array $options
-     * @return ResponseInterface
-     */
-    protected function get(string $path, array $parameters = [], array $options = []): ResponseInterface {
-        return $this->request('GET', $path, $parameters, $options);
-    }
-
-    /**
-     * Send an HTTP request to the Dolibarr API,
-     * and return the decoded content of the response's body
-     *
-     * @param string $method
-     * @param string $url
-     * @param array $parameters
-     * @param array $options
-     * @return ResponseInterface
-     */
-    protected function request(
-        string $method,
-        string $url,
-        array $parameters = [],
-        array $options = []
-    ): ResponseInterface
-    {
-        $url = ltrim($url, '/');
-        $url = UrlBuilder::concatParameters($url, $parameters);
-        try {
-            return $this->client->request($method, $url, $options);
-        } catch (HttpExceptionInterface | TransportExceptionInterface $e) {
-            throw new NotFoundHttpException('fetch error', $e, 500);
-        }
-    }
-}

+ 1 - 1
src/Service/Rest/ApiRequestService.php

@@ -48,7 +48,7 @@ class ApiRequestService implements ApiRequestInterface
         try {
             return $this->get($path, $parameters, $options)->getContent();
         } catch (ClientExceptionInterface | TransportExceptionInterface | RedirectionExceptionInterface | ServerExceptionInterface $e) {
-            throw new HttpException(404, 'Data not found', $e);
+            throw new HttpException(500, 'Request error : ', $e);
         }
     }
 

+ 2 - 0
src/Service/Typo3/BindFileService.php

@@ -4,6 +4,8 @@ namespace App\Service\Typo3;
 
 /**
  * Opérations sur le fichier Bind, qui gère entre autres l'adressage DNS lié aux sous-domaines
+ *
+ * @codeCoverageIgnore
  */
 class BindFileService
 {

+ 1 - 1
src/Service/Typo3/Typo3Service.php

@@ -26,7 +26,7 @@ class Typo3Service
      * @return ResponseInterface
      * @throws TransportExceptionInterface
      */
-    private function sendCommand(string $route, array $parameters): ResponseInterface
+    protected function sendCommand(string $route, array $parameters): ResponseInterface
     {
         $url = UrlBuilder::concatParameters('/typo3/index.php?route=' . $route, $parameters);
         return $this->typo3_client->request('GET', $url);

+ 103 - 0
tests/Service/MailHubTest.php

@@ -0,0 +1,103 @@
+<?php
+
+use App\Service\Core\ContactPointUtils;
+use App\Service\MailHub;
+use PHPUnit\Framework\TestCase;
+use Symfony\Bridge\Twig\Mime\TemplatedEmail;
+use Symfony\Component\Mailer\MailerInterface;
+
+class MailHubTest extends TestCase
+{
+    private MailerInterface $mailer;
+    private string $opentalentNoReplyEmailAddress;
+    private ContactPointUtils $contactPointUtils;
+    private \App\Service\Access\Utils $accessUtils;
+
+    public function setUp(): void {
+        $this->mailer = $this->getMockBuilder(MailerInterface::class)->disableOriginalConstructor()->getMock();
+        $this->opentalentNoReplyEmailAddress = 'noreply@opentalent.fr';
+        $this->contactPointUtils = $this->getMockBuilder(ContactPointUtils::class)->disableOriginalConstructor()->getMock();
+        $this->accessUtils = $this->getMockBuilder(\App\Service\Access\Utils::class)->disableOriginalConstructor()->getMock();
+    }
+
+    public function testSendAutomaticEmailTo(): void
+    {
+        $contactPoint = $this->getMockBuilder(\App\Entity\Core\ContactPoint::class)->disableOriginalConstructor()->getMock();
+        $contactPoint->method('getEmail')->willReturn('mail@domain.net');
+
+        $person = $this->getMockBuilder(\App\Entity\Person\Person::class)->disableOriginalConstructor()->getMock();
+        $person->method('getFullName')->willReturn('Don Diego de la Vega');
+        $person->method('getUsername')->willReturn('zorro2000');
+
+        $access = $this->getMockBuilder(\App\Entity\Access\Access::class)->disableOriginalConstructor()->getMock();
+        $access->method('getPerson')->willReturn($person);
+
+        $this->contactPointUtils->expects(self::once())->method('getPersonContactPointPrincipal')->willReturn($contactPoint);
+
+        $this->mailer->expects(self::once())
+            ->method('send')
+            ->with(self::isInstanceOf(TemplatedEmail::class));
+
+        $mailerHub = new MailHub(
+            $this->mailer,
+            $this->opentalentNoReplyEmailAddress,
+            $this->contactPointUtils,
+            $this->accessUtils
+        );
+
+        $mailerHub->sendAutomaticEmailTo($access, 'subject', 'a_template', []);
+    }
+
+    public function testSendAutomaticEmailToButNoAddress(): void
+    {
+        $access = $this->getMockBuilder(\App\Entity\Access\Access::class)->disableOriginalConstructor()->getMock();
+
+        $this->contactPointUtils->expects(self::once())->method('getPersonContactPointPrincipal')->willReturn(null);
+
+        $mailerHub = new MailHub(
+            $this->mailer,
+            $this->opentalentNoReplyEmailAddress,
+            $this->contactPointUtils,
+            $this->accessUtils
+        );
+
+        try {
+            $mailerHub->sendAutomaticEmailTo($access, 'subject', 'a_template', []);
+            throw new AssertionError('A RuntimeException should have been thrown but has not');
+        } catch (\RuntimeException $e) {}
+    }
+
+    public function testSendAutomaticEmailToAdmin() {
+
+        $organization = $this->getMockBuilder(\App\Entity\Organization\Organization::class)->disableOriginalConstructor()->getMock();
+        $admin = $this->getMockBuilder(\App\Entity\Access\Access::class)->disableOriginalConstructor()->getMock();
+
+        $this->accessUtils->expects(self::once())->method('findAdminFor')->with($organization)->willReturn($admin);
+
+        $mailerHub = $this->getMockBuilder(MailHub::class)
+            ->onlyMethods(['sendAutomaticEmailTo'])
+            ->setConstructorArgs([$this->mailer, $this->opentalentNoReplyEmailAddress, $this->contactPointUtils, $this->accessUtils])
+            ->getMock();
+        $mailerHub->expects(self::once())->method('sendAutomaticEmailTo')->with($admin, 'subject', 'template', []);
+
+        $mailerHub->sendAutomaticEmailToAdmin($organization, 'subject', 'template', []);
+    }
+
+    public function testSendAutomaticEmailToAdminButNoAdmin() {
+
+        $organization = $this->getMockBuilder(\App\Entity\Organization\Organization::class)->disableOriginalConstructor()->getMock();
+        $this->accessUtils->expects(self::once())->method('findAdminFor')->with($organization)->willReturn(null);
+
+        $mailerHub = new MailHub(
+            $this->mailer,
+            $this->opentalentNoReplyEmailAddress,
+            $this->contactPointUtils,
+            $this->accessUtils
+        );
+
+        try {
+            $mailerHub->sendAutomaticEmailToAdmin($organization, 'subject', 'template', []);
+            throw new AssertionError('A RuntimeException should have been thrown but has not');
+        } catch (\RuntimeException $e) {}
+    }
+}

+ 1 - 1
tests/Service/OnChange/Organization/OnParametersChangeTest.php

@@ -29,7 +29,7 @@ class OnParametersChangeTest extends TestCase
     private MessageBusInterface $messageBus;
     private \App\Service\Organization\Utils $organizationUtils;
 
-    public function setUp():void
+    public function setUp(): void
     {
         $this->courseRepositoryMock = $this->getMockBuilder(CourseRepository::class)->disableOriginalConstructor()->getMock();
         $this->networkUtils = $this->getMockBuilder(\App\Service\Network\Utils::class)->disableOriginalConstructor()->getMock();

+ 145 - 20
tests/Service/Rest/ApiRequestServiceTest.php

@@ -3,44 +3,169 @@
 namespace App\Tests\Service;
 
 use App\Service\Rest\ApiRequestService;
+use AssertionError;
 use PHPUnit\Framework\TestCase;
+use Symfony\Component\HttpClient\Exception\TransportException;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
 use Symfony\Contracts\HttpClient\ResponseInterface;
+use Symfony\Component\HttpKernel\Exception\HttpException;
 
 class ApiRequestServiceTest extends TestCase
 {
-    private ApiRequestService $apiRequestService;
+    private HttpClientInterface $client;
 
     public function setUp(): void {
-        $client = $this->getMockBuilder(HttpClientInterface::class)
-            ->disableOriginalConstructor()
+        $this->client = $this->getMockBuilder(HttpClientInterface::class)->disableOriginalConstructor()->getMock();
+    }
+
+    public function testGetJsonContent() {
+        $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
+            ->setConstructorArgs([$this->client])
+            ->onlyMethods(['getContent'])
+            ->getMock();
+
+        $apiRequestService->expects(self::once())
+            ->method('getContent')
+            ->with('path/to/data', [], [])
+            ->willReturn('{"foo": "bar"}');
+
+        $data = $apiRequestService->getJsonContent('path/to/data');
+
+        $this->assertEquals(['foo' => 'bar'], $data);
+    }
+
+    public function testGetContent() {
+        $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
+            ->setConstructorArgs([$this->client])
+            ->onlyMethods(['get'])
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+        $response->expects(self::once())->method('getContent')->willReturn('{foo: bar}');
+
+        $apiRequestService->expects(self::once())
+            ->method('get')
+            ->with('path/to/data', [], [])
+            ->willReturn($response);
+
+        $content = $apiRequestService->getContent('path/to/data');
+
+        $this->assertEquals('{foo: bar}', $content);
+    }
+
+    public function testGetContentWithError() {
+        $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
+            ->setConstructorArgs([$this->client])
+            ->onlyMethods(['get'])
             ->getMock();
 
-        $response = $this->getMockBuilder(ResponseInterface::class)
-            ->disableOriginalConstructor()
+        $apiRequestService->expects(self::once())
+            ->method('get')
+            ->willThrowException(new TransportException());
+
+        try {
+            $apiRequestService->getContent('path/to/data');
+            throw new AssertionError('An HttpException should have been thrown, but has not');
+        } catch (HttpException $e) {
+            $this->assertEquals(500, $e->getStatusCode());
+        }
+    }
+
+    public function testGet() {
+        $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
+            ->setConstructorArgs([$this->client])
+            ->onlyMethods(['request'])
             ->getMock();
-        $response->method('getContent')->willReturn('{"a": 1}');
 
-        $client
-            ->expects($this->once())
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+
+        $apiRequestService->expects(self::once())
             ->method('request')
-            ->with("GET", "my_url.org")
+            ->with('GET', 'path/to/data', [], [])
             ->willReturn($response);
 
-        $this->apiRequestService = new ApiRequestService($client);
+        $actualResponse = $apiRequestService->get('path/to/data');
+
+        $this->assertEquals($response, $actualResponse);
     }
 
-    public function testGetJsonContent() {
-        $this->assertEquals(
-            ['a' => 1],
-            $this->apiRequestService->getJsonContent('my_url.org')
-        );
+    public function testPost() {
+        $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
+            ->setConstructorArgs([$this->client])
+            ->onlyMethods(['request'])
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+
+        $apiRequestService->expects(self::once())
+            ->method('request')
+            ->with('POST', 'path/to/data', [], [])
+            ->willReturn($response);
+
+        $actualResponse = $apiRequestService->post('path/to/data');
+
+        $this->assertEquals($response, $actualResponse);
     }
 
-    public function testGetContent() {
-        $this->assertEquals(
-            '{"a": 1}',
-            $this->apiRequestService->getContent('my_url.org')
-        );
+    public function testPut() {
+        $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
+            ->setConstructorArgs([$this->client])
+            ->onlyMethods(['request'])
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+
+        $apiRequestService->expects(self::once())
+            ->method('request')
+            ->with('PUT', 'path/to/data', [], [])
+            ->willReturn($response);
+
+        $actualResponse = $apiRequestService->put('path/to/data');
+
+        $this->assertEquals($response, $actualResponse);
+    }
+
+    public function testDelete() {
+        $apiRequestService = $this->getMockBuilder(ApiRequestService::class)
+            ->setConstructorArgs([$this->client])
+            ->onlyMethods(['request'])
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+
+        $apiRequestService->expects(self::once())
+            ->method('request')
+            ->with('DELETE', 'path/to/data', [], [])
+            ->willReturn($response);
+
+        $actualResponse = $apiRequestService->delete('path/to/data');
+
+        $this->assertEquals($response, $actualResponse);
+    }
+
+    public function testRequest() {
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+
+        $this->client->expects(self::once())->method('request')->with('GET', 'path/to/data?param=1', [])->willReturn($response);
+
+        $apiRequestService = new ApiRequestService($this->client);
+
+        $actualResponse = $apiRequestService->request('GET', 'path/to/data', ['param' => 1]);
+
+        $this->assertEquals($response, $actualResponse);
+    }
+
+    public function testRequestWithError() {
+
+        $this->client->expects(self::once())->method('request')->willThrowException(new TransportException('error', 500));
+
+        $apiRequestService = new ApiRequestService($this->client);
+
+        try {
+            $apiRequestService->request('GET', 'path/to/data');
+            throw new AssertionError('An HttpException should have been thrown, but has not');
+        } catch (HttpException $e) {
+            $this->assertEquals(500, $e->getStatusCode());
+        }
     }
 }

+ 171 - 0
tests/Service/Typo3/Typo3ServiceTest.php

@@ -0,0 +1,171 @@
+<?php
+
+namespace App\Test\Service\Typo3;
+
+use App\Service\Typo3\Typo3Service;
+use PHPUnit\Framework\TestCase;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
+use Symfony\Contracts\HttpClient\ResponseInterface;
+
+class TestableTypo3Service extends Typo3Service {
+    public function sendCommand(string $route, array $parameters): ResponseInterface { return parent::sendCommand($route, $parameters); }
+}
+
+class Typo3ServiceTest extends TestCase
+{
+    private HttpClientInterface $typo3Client;
+
+    public function setUp(): void {
+        $this->typo3Client = $this->getMockBuilder(HttpClientInterface::class)->disableOriginalConstructor()->getMock();
+    }
+
+    public function testSendCommand(): void
+    {
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+
+        $this->typo3Client
+            ->expects(self::once())
+            ->method('request')
+            ->with('GET', '/typo3/index.php?route=foo&param=bar')
+            ->willReturn($response);
+
+        $typo3Service = new TestableTypo3Service($this->typo3Client);
+
+        $typo3Service->sendCommand('foo', ['param' => 'bar']);
+    }
+
+    public function testCreateSite() {
+        $typo3Service = $this->getMockBuilder(Typo3Service::class)
+            ->onlyMethods(['sendCommand'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+        $typo3Service->expects(self::once())
+            ->method('sendCommand')->
+            with('/otadmin/site/create', ['organization-id' => 1])
+            ->willReturn($response);
+
+        $typo3Service->createSite(1);
+    }
+
+    public function testClearSiteCache() {
+        $typo3Service = $this->getMockBuilder(Typo3Service::class)
+            ->onlyMethods(['sendCommand'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+        $typo3Service->expects(self::once())
+            ->method('sendCommand')->
+            with('/otadmin/site/update', ['organization-id' => 1])
+            ->willReturn($response);
+
+        $typo3Service->updateSite(1);
+    }
+
+    public function testDeleteSite() {
+        $typo3Service = $this->getMockBuilder(Typo3Service::class)
+            ->onlyMethods(['sendCommand'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+        $typo3Service->expects(self::once())
+            ->method('sendCommand')->
+            with('/otadmin/site/delete', ['organization-id' => 1])
+            ->willReturn($response);
+
+        $typo3Service->deleteSite(1);
+    }
+
+    public function testUndeleteSite() {
+        $typo3Service = $this->getMockBuilder(Typo3Service::class)
+            ->onlyMethods(['sendCommand'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+        $typo3Service->expects(self::once())
+            ->method('sendCommand')->
+            with('/otadmin/site/undelete', ['organization-id' => 1])
+            ->willReturn($response);
+
+        $typo3Service->undeleteSite(1);
+    }
+
+    public function testSetSiteDomain() {
+        $typo3Service = $this->getMockBuilder(Typo3Service::class)
+            ->onlyMethods(['sendCommand'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+        $typo3Service->expects(self::once())
+            ->method('sendCommand')->
+            with('/otadmin/site/set-domain', ['organization-id' => 1, 'domain' => 'new-domain'])
+            ->willReturn($response);
+
+        $typo3Service->setSiteDomain(1, 'new-domain', false);
+    }
+
+    public function testSetSiteDomainWithRedirection() {
+        $typo3Service = $this->getMockBuilder(Typo3Service::class)
+            ->onlyMethods(['sendCommand'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+        $typo3Service->expects(self::once())
+            ->method('sendCommand')->
+            with('/otadmin/site/set-domain', ['organization-id' => 1, 'domain' => 'new-domain', 'redirect' => 1])
+            ->willReturn($response);
+
+        $typo3Service->setSiteDomain(1, 'new-domain', true);
+    }
+
+    public function testResetSitePerms() {
+        $typo3Service = $this->getMockBuilder(Typo3Service::class)
+            ->onlyMethods(['sendCommand'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+        $typo3Service->expects(self::once())
+            ->method('sendCommand')->
+            with('/otadmin/site/reset-perms', ['organization-id' => 1])
+            ->willReturn($response);
+
+        $typo3Service->resetSitePerms(1);
+    }
+
+    public function testGetSiteStatus() {
+        $typo3Service = $this->getMockBuilder(Typo3Service::class)
+            ->onlyMethods(['sendCommand'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+        $typo3Service->expects(self::once())
+            ->method('sendCommand')->
+            with('/otadmin/site/status', ['organization-id' => 1])
+            ->willReturn($response);
+
+        $typo3Service->getSiteStatus(1);
+    }
+
+    public function testAddRedirection() {
+        $typo3Service = $this->getMockBuilder(Typo3Service::class)
+            ->onlyMethods(['sendCommand'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)->disableOriginalConstructor()->getMock();
+        $typo3Service->expects(self::once())
+            ->method('sendCommand')->
+            with('/otadmin/redirect/add', ['from-domain' => 'foo', 'to-domain' => 'bar'])
+            ->willReturn($response);
+
+        $typo3Service->addRedirection('foo', 'bar');
+    }
+}