Organization service test
This commit is contained in:
parent
30901335d9
commit
fdf52465fe
|
|
@ -0,0 +1,271 @@
|
|||
<?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\Repository\UsersOrganizationsRepository;
|
||||
use App\Service\AwsService;
|
||||
use App\Service\LoggerService;
|
||||
use App\Service\NotificationService;
|
||||
use App\Service\OrganizationsService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
class OrganizationsServiceTest extends TestCase
|
||||
{
|
||||
private OrganizationsService $service;
|
||||
|
||||
// Mocks
|
||||
private MockObject|AwsService $awsService;
|
||||
private MockObject|EntityManagerInterface $entityManager;
|
||||
private MockObject|UsersOrganizationsRepository $uoRepository;
|
||||
private MockObject|NotificationService $notificationService;
|
||||
private MockObject|LoggerInterface $emailNotificationLogger;
|
||||
private MockObject|LoggerService $loggerService;
|
||||
|
||||
private string $logoDirectory = '/tmp/logos';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->awsService = $this->createMock(AwsService::class);
|
||||
$this->entityManager = $this->createMock(EntityManagerInterface::class);
|
||||
$this->uoRepository = $this->createMock(UsersOrganizationsRepository::class);
|
||||
$this->notificationService = $this->createMock(NotificationService::class);
|
||||
$this->emailNotificationLogger = $this->createMock(LoggerInterface::class);
|
||||
$this->loggerService = $this->createMock(LoggerService::class);
|
||||
|
||||
// Set the ENV variable used in the service
|
||||
$_ENV['S3_PORTAL_BUCKET'] = 'test-bucket';
|
||||
|
||||
$this->service = new OrganizationsService(
|
||||
$this->logoDirectory,
|
||||
$this->awsService,
|
||||
$this->entityManager,
|
||||
$this->uoRepository,
|
||||
$this->notificationService,
|
||||
$this->emailNotificationLogger,
|
||||
$this->loggerService
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to set private ID property via Reflection
|
||||
*/
|
||||
private function setEntityId(object $entity, int $id): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($entity);
|
||||
if ($reflection->hasProperty('id')) {
|
||||
$property = $reflection->getProperty('id');
|
||||
// $property->setAccessible(true); // PHP < 8.1
|
||||
$property->setValue($entity, $id);
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// TEST: handleLogo
|
||||
// ==========================================
|
||||
|
||||
public function testHandleLogoSuccess(): void
|
||||
{
|
||||
$org = new Organizations();
|
||||
$this->setEntityId($org, 1);
|
||||
$org->setName('MyOrg');
|
||||
|
||||
$file = $this->createMock(UploadedFile::class);
|
||||
$file->method('guessExtension')->willReturn('png');
|
||||
|
||||
// Expect AWS Upload
|
||||
$this->awsService->expects($this->once())
|
||||
->method('PutDocObj')
|
||||
->with(
|
||||
'test-bucket',
|
||||
$file,
|
||||
$this->stringContains('MyOrg_'), // Filename check
|
||||
'png',
|
||||
'logo/'
|
||||
);
|
||||
|
||||
// Expect Log
|
||||
$this->loggerService->expects($this->once())->method('logAWSAction');
|
||||
|
||||
$this->service->handleLogo($org, $file);
|
||||
|
||||
// Assert URL is set on entity
|
||||
$this->assertStringContainsString('logo/MyOrg_', $org->getLogoUrl());
|
||||
}
|
||||
|
||||
public function testHandleLogoThrowsException(): void
|
||||
{
|
||||
$org = new Organizations();
|
||||
$this->setEntityId($org, 1);
|
||||
$org->setName('MyOrg');
|
||||
|
||||
$file = $this->createMock(UploadedFile::class);
|
||||
$file->method('guessExtension')->willReturn('png');
|
||||
|
||||
// Simulate AWS Failure
|
||||
$this->awsService->method('PutDocObj')
|
||||
->willThrowException(new FileException('S3 Down'));
|
||||
|
||||
// Expect Error Log
|
||||
$this->loggerService->expects($this->once())
|
||||
->method('logError')
|
||||
->with('Failed to upload organization logo to S3', $this->anything());
|
||||
|
||||
$this->expectException(FileException::class);
|
||||
$this->expectExceptionMessage('Failed to upload logo to S3: S3 Down');
|
||||
|
||||
$this->service->handleLogo($org, $file);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// TEST: appsAccess
|
||||
// ==========================================
|
||||
|
||||
public function testAppsAccess(): void
|
||||
{
|
||||
$app1 = new Apps(); $this->setEntityId($app1, 10);
|
||||
$app2 = new Apps(); $this->setEntityId($app2, 20);
|
||||
$app3 = new Apps(); $this->setEntityId($app3, 30);
|
||||
|
||||
$allApps = [$app1, $app2, $app3];
|
||||
$orgApps = [$app2]; // Org only has access to App 2
|
||||
|
||||
$result = $this->service->appsAccess($allApps, $orgApps);
|
||||
|
||||
$this->assertCount(3, $result);
|
||||
|
||||
// App 1 -> False
|
||||
$this->assertSame($app1, $result[0]['entity']);
|
||||
$this->assertFalse($result[0]['hasAccess']);
|
||||
|
||||
// App 2 -> True
|
||||
$this->assertSame($app2, $result[1]['entity']);
|
||||
$this->assertTrue($result[1]['hasAccess']);
|
||||
|
||||
// App 3 -> False
|
||||
$this->assertSame($app3, $result[2]['entity']);
|
||||
$this->assertFalse($result[2]['hasAccess']);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// TEST: notifyOrganizationAdmins
|
||||
// ==========================================
|
||||
|
||||
public function testNotifyOrganizationAdminsUserAccepted(): void
|
||||
{
|
||||
// 1. Setup Data
|
||||
$targetUser = new User(); $this->setEntityId($targetUser, 100);
|
||||
|
||||
$adminUser = new User(); $this->setEntityId($adminUser, 999);
|
||||
|
||||
$org = new Organizations(); $this->setEntityId($org, 50);
|
||||
|
||||
$data = ['user' => $targetUser, 'organization' => $org];
|
||||
|
||||
// 2. Setup Admin Link (The user who IS admin)
|
||||
$adminUO = new UsersOrganizations();
|
||||
$this->setEntityId($adminUO, 555);
|
||||
$adminUO->setUsers($adminUser);
|
||||
$adminUO->setOrganization($org);
|
||||
|
||||
// 3. Setup Role Logic
|
||||
$adminRole = new Roles(); $this->setEntityId($adminRole, 1);
|
||||
$adminRole->setName('ADMIN');
|
||||
|
||||
// 4. Setup UOA Logic (Proof that user is Admin of an App)
|
||||
$uoa = new UserOrganizatonApp();
|
||||
$this->setEntityId($uoa, 777);
|
||||
$uoa->setUserOrganization($adminUO);
|
||||
$uoa->setRole($adminRole);
|
||||
$uoa->setIsActive(true);
|
||||
|
||||
// 5. Mocks
|
||||
// Mock Roles Repo
|
||||
$rolesRepo = $this->createMock(EntityRepository::class);
|
||||
$rolesRepo->method('findOneBy')->with(['name' => 'ADMIN'])->willReturn($adminRole);
|
||||
|
||||
// Mock UO Repo (Find potential admins in org)
|
||||
$this->uoRepository->expects($this->once())
|
||||
->method('findBy')
|
||||
->with(['organization' => $org, 'isActive' => true])
|
||||
->willReturn([$adminUO]);
|
||||
|
||||
// Mock UOA Repo (Check if they have ADMIN role)
|
||||
$uoaRepo = $this->createMock(EntityRepository::class);
|
||||
$uoaRepo->method('findOneBy')->willReturn($uoa);
|
||||
|
||||
$this->entityManager->method('getRepository')->willReturnMap([
|
||||
[Roles::class, $rolesRepo],
|
||||
[UserOrganizatonApp::class, $uoaRepo],
|
||||
]);
|
||||
|
||||
// 6. Expectations
|
||||
$this->notificationService->expects($this->once())
|
||||
->method('notifyUserAcceptedInvite')
|
||||
->with($adminUser, $targetUser, $org);
|
||||
|
||||
$this->loggerService->expects($this->once())
|
||||
->method('logAdminNotified')
|
||||
->with([
|
||||
'admin_user_id' => 999,
|
||||
'target_user_id' => 100,
|
||||
'organization_id' => 50,
|
||||
'case' => 'USER_ACCEPTED'
|
||||
]);
|
||||
|
||||
// 7. Run
|
||||
$result = $this->service->notifyOrganizationAdmins($data, 'USER_ACCEPTED');
|
||||
|
||||
// The service returns the last admin UO processed (based on loop)
|
||||
$this->assertSame($adminUO, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test ensures that if the admin is the SAME person as the target user,
|
||||
* they do not get notified (Skip Self Check).
|
||||
*/
|
||||
public function testNotifyOrganizationAdminsSkipsSelf(): void
|
||||
{
|
||||
$user = new User(); $this->setEntityId($user, 100);
|
||||
$org = new Organizations(); $this->setEntityId($org, 50);
|
||||
|
||||
// Admin IS the user
|
||||
$adminUO = new UsersOrganizations();
|
||||
$adminUO->setUsers($user);
|
||||
|
||||
$roleAdmin = new Roles();
|
||||
|
||||
$uoa = new UserOrganizatonApp(); // active admin link
|
||||
|
||||
// Mocks setup
|
||||
$rolesRepo = $this->createMock(EntityRepository::class);
|
||||
$rolesRepo->method('findOneBy')->willReturn($roleAdmin);
|
||||
|
||||
$this->uoRepository->method('findBy')->willReturn([$adminUO]);
|
||||
|
||||
$uoaRepo = $this->createMock(EntityRepository::class);
|
||||
$uoaRepo->method('findOneBy')->willReturn($uoa);
|
||||
|
||||
$this->entityManager->method('getRepository')->willReturnMap([
|
||||
[Roles::class, $rolesRepo],
|
||||
[UserOrganizatonApp::class, $uoaRepo],
|
||||
]);
|
||||
|
||||
// Expectations: Notification service should NEVER be called
|
||||
$this->notificationService->expects($this->never())->method('notifyUserAcceptedInvite');
|
||||
$this->loggerService->expects($this->never())->method('logAdminNotified');
|
||||
|
||||
$this->service->notifyOrganizationAdmins(['user' => $user, 'organization' => $org], 'USER_ACCEPTED');
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue