nhance/tests/smoke_verified_hr_claims_submenu.php

313 lines
10 KiB
PHP

<?php
/**
* Smoke test: RestAuthenticationController::getVerifiedHrData
* — claims module strip when allowed_active_policies empty
* — claims_sub_menu EB / Non-EB based on policy_type.allocg
*
* Run:
* php tests/smoke_verified_hr_claims_submenu.php
*/
declare(strict_types=1);
ob_start();
define('FCPATH', __DIR__ . '/../public/');
chdir(FCPATH);
require FCPATH . '../app/Config/Paths.php';
$paths = new Config\Paths();
require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php';
require_once SYSTEMPATH . 'Config/DotEnv.php';
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();
defined('ENVIRONMENT') || define('ENVIRONMENT', env('CI_ENVIRONMENT', 'development'));
$boot = APPPATH . 'Config/Boot/' . ENVIRONMENT . '.php';
if (is_file($boot)) {
require_once $boot;
}
if (empty(env('JWT_SECRET'))) {
$smokeJwtSecret = 'smoke-verified-hr-claims-submenu-jwt-secret';
putenv('JWT_SECRET=' . $smokeJwtSecret);
$_ENV['JWT_SECRET'] = $smokeJwtSecret;
$_SERVER['JWT_SECRET'] = $smokeJwtSecret;
}
use App\Controllers\RestAuthenticationController;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\URI;
use CodeIgniter\HTTP\UserAgent;
use Config\Services;
$pass = 0;
$fail = 0;
$skip = 0;
$results = [];
function ok(string $label, bool $cond, string $detail = ''): void
{
global $pass, $fail, $results;
if ($cond) {
$pass++;
$results[] = '[PASS] ' . $label . ($detail !== '' ? "{$detail}" : '');
} else {
$fail++;
$results[] = '[FAIL] ' . $label . ($detail !== '' ? "{$detail}" : '');
}
}
function skip(string $label, string $detail = ''): void
{
global $skip, $results;
$skip++;
$results[] = '[SKIP] ' . $label . ($detail !== '' ? "{$detail}" : '');
}
/**
* @return array{http:int,body:array,raw:string,error:?string}
*/
function invokeGetVerifiedHrData(array $payload): array
{
try {
$uri = new URI('http://localhost/nhance_v2/employeeRest/getVerifiedHrData');
$bodyString = json_encode($payload, JSON_THROW_ON_ERROR);
$request = new IncomingRequest(
config('App'),
$uri,
$bodyString,
new UserAgent()
);
$request->setMethod('post');
$request->setHeader('Content-Type', 'application/json');
$request->setHeader('User-Agent', 'SmokeTest/1.0');
$request->setGlobal('post', []);
Services::injectMock('request', $request);
$controller = new RestAuthenticationController();
$response = Services::response();
$logger = Services::logger();
$controller->initController($request, $response, $logger);
// Local DB user may lack INSERT on auth_history; stub so smoke can focus on claims logic.
$authHistoryStub = new class {
public function insert($data = null, bool $returnID = true)
{
return true;
}
};
$ref = new ReflectionProperty(RestAuthenticationController::class, 'authHistoryModel');
$ref->setAccessible(true);
$ref->setValue($controller, $authHistoryStub);
$resp = $controller->getVerifiedHrData();
$raw = $resp->getBody();
$body = json_decode($raw, true);
return [
'http' => $resp->getStatusCode(),
'body' => is_array($body) ? $body : [],
'raw' => (string) $raw,
'error' => null,
];
} catch (Throwable $e) {
return [
'http' => 500,
'body' => [],
'raw' => '',
'error' => $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine(),
];
}
}
function findHrRowForClient(array $dataRows, int $clientId, int $hrId): ?array
{
foreach ($dataRows as $row) {
if ((int) ($row['client_id'] ?? 0) === $clientId && (int) ($row['id'] ?? 0) === $hrId) {
return $row;
}
}
return $dataRows[0] ?? null;
}
function postModulesContainClaims(?array $allowedModules): bool
{
if (!is_array($allowedModules)) {
return false;
}
if (isset($allowedModules['post']) && is_array($allowedModules['post'])) {
return in_array(4, array_map('intval', $allowedModules['post']), true);
}
if (!isset($allowedModules['pre']) && !isset($allowedModules['post'])) {
return in_array(4, array_map('intval', $allowedModules), true);
}
return false;
}
$db = db_connect();
$fixture = $db->query(
"SELECT hac.id AS hac_id, hac.post_hr_id, hac.post_client_id, hac.post_branch_id,
hac.allowed_modules, hac.allowed_active_policies,
lc.mobile, lc.email, lc.otp AS original_otp
FROM hr_access_control hac
INNER JOIN level_contacts lc ON lc.id = hac.post_hr_id
WHERE hac.is_active = 1
AND lc.is_active = 1
AND lc.contact_type = 'client'
AND lc.mobile IS NOT NULL
AND lc.mobile <> ''
AND hac.allowed_modules LIKE '%4%'
AND hac.allowed_active_policies IS NOT NULL
AND hac.allowed_active_policies <> '[]'
AND hac.allowed_active_policies <> ''
ORDER BY hac.id DESC
LIMIT 1"
)->getRowArray();
$nonEbPolicy = $db->query(
"SELECT cp.id, pt.allocg
FROM client_policy cp
JOIN policy_type pt ON pt.id = cp.policy_type_id
WHERE pt.allocg <> 'EB'
AND cp.is_active = 1
ORDER BY cp.id DESC
LIMIT 1"
)->getRowArray();
if (!$fixture) {
skip('Fixture HR with claims + policies', 'none found');
foreach ($results as $line) {
echo $line . PHP_EOL;
}
echo PHP_EOL . "PASS={$pass} FAIL={$fail} SKIP={$skip}" . PHP_EOL;
exit($fail > 0 ? 1 : 0);
}
ok('Fixture HR with claims module', true, "hac_id={$fixture['hac_id']} hr={$fixture['post_hr_id']} mobile={$fixture['mobile']}");
$otp = '999111';
$originalPolicies = $fixture['allowed_active_policies'];
$originalModules = $fixture['allowed_modules'];
$originalOtp = $fixture['original_otp'];
$hrId = (int) $fixture['post_hr_id'];
$clientId = (int) $fixture['post_client_id'];
$hacId = (int) $fixture['hac_id'];
$mobile = $fixture['mobile'];
$restore = static function () use ($db, $hacId, $hrId, $originalPolicies, $originalModules, $originalOtp): void {
$db->table('hr_access_control')->where('id', $hacId)->update([
'allowed_active_policies' => $originalPolicies,
'allowed_modules' => $originalModules,
]);
$db->table('level_contacts')->where('id', $hrId)->update([
'otp' => $originalOtp,
]);
};
register_shutdown_function($restore);
// ── Case 1: EB-only policies → claims_sub_menu = ["EB"] ──────────────────────
$db->table('level_contacts')->where('id', $hrId)->update(['otp' => $otp]);
$case1 = invokeGetVerifiedHrData([
'mobile_no' => $mobile,
'otp' => $otp,
]);
ok('Case1 HTTP/error free', $case1['error'] === null, (string) ($case1['error'] ?? 'ok'));
ok('Case1 status success', ($case1['body']['status'] ?? '') === 'success', json_encode($case1['body']['message'] ?? $case1['body']['status'] ?? null));
$case1Rows = $case1['body']['data'] ?? [];
$case1Row = is_array($case1Rows) ? findHrRowForClient($case1Rows, $clientId, $hrId) : null;
ok('Case1 row found', is_array($case1Row), 'client_id=' . $clientId);
ok(
'Case1 claims still present',
postModulesContainClaims($case1Row['allowed_modules'] ?? null),
json_encode($case1Row['allowed_modules'] ?? null)
);
ok(
'Case1 claims_sub_menu is EB only',
($case1Row['claims_sub_menu'] ?? null) === ['EB'],
json_encode($case1Row['claims_sub_menu'] ?? null)
);
// ── Case 2: include Non-EB policy → claims_sub_menu = ["EB","Non-EB"] ─────────
if (!$nonEbPolicy) {
skip('Case2 Non-EB policy fixture', 'no non-EB client_policy found');
} else {
$mixedPolicies = json_decode($originalPolicies, true) ?: [];
$mixedPolicies[] = (int) $nonEbPolicy['id'];
$mixedPolicies = array_values(array_unique(array_map('intval', $mixedPolicies)));
$db->table('hr_access_control')->where('id', $hacId)->update([
'allowed_active_policies' => json_encode($mixedPolicies),
]);
$db->table('level_contacts')->where('id', $hrId)->update(['otp' => $otp]);
$case2 = invokeGetVerifiedHrData([
'mobile_no' => $mobile,
'otp' => $otp,
]);
ok('Case2 HTTP/error free', $case2['error'] === null, (string) ($case2['error'] ?? 'ok'));
ok('Case2 status success', ($case2['body']['status'] ?? '') === 'success', json_encode($case2['body']['status'] ?? null));
$case2Rows = $case2['body']['data'] ?? [];
$case2Row = is_array($case2Rows) ? findHrRowForClient($case2Rows, $clientId, $hrId) : null;
ok(
'Case2 claims_sub_menu has EB + Non-EB',
($case2Row['claims_sub_menu'] ?? null) === ['EB', 'Non-EB'],
json_encode($case2Row['claims_sub_menu'] ?? null) . ' nonEbPolicy=' . $nonEbPolicy['id'] . '/' . $nonEbPolicy['allocg']
);
}
// ── Case 3: empty policies → claims stripped, claims_sub_menu = [] ────────────
$db->table('hr_access_control')->where('id', $hacId)->update([
'allowed_active_policies' => '[]',
]);
$db->table('level_contacts')->where('id', $hrId)->update(['otp' => $otp]);
$case3 = invokeGetVerifiedHrData([
'mobile_no' => $mobile,
'otp' => $otp,
]);
ok('Case3 HTTP/error free', $case3['error'] === null, (string) ($case3['error'] ?? 'ok'));
ok('Case3 status success', ($case3['body']['status'] ?? '') === 'success', json_encode($case3['body']['status'] ?? null));
$case3Rows = $case3['body']['data'] ?? [];
$case3Row = is_array($case3Rows) ? findHrRowForClient($case3Rows, $clientId, $hrId) : null;
ok(
'Case3 claims module removed',
!postModulesContainClaims($case3Row['allowed_modules'] ?? null),
json_encode($case3Row['allowed_modules'] ?? null)
);
ok(
'Case3 claims_sub_menu empty',
($case3Row['claims_sub_menu'] ?? null) === [],
json_encode($case3Row['claims_sub_menu'] ?? null)
);
$restore();
ob_end_clean();
foreach ($results as $line) {
echo $line . PHP_EOL;
}
echo PHP_EOL . "PASS={$pass} FAIL={$fail} SKIP={$skip}" . PHP_EOL;
exit($fail > 0 ? 1 : 0);