320 lines
11 KiB
PHP
320 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Service;
|
|
|
|
use App\Entity\Apps;
|
|
use App\Entity\Organizations;
|
|
use App\Entity\Roles;
|
|
use App\Entity\User;
|
|
use App\Entity\UserOrganizatonApp;
|
|
use App\Entity\UsersOrganizations;
|
|
use App\Service\ActionService;
|
|
use App\Service\LoggerService;
|
|
use App\Service\UserOrganizationAppService;
|
|
use App\Service\UserService;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Doctrine\ORM\EntityRepository;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Bundle\SecurityBundle\Security;
|
|
|
|
class UserOrganizationAppServiceTest extends TestCase
|
|
{
|
|
private UserOrganizationAppService $service;
|
|
|
|
// Mocks
|
|
private MockObject|EntityManagerInterface $entityManager;
|
|
private MockObject|ActionService $actionService;
|
|
private MockObject|Security $security;
|
|
private MockObject|UserService $userService;
|
|
private MockObject|LoggerInterface $psrLogger;
|
|
private MockObject|LoggerService $loggerService;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->entityManager = $this->createMock(EntityManagerInterface::class);
|
|
$this->actionService = $this->createMock(ActionService::class);
|
|
$this->security = $this->createMock(Security::class);
|
|
$this->userService = $this->createMock(UserService::class);
|
|
$this->psrLogger = $this->createMock(LoggerInterface::class);
|
|
$this->loggerService = $this->createMock(LoggerService::class);
|
|
|
|
$this->service = new UserOrganizationAppService(
|
|
$this->entityManager,
|
|
$this->actionService,
|
|
$this->security,
|
|
$this->userService,
|
|
$this->psrLogger,
|
|
$this->loggerService
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Helper to set private ID property on entities.
|
|
*/
|
|
private function setEntityId(object $entity, int $id): void
|
|
{
|
|
$reflection = new \ReflectionClass($entity);
|
|
if ($reflection->hasProperty('id')) {
|
|
$property = $reflection->getProperty('id');
|
|
// $property->setAccessible(true); // Needed for PHP < 8.1
|
|
$property->setValue($entity, $id);
|
|
}
|
|
}
|
|
|
|
// ==========================================
|
|
// TEST: groupUserOrganizationAppsByApplication
|
|
// ==========================================
|
|
|
|
public function testGroupUserOrganizationAppsByApplication(): void
|
|
{
|
|
// 1. Setup Apps
|
|
$app1 = new Apps(); $this->setEntityId($app1, 1);
|
|
$app2 = new Apps(); $this->setEntityId($app2, 2); // No roles for this one
|
|
|
|
// 2. Setup Existing Link
|
|
$role = new Roles(); $this->setEntityId($role, 10);
|
|
|
|
$uo = new UsersOrganizations(); $this->setEntityId($uo, 99);
|
|
|
|
$uoa = new UserOrganizatonApp();
|
|
$this->setEntityId($uoa, 500);
|
|
$uoa->setApplication($app1);
|
|
$uoa->setRole($role);
|
|
$uoa->setUserOrganization($uo);
|
|
|
|
// 3. Run
|
|
$result = $this->service->groupUserOrganizationAppsByApplication(
|
|
[$uoa],
|
|
[$app1, $app2],
|
|
null
|
|
);
|
|
|
|
// 4. Assert
|
|
$this->assertArrayHasKey(1, $result);
|
|
$this->assertArrayHasKey(2, $result);
|
|
|
|
// Check App 1 (Has existing link)
|
|
$this->assertEquals(99, $result[1]['uoId']);
|
|
$this->assertEquals([10], $result[1]['selectedRoleIds']);
|
|
|
|
// Check App 2 (Empty default)
|
|
$this->assertNull($result[2]['uoId']);
|
|
$this->assertEmpty($result[2]['selectedRoleIds']);
|
|
}
|
|
|
|
// ==========================================
|
|
// TEST: deactivateAllUserOrganizationsAppLinks
|
|
// ==========================================
|
|
|
|
public function testDeactivateAllLinksSuccess(): void
|
|
{
|
|
$uo = new UsersOrganizations();
|
|
$user = new User();
|
|
$org = new Organizations();
|
|
$uo->setUsers($user);
|
|
$uo->setOrganization($org);
|
|
|
|
$app = new Apps();
|
|
$this->setEntityId($app, 1);
|
|
$role = new Roles();
|
|
$this->setEntityId($role, 10);
|
|
|
|
$uoa = new UserOrganizatonApp();
|
|
$this->setEntityId($uoa, 555);
|
|
$uoa->setApplication($app);
|
|
$uoa->setRole($role);
|
|
$uoa->setIsActive(true);
|
|
|
|
// Mock Repository
|
|
$repo = $this->createMock(EntityRepository::class);
|
|
$repo->method('findBy')->willReturn([$uoa]);
|
|
$this->entityManager->method('getRepository')->willReturn($repo);
|
|
|
|
// Expectations
|
|
$this->actionService->expects($this->once())->method('createAction');
|
|
$this->entityManager->expects($this->once())->method('persist')->with($uoa);
|
|
$this->loggerService->expects($this->once())->method('logUOALinkDeactivated');
|
|
|
|
$this->service->deactivateAllUserOrganizationsAppLinks($uo, null);
|
|
|
|
$this->assertFalse($uoa->isActive());
|
|
}
|
|
|
|
public function testDeactivateHandlesException(): void
|
|
{
|
|
$uo = new UsersOrganizations();
|
|
|
|
// The service needs a User to create an Action log
|
|
$user = new User();
|
|
$this->setEntityId($user, 99);
|
|
$uo->setUsers($user); // <--- Assign the user!
|
|
|
|
// Also needs an Org for the Action log
|
|
$org = new Organizations();
|
|
$this->setEntityId($org, 88);
|
|
$uo->setOrganization($org);
|
|
|
|
$app = new Apps(); $this->setEntityId($app, 1);
|
|
$role = new Roles(); $this->setEntityId($role, 1);
|
|
|
|
$realUoa = new UserOrganizatonApp();
|
|
$this->setEntityId($realUoa, 100);
|
|
$realUoa->setApplication($app);
|
|
$realUoa->setRole($role);
|
|
$realUoa->setIsActive(true);
|
|
|
|
$repo = $this->createMock(EntityRepository::class);
|
|
$repo->method('findBy')->willReturn([$realUoa]);
|
|
$this->entityManager->method('getRepository')->willReturn($repo);
|
|
|
|
// Throw exception on persist
|
|
$this->entityManager->method('persist')->willThrowException(new \Exception('DB Error'));
|
|
|
|
// Expect Logger Critical
|
|
$this->loggerService->expects($this->once())->method('logCritical');
|
|
|
|
$this->service->deactivateAllUserOrganizationsAppLinks($uo);
|
|
}
|
|
|
|
// ==========================================
|
|
// TEST: syncRolesForUserOrganizationApp
|
|
// ==========================================
|
|
|
|
public function testSyncRolesAddsNewRole(): void
|
|
{
|
|
// Setup
|
|
$actingUser = new User(); $this->setEntityId($actingUser, 1);
|
|
$targetUser = new User(); $this->setEntityId($targetUser, 2);
|
|
|
|
$org = new Organizations(); $this->setEntityId($org, 10);
|
|
$uo = new UsersOrganizations();
|
|
$uo->setOrganization($org);
|
|
$uo->setUsers($targetUser);
|
|
|
|
$app = new Apps(); $this->setEntityId($app, 5);
|
|
$app->setName('App1');
|
|
|
|
$roleId = 20;
|
|
$role = new Roles();
|
|
$role->setName('EDITOR');
|
|
$this->setEntityId($role, $roleId);
|
|
|
|
// Mock Repositories
|
|
$uoaRepo = $this->createMock(EntityRepository::class);
|
|
$uoaRepo->method('findBy')->willReturn([]); // No existing roles
|
|
|
|
$roleRepo = $this->createMock(EntityRepository::class);
|
|
$roleRepo->method('find')->with($roleId)->willReturn($role);
|
|
|
|
$this->entityManager->method('getRepository')->willReturnMap([
|
|
[UserOrganizatonApp::class, $uoaRepo],
|
|
[Roles::class, $roleRepo],
|
|
]);
|
|
|
|
// Expect creation
|
|
$this->entityManager->expects($this->once())->method('persist')->with($this->isInstanceOf(UserOrganizatonApp::class));
|
|
$this->entityManager->expects($this->once())->method('flush');
|
|
$this->actionService->expects($this->once())->method('createAction');
|
|
|
|
// Run
|
|
$this->service->syncRolesForUserOrganizationApp($uo, $app, [(string)$roleId], $actingUser);
|
|
}
|
|
|
|
public function testSyncRolesDeactivatesUnselectedRole(): void
|
|
{
|
|
$actingUser = new User(); $this->setEntityId($actingUser, 1);
|
|
$targetUser = new User(); $this->setEntityId($targetUser, 2);
|
|
$org = new Organizations(); $this->setEntityId($org, 10);
|
|
|
|
$uo = new UsersOrganizations();
|
|
$uo->setOrganization($org);
|
|
$uo->setUsers($targetUser);
|
|
|
|
$app = new Apps(); $this->setEntityId($app, 5);
|
|
$app->setName('App1');
|
|
|
|
// Existing active role
|
|
$role = new Roles(); $this->setEntityId($role, 30);
|
|
$role->setName('VIEWER');
|
|
|
|
$existingUoa = new UserOrganizatonApp();
|
|
$this->setEntityId($existingUoa, 999);
|
|
$existingUoa->setRole($role);
|
|
$existingUoa->setApplication($app);
|
|
$existingUoa->setUserOrganization($uo);
|
|
$existingUoa->setIsActive(true);
|
|
|
|
// Repos
|
|
$uoaRepo = $this->createMock(EntityRepository::class);
|
|
$uoaRepo->method('findBy')->willReturn([$existingUoa]);
|
|
|
|
$this->entityManager->method('getRepository')->willReturnMap([
|
|
[UserOrganizatonApp::class, $uoaRepo],
|
|
]);
|
|
|
|
// We pass empty array [] as selected roles -> expect deactivation
|
|
$this->service->syncRolesForUserOrganizationApp($uo, $app, [], $actingUser);
|
|
|
|
$this->assertFalse($existingUoa->isActive());
|
|
}
|
|
|
|
public function testSyncRolesHandlesSuperAdminLogic(): void
|
|
{
|
|
// Setup
|
|
$actingUser = new User(); $this->setEntityId($actingUser, 1);
|
|
$targetUser = new User(); $this->setEntityId($targetUser, 2);
|
|
$uo = new UsersOrganizations();
|
|
$uo->setUsers($targetUser);
|
|
|
|
$org = new Organizations();
|
|
$this->setEntityId($org, 500); // <--- Give the Org an ID!
|
|
$uo->setOrganization($org);
|
|
|
|
$app = new Apps(); $this->setEntityId($app, 1);
|
|
$app->setName('Portal');
|
|
|
|
// Roles
|
|
$superAdminRole = new Roles();
|
|
$superAdminRole->setName('SUPER ADMIN');
|
|
$this->setEntityId($superAdminRole, 100);
|
|
|
|
$adminRole = new Roles();
|
|
$adminRole->setName('ADMIN');
|
|
$this->setEntityId($adminRole, 101);
|
|
|
|
// Repositories Configuration
|
|
$uoaRepo = $this->createMock(EntityRepository::class);
|
|
// 1. findBy (initial check) -> returns empty
|
|
// 2. findOneBy (inside ensureAdminRoleForSuperAdmin) -> returns null (Admin link doesn't exist yet)
|
|
$uoaRepo->method('findBy')->willReturn([]);
|
|
$uoaRepo->method('findOneBy')->willReturn(null);
|
|
|
|
$roleRepo = $this->createMock(EntityRepository::class);
|
|
$roleRepo->method('find')->with(100)->willReturn($superAdminRole);
|
|
$roleRepo->method('findOneBy')->with(['name' => 'ADMIN'])->willReturn($adminRole);
|
|
|
|
$this->entityManager->method('getRepository')->willReturnMap([
|
|
[UserOrganizatonApp::class, $uoaRepo],
|
|
[Roles::class, $roleRepo],
|
|
]);
|
|
|
|
// Expectations
|
|
|
|
// 1. UserService should be called to sync SUPER ADMIN
|
|
$this->userService->expects($this->once())
|
|
->method('syncUserRoles')
|
|
->with($targetUser, 'SUPER ADMIN', true);
|
|
|
|
// 2. EntityManager should persist:
|
|
// - The new SUPER ADMIN link
|
|
// - The new ADMIN link (automatically created)
|
|
$this->entityManager->expects($this->exactly(2))
|
|
->method('persist')
|
|
->with($this->isInstanceOf(UserOrganizatonApp::class));
|
|
|
|
// Run
|
|
$this->service->syncRolesForUserOrganizationApp($uo, $app, ['100'], $actingUser);
|
|
}
|
|
} |