Procházet zdrojové kódy

implements test for Get person/id

Olivier Massot před 2 roky
rodič
revize
2d3bdb4ed3

+ 1 - 1
composer.json

@@ -87,7 +87,7 @@
     "symfony/browser-kit": "6.2.*",
     "symfony/css-selector": "6.2.*",
     "symfony/debug-bundle": "6.2.*",
-    "symfony/maker-bundle": "^1.21",
+    "symfony/maker-bundle": "^1.48",
     "symfony/phpunit-bridge": "^6.2",
     "symfony/stopwatch": "6.2.*",
     "symfony/web-profiler-bundle": "6.2.*",

+ 1 - 0
config/opentalent/products.yaml

@@ -57,6 +57,7 @@ opentalent:
           - PersonActivity
           - PersonHoliday
           - OrganizationResponsability
+          - Person
         roles:
           - ROLE_USERS
           - ROLE_ACCOUNTS

+ 1 - 3
config/packages/staging/security.yaml

@@ -3,6 +3,4 @@
 security:
   password_hashers:
     App\Entity\Person\Person:
-      algorithm: md5
-      encode_as_base64: false
-      iterations: 0
+      algorithm: plaintext

+ 3 - 2
src/Entity/Person/Person.php

@@ -45,8 +45,9 @@ class Person implements UserInterface, PasswordAuthenticatedUserInterface
     #[ORM\Column(length: 180, unique: true, nullable: true)]
     private ?string $username = null;
 
-    /** @var string[]  */
-    private array $roles = [];
+    /** @var string[]|null  */
+    #[ORM\Column(type: 'json', nullable: true)]
+    private ?array $roles = [];
 
     #[ORM\Column(nullable: true)]
     private ?string $password = null;

+ 106 - 4
tests/Application/OtWebTestCase.php

@@ -2,33 +2,106 @@
 
 namespace App\Tests\Application;
 
+use App\Entity\Access\Access;
+use App\Entity\Person\Person;
 use App\Entity\Public\FederationStructure;
+use Doctrine\ORM\EntityManagerInterface;
+use Doctrine\Common\DataFixtures\Purger\ORMPurger;
+use Symfony\Bundle\SecurityBundle\Security;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\DomCrawler\Crawler;
 use ApiPlatform\Symfony\Bundle\Test\Client;
 use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
 use Symfony\Contracts\HttpClient\ResponseInterface;
+use Zenstruck\Foundry\Proxy;
 
 /**
  * Base class for applicative tests
  */
 abstract class OtWebTestCase extends ApiTestCase
 {
+    protected EntityManagerInterface $em;
     protected Client $client;
+    protected Access | Proxy | null $user = null;
+    protected ?string $securityToken = null;
 
+    /**
+     * Executed before each test
+     *
+     * @return void
+     * @throws \Exception
+     */
     public function setup(): void {
+
+        // Boot le kernel symfony et récupère l'entity manager
+        // @see https://symfony.com/doc/current/testing.html#retrieving-services-in-the-test
+        self::bootKernel();
+        $this->em = static::getContainer()->get(EntityManagerInterface::class);
+
+        // Purge DB before populating new fixtures
+        $this->purgeDb();
+
+        // Définit les fixtures et flush
+        $this->setFixtures();
+        $this->em->flush();
+
+        // Instancie le client qui exécutera les requêtes à l'api
+        // @see https://symfony.com/doc/current/testing.html#making-requests
         $this->client = static::createClient();
     }
 
+    /**
+     * Delete all DB records before populating fixtures.
+     *
+     * @return void
+     * @throws \Doctrine\DBAL\Exception
+     */
+    private function purgeDb() {
+        if (!preg_match('/.*test.*/', $this->em->getConnection()->getDatabase())) {
+            throw new \RuntimeException("The DB name shall contain 'test' in its name to be purge");
+        }
+
+        $this->em->getConnection()->exec('SET FOREIGN_KEY_CHECKS = 0;');
+        $purger = new ORMPurger($this->em);
+        $purger->setPurgeMode(ORMPurger::PURGE_MODE_DELETE);
+        $purger->purge();
+        $this->em->getConnection()->exec('SET FOREIGN_KEY_CHECKS = 1;');
+    }
+
+    /**
+     * Create and persist the fixtures (no need to flush, the setup will perform it later)
+     *
+     * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#same-entities-used-in-these-docs
+     *
+     * @return void
+     */
+    protected function setFixtures(): void {
+        // TODO: préparer un jeu de fixtures par défaut
+    }
+
     /**
      * Send a requests, parse the hydra response and return an object or a Collection
      *
      * @param string $method
      * @param string $route
-     * @param array<mixed> $parameters
+     * @param array<mixed> $data
+     * @param array<mixed> $headers
      * @return ResponseInterface
      */
-    protected function request(string $method, string $route, array $parameters = []): ResponseInterface {
+    protected function request(string $method, string $route, array | null $data = null, array $headers = []): ResponseInterface {
+        if ($this->user) {
+            $headers = array_merge(
+                ['x-accessid' => $this->user->getId(), 'authorization' => 'BEARER ' . $this->securityToken],
+                $headers
+            );
+        }
+
+        $parameters = ['headers' => $headers];
+
+        if ($data) {
+            $parameters['json'] = $data;
+        }
+
         return $this->client->request(
             $method,
             $route,
@@ -43,11 +116,28 @@ abstract class OtWebTestCase extends ApiTestCase
      * @param array<mixed> $parameters
      * @return ResponseInterface
      */
-    protected function get(string $route, array $parameters = []): ResponseInterface {
+    protected function get(string $route, array $headers = []): ResponseInterface {
         return $this->request(
             Request::METHOD_GET,
             $route,
-            $parameters
+            null,
+            $headers
+        );
+    }
+
+    /**
+     * Send a POST request and return the response parsed content
+     *
+     * @param string $route
+     * @param array<mixed> $parameters
+     * @return ResponseInterface
+     */
+    protected function post(string $route, array $data, array $headers = []): ResponseInterface {
+        return $this->request(
+            Request::METHOD_POST,
+            $route,
+            $data,
+            $headers
         );
     }
 
@@ -62,4 +152,16 @@ abstract class OtWebTestCase extends ApiTestCase
         // $this->assertMatchesResourceCollectionJsonSchema($resourceClass);
     }
 
+    protected function loginAs(Proxy | Access $access): void {
+        $person = $access->getPerson();
+
+        $response = $this->post(
+            '/login_check',
+            ['username' => $person->getUsername(), 'password' => $person->getPassword()]
+        );
+        $content = $response->getContent();
+
+        $this->securityToken = json_decode($content)->token;
+        $this->user = $access;
+    }
 }

+ 86 - 0
tests/Application/Person/PersonTest.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace App\Tests\Application\Person;
+use App\Entity\Access\Access;
+use App\Entity\Organization\Organization;
+use App\Entity\Organization\Settings;
+use App\Entity\Public\PublicEvent;
+use App\Enum\Organization\PrincipalTypeEnum;
+use App\Enum\Organization\SettingsProductEnum;
+use App\Tests\Application\OtWebTestCase;
+use App\Entity\Person;
+use App\Tests\Fixture\Factory\Access\AccessFactory;
+use App\Tests\Fixture\Factory\Organization\OrganizationFactory;
+use App\Tests\Fixture\Factory\Organization\SettingsFactory;
+use App\Tests\Fixture\Factory\Person\PersonFactory;
+use App\Tests\Fixture\PersonFixtures;
+use Zenstruck\Foundry\Factory;
+use Zenstruck\Foundry\Proxy;
+use App\Enum\Organization\LegalEnum;
+
+class PersonTest extends OtWebTestCase
+{
+    private Proxy | Person $person;
+    private Proxy | Organization $organization;
+    private Proxy | Access $access;
+    private Proxy | Settings $settings;
+
+    protected function setFixtures(): void
+    {
+        $this->person = PersonFactory::createOne(
+            [
+                'username' => 'username',
+                'password' => 'password'
+            ]
+        );
+
+        $this->organization = OrganizationFactory::createOne([
+            'legalStatus' => LegalEnum::ASSOCIATION_LAW_1901()->getValue(),
+            'principalType' => PrincipalTypeEnum::ARTISTIC_EDUCATION_ONLY()->getValue(),
+            'name' => 'My Organization'
+        ]);
+
+        $this->settings = SettingsFactory::createOne([
+            'product' => SettingsProductEnum::ARTIST(),
+            'organization' => $this->organization
+        ]);
+
+        $this->access = AccessFactory::createOne([
+            'person' => $this->person,
+            'organization' => $this->organization,
+            'roles' => ['ROLE_USERS_VIEW']
+        ]);
+    }
+
+    public function testPersonGet(): void
+    {
+        $this->loginAs($this->access);
+
+        $this->get('/api/people/' . $this->person->getId());
+
+        $this->validateCollectionSchema(Person::class);
+
+        $this->assertJsonContains([
+            '@context' => '/api/contexts/Person',
+            '@id' => '/api/people/' . $this->person->getId(),
+            '@type' => 'Person',
+            'username' => 'username'
+        ]);
+    }
+
+    public function testPersonGetCollection(): void {
+        // TODO: get collection is not permitted
+    }
+
+    public function testPersonPut(): void {
+        // TODO: put is not permitted
+    }
+
+    public function testPersonPost(): void {
+        // TODO: post is not permitted
+    }
+
+    public function testPersonDelete(): void {
+        // TODO: delete is not permitted
+    }
+}

+ 64 - 0
tests/Fixture/Factory/Access/AccessFactory.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Access;
+
+use App\Entity\Access\Access;
+use App\Tests\Fixture\Factory\Person\PersonRepository;
+use Zenstruck\Foundry\RepositoryProxy;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<Access>
+ *
+ * @phpstan-method        Access|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static Access|Proxy createOne(array $attributes = [])
+ * @phpstan-method static Access|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static Access|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static Access|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static Access|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static Access|Proxy random(array $attributes = [])
+ * @phpstan-method static Access|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static AccessRepository|RepositoryProxy repository()
+ * @phpstan-method static Access[]|Proxy[] all()
+ * @phpstan-method static Access[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static Access[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static Access[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static Access[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static Access[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class AccessFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return Access::class;
+    }
+}

+ 64 - 0
tests/Fixture/Factory/Organization/OrganizationFactory.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Organization;
+
+use App\Entity\Organization\Organization;
+use App\Tests\Fixture\Factory\Person\PersonRepository;
+use Zenstruck\Foundry\RepositoryProxy;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<Organization>
+ *
+ * @phpstan-method        Organization|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static Organization|Proxy createOne(array $attributes = [])
+ * @phpstan-method static Organization|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static Organization|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static Organization|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static Organization|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static Organization|Proxy random(array $attributes = [])
+ * @phpstan-method static Organization|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static OrganizationRepository|RepositoryProxy repository()
+ * @phpstan-method static Organization[]|Proxy[] all()
+ * @phpstan-method static Organization[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static Organization[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static Organization[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static Organization[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static Organization[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class OrganizationFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return Organization::class;
+    }
+}

+ 64 - 0
tests/Fixture/Factory/Organization/SettingsFactory.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Organization;
+
+use App\Entity\Organization\Settings;
+use App\Tests\Fixture\Factory\Person\PersonRepository;
+use Zenstruck\Foundry\RepositoryProxy;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<Settings>
+ *
+ * @phpstan-method        Settings|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static Settings|Proxy createOne(array $attributes = [])
+ * @phpstan-method static Settings|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static Settings|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static Settings|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static Settings|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static Settings|Proxy random(array $attributes = [])
+ * @phpstan-method static Settings|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static SettingsRepository|RepositoryProxy repository()
+ * @phpstan-method static Settings[]|Proxy[] all()
+ * @phpstan-method static Settings[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static Settings[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static Settings[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static Settings[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static Settings[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class SettingsFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return Settings::class;
+    }
+}

+ 63 - 0
tests/Fixture/Factory/Person/PersonFactory.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace App\Tests\Fixture\Factory\Person;
+
+use App\Entity\Person\Person;
+use Zenstruck\Foundry\RepositoryProxy;
+use Zenstruck\Foundry\ModelFactory;
+use Zenstruck\Foundry\Proxy;
+
+/**
+ * @extends ModelFactory<Person>
+ *
+ * @phpstan-method        Person|Proxy create(array|callable $attributes = [])
+ * @phpstan-method static Person|Proxy createOne(array $attributes = [])
+ * @phpstan-method static Person|Proxy find(object|array|mixed $criteria)
+ * @phpstan-method static Person|Proxy findOrCreate(array $attributes)
+ * @phpstan-method static Person|Proxy first(string $sortedField = 'id')
+ * @phpstan-method static Person|Proxy last(string $sortedField = 'id')
+ * @phpstan-method static Person|Proxy random(array $attributes = [])
+ * @phpstan-method static Person|Proxy randomOrCreate(array $attributes = []))
+ * @phpstan-method static PersonRepository|RepositoryProxy repository()
+ * @phpstan-method static Person[]|Proxy[] all()
+ * @phpstan-method static Person[]|Proxy[] createMany(int $number, array|callable $attributes = [])
+ * @phpstan-method static Person[]&Proxy[] createSequence(iterable|callable $sequence)
+ * @phpstan-method static Person[]|Proxy[] findBy(array $attributes)
+ * @phpstan-method static Person[]|Proxy[] randomRange(int $min, int $max, array $attributes = []))
+ * @phpstan-method static Person[]|Proxy[] randomSet(int $number, array $attributes = []))
+ */
+class PersonFactory extends ModelFactory
+{
+    /**
+     * @see https://github.com/zenstruck/foundry#factories-as-services
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#model-factories
+     *
+     * @todo add your default values here
+     */
+    protected function getDefaults(): array
+    {
+        return [];
+    }
+
+    /**
+     * @see https://github.com/zenstruck/foundry#initialization
+     */
+    protected function initialize(): self
+    {
+        return $this
+            // ->afterInstantiate(function(Post $post) {})
+            ;
+    }
+
+    protected static function getClass(): string
+    {
+        return Person::class;
+    }
+}

+ 34 - 0
tests/Fixture/PersonFixtures.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Tests\Fixture;
+
+use App\Entity\Booking\Event;
+use App\Entity\Core\ContactPoint;
+use App\Entity\Network\Network;
+use App\Entity\Network\NetworkOrganization;
+use App\Entity\Organization\Organization;
+use App\Entity\Organization\Parameters;
+use App\Entity\Person\Person;
+use App\Enum\Booking\VisibilityEnum;
+use App\Enum\Core\ContactPointTypeEnum;
+use App\Enum\Organization\LegalEnum;
+use App\Enum\Organization\PrincipalTypeEnum;
+use App\Tests\Fixture\Factory\Person\PersonFactory;
+use Doctrine\Bundle\FixturesBundle\Fixture;
+use Doctrine\Persistence\ObjectManager;
+use Symfony\Component\Serializer\Context\SerializerContextBuilder;
+use App\Service\Utils\Uuid;
+use Zenstruck\Foundry\Factory;
+
+class PersonFixtures extends Fixture
+{
+    public function load(ObjectManager $em): void
+    {
+        PersonFactory::createMany(10, static function() {
+            return [
+                'username' => Factory::faker()->name()
+            ];});
+
+        $em->flush();
+    }
+}