Files
api/services/nginx/app/tests/permissions/PermissionRedisCacheTest.php
T
Jeppe Bundgaard ff2d9788bf Remove dependency on the ws module.
Deleted the entire `ws` library and its associated files. This likely reflects a move away from the WebSocket library, possibly signaling an alternate implementation or unused/legacy code cleanup.
2026-04-14 13:45:17 +02:00

172 lines
6.2 KiB
PHP

<?php
namespace {
if (!defined('WD')) {
define('WD', dirname(__DIR__, 2));
}
$_SERVER['REQUEST_URI'] = '/test';
}
// Setup mock environment
namespace classes {
class authentication {
public static $user = false;
public static $subuser = false;
public function get_user() { return self::$user; }
public function get_subuser() { return self::$subuser; }
}
class response {
public function error($msg, $code) { throw new \Exception("Response Error ($code): $msg"); }
public function forbidden(array $permissions) { throw new \Exception("Response Error (403): Missing permission(s): " . implode(', ', $permissions)); }
public function add_meta($k, $v) {}
}
class permission_node {
public $permission;
public $subusers_node_key;
public static function create($p, $k = null) {
$n = new self();
$n->permission = $p;
$n->subusers_node_key = $k;
return $n;
}
}
}
namespace objects {
class logs_o {
public function add($a, $b, $c, $d, $e, $f) {}
}
class users_o {
public $id = 1;
public $group_id;
public function __construct() {
$this->group_id = new class { public function value() { return 2; } };
}
public function hasPermission($p) {
echo "[DB] Checking permission: $p\n";
return $p === 'allowed_perm';
}
}
class subusers_o {
public $id = 10;
public function hasPermission($node) {
echo "[DB] Checking subuser node: " . $node->name . "\n";
return $node->name === 'ALLOWED_NODE';
}
}
}
namespace {
// Include Redis classes first so we can mock REDIS_CONFIG
global $REDIS_CONFIG;
$REDIS_CONFIG = [
'host' => getenv('REDIS_CONFIG_HOST') ?: 'redis',
'user' => getenv('REDIS_CONFIG_USER') ?: 'default',
'database' => (int)(getenv('REDIS_CONFIG_DATABASE') ?: 0),
'password' => getenv('REDIS_CONFIG_PASSWORD') ?: '',
'port' => (int)(getenv('REDIS_CONFIG_PORT') ?: 6379),
];
require_once WD . '/vendor/autoload.php';
require_once WD . '/interfaces/redis_i.php';
require_once WD . '/traits/redis_t.php';
require_once WD . '/classes/redis.php';
require_once WD . '/traits/route_t.php';
// Set the redis constant
global $response;
$response = new classes\response();
try {
$redis_instance = (new classes\redis())->connect();
if (!defined('redis')) {
define("redis", $redis_instance);
}
} catch (Exception $e) {
die("Could not connect to Redis: " . $e->getMessage());
}
use traits\route_t;
use classes\authentication;
use classes\permission_node;
use objects\users_o;
use objects\subusers_o;
class TestRoute {
use route_t;
public function testEval($p, $c = null, $t = false) {
return $this->evaluatePermission($p, $c, $t);
}
// Mocking resolveCustomerNumberForSubuser as it's private and uses headers
private function resolveCustomerNumberForSubuser($auth, ?int $customer_number = null): ?int {
return $customer_number ?? 999;
}
}
$route = new TestRoute();
function assertResult($actual, $expected, $msg) {
if ($actual === $expected) {
echo "\033[32m✔ $msg\033[0m\n";
} else {
echo "\033[31m✖ $msg (Expected " . var_export($expected, true) . ", got " . var_export($actual, true) . ")\033[0m\n";
exit(1);
}
}
// 1. Test classic user permission caching
echo "--- Testing Classic User Permission Caching ---\n";
$user = new users_o();
authentication::$user = $user;
// Clear previous cache if any
redis->clear_permission("user:1:allowed_perm");
redis->clear_permission("user:1:denied_perm");
echo "First call (should hit DB):\n";
assertResult($route->testEval('allowed_perm'), true, "User should have allowed_perm");
echo "Second call (should hit memory cache, no DB output expected):\n";
assertResult($route->testEval('allowed_perm'), true, "User should still have allowed_perm (from memory)");
// Clear memory cache by creating new route object
$route = new TestRoute();
echo "Third call after new object (should hit Redis, no DB output expected):\n";
assertResult($route->testEval('allowed_perm'), true, "User should still have allowed_perm (from Redis)");
// Test denied perm
echo "\nTesting denied perm:\n";
assertResult($route->testEval('denied_perm'), false, "User should NOT have denied_perm");
$route = new TestRoute();
echo "Call after new object (should hit Redis, no DB output expected):\n";
assertResult($route->testEval('denied_perm'), false, "User should still NOT have denied_perm (from Redis)");
// 2. Test subuser node caching
echo "\n--- Testing Subuser Node Caching ---\n";
$subuser = new subusers_o();
authentication::$subuser = $subuser;
$allowedNode = new stdClass(); $allowedNode->name = 'ALLOWED_NODE';
$deniedNode = new stdClass(); $deniedNode->name = 'DENIED_NODE';
$allowedPermNode = permission_node::create('allowed_node_perm', $allowedNode);
$deniedPermNode = permission_node::create('denied_node_perm', $deniedNode);
redis->clear_permission("subuser:10:999:ALLOWED_NODE");
redis->clear_permission("subuser:10:999:DENIED_NODE");
echo "First call (should hit DB):\n";
assertResult($route->testEval($allowedPermNode), true, "Subuser should have ALLOWED_NODE");
$route = new TestRoute();
echo "Second call after new object (should hit Redis, no DB output expected):\n";
assertResult($route->testEval($allowedPermNode), true, "Subuser should still have ALLOWED_NODE (from Redis)");
echo "\nTesting denied node:\n";
assertResult($route->testEval($deniedPermNode), false, "Subuser should NOT have DENIED_NODE");
$route = new TestRoute();
echo "Call after new object (should hit Redis, no DB output expected):\n";
assertResult($route->testEval($deniedPermNode), false, "Subuser should still NOT have DENIED_NODE (from Redis)");
echo "\nPermissionRedisCacheTest completed successfully.\n";
}