451 lines
14 KiB
PHP
451 lines
14 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Controllers\RestAuthenticationController;
|
|
use App\Models\AuthHistoryModel;
|
|
use App\Models\LevelContactModel;
|
|
use CodeIgniter\HTTP\IncomingRequest;
|
|
use CodeIgniter\HTTP\ResponseInterface;
|
|
use CodeIgniter\HTTP\URI;
|
|
use CodeIgniter\Test\CIUnitTestCase;
|
|
use Config\Database as DatabaseConfig;
|
|
use Config\Services;
|
|
use ReflectionClass;
|
|
use ReflectionProperty;
|
|
|
|
class GetVerifiedHrDataTest extends CIUnitTestCase
|
|
{
|
|
private string $jwtSecret = 'test-secret-key-for-get-verified-hr-data';
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
putenv("JWT_SECRET={$this->jwtSecret}");
|
|
$_ENV['JWT_SECRET'] = $this->jwtSecret;
|
|
$_SERVER['JWT_SECRET'] = $this->jwtSecret;
|
|
|
|
putenv('POST_ENROLLMENT_BASEURL=http://example.com/');
|
|
$_ENV['POST_ENROLLMENT_BASEURL'] = 'http://example.com/';
|
|
|
|
$this->mockCurlRequest(['ok' => true, 'source' => 'post_enrollment']);
|
|
$this->mockRateLimiter();
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
$this->clearInjectedDbConnections();
|
|
Services::reset(true);
|
|
|
|
putenv('JWT_SECRET');
|
|
putenv('POST_ENROLLMENT_BASEURL');
|
|
unset(
|
|
$_ENV['JWT_SECRET'],
|
|
$_SERVER['JWT_SECRET'],
|
|
$_ENV['POST_ENROLLMENT_BASEURL']
|
|
);
|
|
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function testInvalidOtpReturnsFailed404()
|
|
{
|
|
$hrModel = $this->createHrModelStub([
|
|
'first' => null,
|
|
'findAll' => [],
|
|
]);
|
|
|
|
$controller = $this->buildController(
|
|
['email' => 'hr@example.com', 'otp' => '000000'],
|
|
$hrModel
|
|
);
|
|
|
|
$body = $this->decodeResponse($controller->getVerifiedHrData());
|
|
|
|
$this->assertSame('failed', $body['status']);
|
|
$this->assertSame(404, $body['code']);
|
|
$this->assertSame('', $body['data']);
|
|
$this->assertSame(['ok' => true, 'source' => 'post_enrollment'], $body['post_enrollment']);
|
|
}
|
|
|
|
public function testValidOtpWithNoActiveBranchesReturnsFailed404()
|
|
{
|
|
$hrModel = $this->createHrModelStub([
|
|
'first' => ['id' => 5, 'email' => 'hr@example.com', 'mobile' => '9876543210'],
|
|
'findAll' => [],
|
|
'update' => true,
|
|
]);
|
|
|
|
$authHistoryModel = $this->createMock(AuthHistoryModel::class);
|
|
$authHistoryModel->expects($this->once())->method('insert');
|
|
|
|
$controller = $this->buildController(
|
|
['email' => 'hr@example.com', 'otp' => '123456'],
|
|
$hrModel,
|
|
$authHistoryModel
|
|
);
|
|
|
|
$body = $this->decodeResponse($controller->getVerifiedHrData());
|
|
|
|
$this->assertSame('failed', $body['status']);
|
|
$this->assertSame(404, $body['code']);
|
|
$this->assertSame('', $body['data']);
|
|
}
|
|
|
|
public function testValidMobileOtpReturnsSuccessWithClaimsSubMenu()
|
|
{
|
|
$branchRow = [
|
|
'id' => 5,
|
|
'mobile' => '9876543210',
|
|
'email' => 'hr@example.com',
|
|
'client_id' => 42,
|
|
'client_name' => 'Acme Corp',
|
|
'short_name' => 'ACME',
|
|
'client_branch_id' => 7,
|
|
'branch_name' => 'HQ',
|
|
'post_branch_id' => 70,
|
|
];
|
|
|
|
$hrModel = $this->createHrModelStub([
|
|
'first' => ['id' => 5, 'email' => 'hr@example.com', 'mobile' => '9876543210'],
|
|
'findAll' => [$branchRow],
|
|
'update' => true,
|
|
]);
|
|
|
|
$authHistoryModel = $this->createMock(AuthHistoryModel::class);
|
|
$authHistoryModel->expects($this->once())->method('insert');
|
|
|
|
$this->injectDbConnection('postDB', $this->createQueryResultStub([
|
|
'pre_client_id' => 42,
|
|
'post_client_id' => 420,
|
|
'pre_branch_id' => 7,
|
|
'pre_hr_id' => 5,
|
|
'allowed_modules' => json_encode(['post' => [1, 4, 5]]),
|
|
'allowed_active_policies' => json_encode([101, 102]),
|
|
]));
|
|
|
|
$this->injectDbConnection('tests', $this->createQueryResultStub(
|
|
null,
|
|
[
|
|
['allocg' => 'EB'],
|
|
['allocg' => 'GPA'],
|
|
]
|
|
));
|
|
|
|
$controller = $this->buildController(
|
|
['mobile_no' => '9876543210', 'otp' => '123456'],
|
|
$hrModel,
|
|
$authHistoryModel
|
|
);
|
|
|
|
$body = $this->decodeResponse($controller->getVerifiedHrData());
|
|
|
|
$this->assertSame('success', $body['status']);
|
|
$this->assertSame(200, $body['code']);
|
|
$this->assertCount(1, $body['data']);
|
|
$this->assertSame(['post' => [1, 4, 5]], $body['data'][0]['allowed_modules']);
|
|
$this->assertSame(['EB', 'Non-EB'], $body['data'][0]['claims_sub_menu']);
|
|
$this->assertNotEmpty($body['data'][0]['token']);
|
|
$this->assertSame(['ok' => true, 'source' => 'post_enrollment'], $body['post_enrollment']);
|
|
}
|
|
|
|
public function testClaimsModuleWithoutActivePoliciesStripsModuleId4()
|
|
{
|
|
$branchRow = [
|
|
'id' => 5,
|
|
'mobile' => null,
|
|
'email' => 'hr@example.com',
|
|
'client_id' => 42,
|
|
'client_name' => 'Acme Corp',
|
|
'short_name' => 'ACME',
|
|
'client_branch_id' => 7,
|
|
'branch_name' => 'HQ',
|
|
'post_branch_id' => 70,
|
|
];
|
|
|
|
$hrModel = $this->createHrModelStub([
|
|
'first' => ['id' => 5, 'email' => 'hr@example.com', 'mobile' => null],
|
|
'findAll' => [$branchRow],
|
|
'update' => true,
|
|
]);
|
|
|
|
$authHistoryModel = $this->createMock(AuthHistoryModel::class);
|
|
$authHistoryModel->method('insert')->willReturn(1);
|
|
|
|
$this->injectDbConnection('postDB', $this->createQueryResultStub([
|
|
'pre_client_id' => 42,
|
|
'post_client_id' => 420,
|
|
'pre_branch_id' => 7,
|
|
'pre_hr_id' => 5,
|
|
'allowed_modules' => json_encode(['post' => [1, 4, 5]]),
|
|
'allowed_active_policies' => json_encode([]),
|
|
]));
|
|
|
|
$controller = $this->buildController(
|
|
['email' => 'hr@example.com', 'otp' => '123456'],
|
|
$hrModel,
|
|
$authHistoryModel
|
|
);
|
|
|
|
$body = $this->decodeResponse($controller->getVerifiedHrData());
|
|
|
|
$this->assertSame('success', $body['status']);
|
|
$this->assertSame(['post' => [1, 5]], $body['data'][0]['allowed_modules']);
|
|
$this->assertSame([], $body['data'][0]['claims_sub_menu']);
|
|
$this->assertNotEmpty($body['data'][0]['token']);
|
|
}
|
|
|
|
public function testMissingHrAccessReturnsEmptyModulesAndEmptyToken()
|
|
{
|
|
$branchRow = [
|
|
'id' => 5,
|
|
'mobile' => '9876543210',
|
|
'email' => 'hr@example.com',
|
|
'client_id' => 42,
|
|
'client_name' => 'Acme Corp',
|
|
'short_name' => 'ACME',
|
|
'client_branch_id' => 7,
|
|
'branch_name' => 'HQ',
|
|
'post_branch_id' => 70,
|
|
];
|
|
|
|
$hrModel = $this->createHrModelStub([
|
|
'first' => ['id' => 5, 'email' => 'hr@example.com', 'mobile' => '9876543210'],
|
|
'findAll' => [$branchRow],
|
|
'update' => true,
|
|
]);
|
|
|
|
$authHistoryModel = $this->createMock(AuthHistoryModel::class);
|
|
$authHistoryModel->method('insert')->willReturn(1);
|
|
|
|
$this->injectDbConnection('postDB', $this->createQueryResultStub(null));
|
|
|
|
$controller = $this->buildController(
|
|
['mobile_no' => '9876543210', 'otp' => '123456'],
|
|
$hrModel,
|
|
$authHistoryModel
|
|
);
|
|
|
|
$body = $this->decodeResponse($controller->getVerifiedHrData());
|
|
|
|
$this->assertSame('success', $body['status']);
|
|
$this->assertSame(200, $body['code']);
|
|
$this->assertSame([], $body['data'][0]['allowed_modules']);
|
|
$this->assertSame('', $body['data'][0]['token']);
|
|
}
|
|
|
|
private function buildController(
|
|
array $payload,
|
|
object $hrModel,
|
|
?AuthHistoryModel $authHistoryModel = null
|
|
): RestAuthenticationController {
|
|
$json = (object) $payload;
|
|
|
|
$uri = $this->createMock(URI::class);
|
|
$uri->method('getPath')->willReturn('/employeeRest/getVerifiedHrData');
|
|
$uri->method('getSegments')->willReturn(['employeeRest', 'getVerifiedHrData']);
|
|
|
|
$request = $this->getMockBuilder(IncomingRequest::class)
|
|
->disableOriginalConstructor()
|
|
->onlyMethods([
|
|
'getJSON',
|
|
'getHeaderLine',
|
|
'getIPAddress',
|
|
'getMethod',
|
|
'getPost',
|
|
'getVar',
|
|
])
|
|
->getMock();
|
|
|
|
$request->uri = $uri;
|
|
$request->method('getJSON')->willReturn($json);
|
|
$request->method('getHeaderLine')->with('User-Agent')->willReturn('PHPUnit');
|
|
$request->method('getIPAddress')->willReturn('127.0.0.1');
|
|
$request->method('getMethod')->willReturn('post');
|
|
$request->method('getPost')->willReturn([]);
|
|
$request->method('getVar')->willReturnCallback(static function ($key) {
|
|
return match ($key) {
|
|
'rateLimitFingerprint' => 'test-fingerprint',
|
|
'rateLimitIdentity' => 'hr@example.com',
|
|
default => null,
|
|
};
|
|
});
|
|
|
|
Services::injectMock('request', $request);
|
|
|
|
$controller = new RestAuthenticationController();
|
|
$controller->initController($request, Services::response(), Services::logger());
|
|
|
|
$reflection = new ReflectionClass($controller);
|
|
|
|
$hrProp = $reflection->getProperty('hrModel');
|
|
$hrProp->setAccessible(true);
|
|
$hrProp->setValue($controller, $hrModel);
|
|
|
|
if ($authHistoryModel !== null) {
|
|
$authProp = $reflection->getProperty('authHistoryModel');
|
|
$authProp->setAccessible(true);
|
|
$authProp->setValue($controller, $authHistoryModel);
|
|
}
|
|
|
|
return $controller;
|
|
}
|
|
|
|
private function createHrModelStub(array $results): object
|
|
{
|
|
return new class ($results) {
|
|
private array $results;
|
|
private $setPayload = null;
|
|
|
|
public function __construct(array $results)
|
|
{
|
|
$this->results = $results;
|
|
}
|
|
|
|
public function select(...$args)
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function join(...$args)
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function where(...$args)
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function set($data)
|
|
{
|
|
$this->setPayload = $data;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function first()
|
|
{
|
|
return $this->results['first'] ?? null;
|
|
}
|
|
|
|
public function findAll()
|
|
{
|
|
return $this->results['findAll'] ?? [];
|
|
}
|
|
|
|
public function update(...$args)
|
|
{
|
|
return $this->results['update'] ?? true;
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Fluent DB stub returning either a single row (getRowArray) or many rows (getResultArray).
|
|
*/
|
|
private function createQueryResultStub(?array $row, array $rows = []): object
|
|
{
|
|
return new class ($row, $rows) {
|
|
private ?array $row;
|
|
private array $rows;
|
|
|
|
public function __construct(?array $row, array $rows)
|
|
{
|
|
$this->row = $row;
|
|
$this->rows = $rows;
|
|
}
|
|
|
|
public function table(...$args)
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function select(...$args)
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function join(...$args)
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function where(...$args)
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function whereIn(...$args)
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function get()
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function getRowArray(): ?array
|
|
{
|
|
return $this->row;
|
|
}
|
|
|
|
public function getResultArray(): array
|
|
{
|
|
return $this->rows;
|
|
}
|
|
};
|
|
}
|
|
|
|
private function injectDbConnection(string $group, object $connection): void
|
|
{
|
|
$property = new ReflectionProperty(DatabaseConfig::class, 'instances');
|
|
$property->setAccessible(true);
|
|
|
|
$instances = $property->getValue() ?? [];
|
|
$instances[$group] = $connection;
|
|
$property->setValue(null, $instances);
|
|
}
|
|
|
|
private function clearInjectedDbConnections(): void
|
|
{
|
|
$property = new ReflectionProperty(DatabaseConfig::class, 'instances');
|
|
$property->setAccessible(true);
|
|
$property->setValue(null, []);
|
|
}
|
|
|
|
private function mockCurlRequest(array $payload): void
|
|
{
|
|
$response = $this->createMock(ResponseInterface::class);
|
|
$response->method('getBody')->willReturn(json_encode($payload));
|
|
|
|
$curl = $this->getMockBuilder(\CodeIgniter\HTTP\CURLRequest::class)
|
|
->disableOriginalConstructor()
|
|
->onlyMethods(['post', 'get'])
|
|
->getMock();
|
|
$curl->method('post')->willReturn($response);
|
|
$curl->method('get')->willReturn($response);
|
|
|
|
Services::injectMock('curlrequest', $curl);
|
|
}
|
|
|
|
private function mockRateLimiter(): void
|
|
{
|
|
$limiter = $this->getMockBuilder(\App\Libraries\RateLimiterService::class)
|
|
->disableOriginalConstructor()
|
|
->onlyMethods(['recordIpFailure', 'recordUserFailure'])
|
|
->getMock();
|
|
$limiter->method('recordIpFailure')->willReturn(null);
|
|
$limiter->method('recordUserFailure')->willReturn(null);
|
|
|
|
Services::injectMock('limiter', $limiter);
|
|
}
|
|
|
|
private function decodeResponse($response): array
|
|
{
|
|
return json_decode($response->getBody(), true);
|
|
}
|
|
}
|