refs #451. Testing OrganizationalUnit, and partial Client

pull/7/head
Manuel Aranda Rosales 2024-06-12 16:46:35 +02:00
parent a5d37d5092
commit f3e19eb8ee
8 changed files with 307 additions and 9 deletions

View File

@ -3,6 +3,7 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\HardwareProfileOutput;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Entity\Client;
use Symfony\Component\Serializer\Annotation\Groups;
@ -43,6 +44,11 @@ final class ClientInput
#[ApiProperty(description: 'The organizational unit of the client')]
public ?OrganizationalUnitOutput $organizationalUnit = null;
#[Assert\NotNull]
#[Groups(['client:write', 'client:patch'])]
#[ApiProperty(description: 'The hardware profile of the client')]
public ?HardwareProfileOutput $hardwareProfile = null;
public function __construct(?Client $client = null)
{
if (!$client) {
@ -53,6 +59,7 @@ final class ClientInput
$this->serialNumber = $client->getSerialNumber();
$this->netiface = $client->getNetiface();
$this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit());
$this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile());
$this->netDriver = $client->getNetDriver();
$this->mac = $client->getMac();
$this->ip = $client->getIp();
@ -69,6 +76,7 @@ final class ClientInput
$client->setSerialNumber($this->serialNumber);
$client->setNetiface($this->netiface);
$client->setOrganizationalUnit($this->organizationalUnit->getEntity());
$client->setHardwareProfile($this->hardwareProfile->getEntity());
$client->setNetDriver($this->netDriver);
$client->setMac($this->mac);
$client->setIp($this->ip);

View File

@ -21,6 +21,9 @@ final class ClientOutput extends AbstractOutput
#[Groups(['client:read'])]
public ?OrganizationalUnitOutput $organizationalUnit = null;
#[Groups(['client:read'])]
public ?HardwareProfileOutput $hardwareProfile = null;
#[Groups(['client:read'])]
public \DateTime $createAt;
@ -34,7 +37,12 @@ final class ClientOutput extends AbstractOutput
$this->name = $client->getName();
$this->serialNumber = $client->getSerialNumber();
$this->netiface = $client->getNetiface();
$this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit());
if ($client->getOrganizationalUnit()) {
$this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit());
}
if($client->getHardwareProfile()) {
$this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile());
}
$this->createAt = $client->getCreatedAt();
$this->createBy = $client->getCreatedBy();
}

View File

@ -12,6 +12,9 @@ final class OrganizationalUnitOutput extends AbstractOutput
#[Groups(['organizational-unit:read'])]
public string $name;
#[Groups(['organizational-unit:read'])]
public ?string $comments = null;
#[Groups(['organizational-unit:read'])]
public string $type;
@ -39,6 +42,7 @@ final class OrganizationalUnitOutput extends AbstractOutput
parent::__construct($organizationalUnit);
$this->name = $organizationalUnit->getName();
$this->comments = $organizationalUnit->getComments();
$this->type = $organizationalUnit->getType();
$this->networkSettings = $organizationalUnit->getNetworkSettings() ? new NetworkSettingsOutput($organizationalUnit->getNetworkSettings()) : null;
$this->clients = $organizationalUnit->getClients()->toArray();

View File

@ -0,0 +1,57 @@
<?php
namespace App\Factory;
use App\Entity\Client;
use Zenstruck\Foundry\ModelFactory;
use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;
/**
* @extends ModelFactory<Client>
*/
final class ClientFactory extends ModelFactory
{
/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
*
* @todo inject services if required
*/
public function __construct()
{
parent::__construct();
}
public static function class(): string
{
return Client::class;
}
/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
*
* @todo add your default values here
*/
protected function getDefaults(): array
{
return [
'createdAt' => self::faker()->dateTime(),
'name' => self::faker()->text(255),
'updatedAt' => self::faker()->dateTime(),
];
}
/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
*/
protected function initialize(): self
{
return $this
// ->afterInstantiate(function(Client $client): void {})
;
}
protected static function getClass(): string
{
return Client::class;
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace App\Factory;
use App\Entity\HardwareProfile;
use Zenstruck\Foundry\ModelFactory;
use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;
/**
* @extends ModelFactory<HardwareProfile>
*/
final class HardwareProfileFactory extends ModelFactory
{
/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
*
* @todo inject services if required
*/
public function __construct()
{
parent::__construct();
}
public static function class(): string
{
return HardwareProfile::class;
}
/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
*
* @todo add your default values here
*/
protected function getDefaults(): array
{
return [
'createdAt' => self::faker()->dateTime(),
'updatedAt' => self::faker()->dateTime(),
'description' => self::faker()->text(255),
];
}
/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
*/
protected function initialize(): self
{
return $this
// ->afterInstantiate(function(HardwareProfile $hardwareProfile): void {})
;
}
protected static function getClass(): string
{
return HardwareProfile::class;
}
}

View File

@ -0,0 +1,115 @@
<?php
namespace Functional;
use App\Entity\Client;
use App\Entity\HardwareProfile;
use App\Entity\OrganizationalUnit;
use App\Entity\UserGroup;
use App\Factory\ClientFactory;
use App\Factory\HardwareProfileFactory;
use App\Factory\OrganizationalUnitFactory;
use App\Factory\UserFactory;
use App\Factory\UserGroupFactory;
use App\Model\OrganizationalUnitTypes;
use App\Model\UserGroupPermissions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class ClientTest extends AbstractTest
{
CONST string USER_ADMIN = 'ogadmin';
CONST string CLIENT_CREATE = 'test-client-create';
CONST string CLIENT_UPDATE = 'test-client-update';
CONST string CLIENT_DELETE = 'test-client-delete';
const string HW_PROFILE = 'HW Test';
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
*/
public function testGetCollectionClients(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
ClientFactory::createMany(10);
$this->createClientWithCredentials()->request('GET', '/clients');
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/contexts/Client',
'@id' => '/clients',
'@type' => 'hydra:Collection',
'hydra:totalItems' => 10,
]);
}
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
*/
public function testCreateClient(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]);
$ouIri = $this->findIriBy(OrganizationalUnit::class, ['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]);
HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]);
$hpIri = $this->findIriBy(HardwareProfile::class, ['description' => self::HW_PROFILE]);
$this->createClientWithCredentials()->request('POST', '/clients',['json' => [
'name' => self::CLIENT_CREATE,
'organizationalUnit' => $ouIri,
'hardwareProfile' => $hpIri,
'serialNumber' => '123abc',
]]);
$this->assertResponseStatusCodeSame(201);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/contexts/ClientOutput',
'@type' => 'Client',
'name' => self::CLIENT_CREATE,
'serialNumber' => '123abc',
]);
}
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
*/
public function testUpdateUserGroup(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
ClientFactory::createOne(['name' => self::CLIENT_UPDATE, 'serialNumber' => '123abc']);
$iri = $this->findIriBy(Client::class, ['name' => self::CLIENT_UPDATE]);
$this->createClientWithCredentials()->request('PUT', $iri, ['json' => [
'name' => self::CLIENT_UPDATE,
'serialNumber' => '987zyx'
]]);
$this->assertResponseIsSuccessful();
$this->assertJsonContains([
'@id' => $iri,
'name' => self::CLIENT_UPDATE,
'serialNumber' => '987zyx'
]);
}
}

View File

@ -2,6 +2,8 @@
namespace Functional;
use App\Entity\OrganizationalUnit;
use App\Entity\UserGroup;
use App\Factory\OrganizationalUnitFactory;
use App\Factory\UserFactory;
use App\Model\OrganizationalUnitTypes;
@ -16,8 +18,9 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class OrganizationalUnitTest extends AbstractTest
{
CONST string USER_ADMIN = 'ogadmin';
CONST string ORGANIZATIONAL_UNIT_CREATE = 'test-organizational-unit-create';
CONST string ORGANIZATIONAL_UNIT_UPDATE = 'test-organizational-unit-update';
CONST string ORGANIZATIONAL_UNIT_DELETE = 'test-organizational-unit-delete';
/**
* @throws RedirectionExceptionInterface
@ -145,4 +148,52 @@ class OrganizationalUnitTest extends AbstractTest
'type' => OrganizationalUnitTypes::CLIENTS_GROUP,
]);
}
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
*/
public function testUpdateOrganizationalUnit(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
OrganizationalUnitFactory::createOne(['name' => self::ORGANIZATIONAL_UNIT_CREATE, 'type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]);
$iri = $this->findIriBy(OrganizationalUnit::class, ['name' => self::ORGANIZATIONAL_UNIT_CREATE]);
$this->createClientWithCredentials()->request('PUT', $iri, ['json' => [
'name' => self::ORGANIZATIONAL_UNIT_UPDATE,
'comments' => 'comments',
]]);
$this->assertResponseIsSuccessful();
$this->assertJsonContains([
'@id' => $iri,
'name' => self::ORGANIZATIONAL_UNIT_UPDATE,
'comments' => 'comments'
]);
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
*/
public function testDeleteOrganizationalUnit(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
OrganizationalUnitFactory::createOne(['name' => self::ORGANIZATIONAL_UNIT_DELETE, 'type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]);
$iri = $this->findIriBy(OrganizationalUnit::class, ['name' => self::ORGANIZATIONAL_UNIT_DELETE]);
$this->createClientWithCredentials()->request('DELETE', $iri);
$this->assertResponseStatusCodeSame(204);
$this->assertNull(
static::getContainer()->get('doctrine')->getRepository(UserGroup::class)->findOneBy(['name' => self::ORGANIZATIONAL_UNIT_DELETE])
);
}
}

View File

@ -2,7 +2,6 @@
namespace Functional;
use App\Entity\User;
use App\Entity\UserGroup;
use App\Factory\UserFactory;
use App\Factory\UserGroupFactory;
@ -16,12 +15,11 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class UserGroupTest extends AbstractTest
{
CONST USER_ADMIN = 'ogadmin';
CONST USER_GROUP_CREATE = 'test-user-group-create';
CONST USER_GROUP_UPDATE = 'test-user-group-update';
CONST USER_GROUP_DELETE = 'test-user-group-delete';
CONST ROLE_ORGANIZATIONAL_UNIT_ADMIN = 'ROLE_ORGANIZATIONAL_UNIT_ADMIN';
CONST string USER_ADMIN = 'ogadmin';
CONST string USER_GROUP_CREATE = 'test-user-group-create';
CONST string USER_GROUP_UPDATE = 'test-user-group-update';
CONST string USER_GROUP_DELETE = 'test-user-group-delete';
CONST string ROLE_ORGANIZATIONAL_UNIT_ADMIN = 'ROLE_ORGANIZATIONAL_UNIT_ADMIN';
/**
* @throws RedirectionExceptionInterface