Resolve recommended-profile Critical and High findings, retain narrow analyzer exceptions, and update the edge-broker WebSocket dependency to a non-vulnerable release.
102 lines
2.5 KiB
PHP
102 lines
2.5 KiB
PHP
<?php
|
|
|
|
app_require('classes/redis.php');
|
|
|
|
use classes\redis;
|
|
use Predis\Client as PredisClient;
|
|
|
|
class RedisAtomicReservationTestClient extends PredisClient
|
|
{
|
|
public array $calls = [];
|
|
|
|
public function __construct(private mixed $returnValue)
|
|
{
|
|
}
|
|
|
|
public function mget(array $keyOrKeys): array
|
|
{
|
|
$this->calls[] = ['mget', $keyOrKeys];
|
|
return $this->returnValue;
|
|
}
|
|
|
|
public function set(...$arguments): mixed
|
|
{
|
|
$this->calls[] = $arguments;
|
|
return $this->returnValue;
|
|
}
|
|
|
|
public function disconnect(): void
|
|
{
|
|
}
|
|
}
|
|
|
|
function redis_test_inject_client(redis $redis, PredisClient $client): void
|
|
{
|
|
$reflection = new ReflectionClass($redis);
|
|
$property = $reflection->getProperty('redis');
|
|
$property->setValue($redis, $client);
|
|
}
|
|
|
|
it('claims a slot atomically with nx and expiration', function (): void {
|
|
global $REDIS_CONFIG;
|
|
|
|
$REDIS_CONFIG = [
|
|
'host' => 'redis',
|
|
'database' => 0,
|
|
'password' => '',
|
|
];
|
|
|
|
$client = new RedisAtomicReservationTestClient('OK');
|
|
|
|
$redis = new redis();
|
|
redis_test_inject_client($redis, $client);
|
|
|
|
expect($redis->set_if_absent_with_expiration('goal_alert_sent:22:2026-03-17', '1', 86400))->toBeTrue();
|
|
expect($client->calls)->toBe([
|
|
['goal_alert_sent:22:2026-03-17', '1', 'EX', 86400, 'NX'],
|
|
]);
|
|
});
|
|
|
|
it('returns false when the slot is already claimed and clamps ttl to one second', function (): void {
|
|
global $REDIS_CONFIG;
|
|
|
|
$REDIS_CONFIG = [
|
|
'host' => 'redis',
|
|
'database' => 0,
|
|
'password' => '',
|
|
];
|
|
|
|
$client = new RedisAtomicReservationTestClient(null);
|
|
|
|
$redis = new redis();
|
|
redis_test_inject_client($redis, $client);
|
|
|
|
expect($redis->set_if_absent_with_expiration('goal_alert_sent:22:2026-03-17', '1', 0))->toBeFalse();
|
|
expect($client->calls)->toBe([
|
|
['goal_alert_sent:22:2026-03-17', '1', 'EX', 1, 'NX'],
|
|
]);
|
|
});
|
|
|
|
it('does not send empty mget commands to redis', function (): void {
|
|
global $REDIS_CONFIG;
|
|
|
|
$REDIS_CONFIG = [
|
|
'host' => 'redis',
|
|
'database' => 0,
|
|
'password' => '',
|
|
];
|
|
|
|
$client = new RedisAtomicReservationTestClient(['cached-value']);
|
|
|
|
$redis = new redis();
|
|
redis_test_inject_client($redis, $client);
|
|
|
|
expect($redis->mget([]))->toBe([]);
|
|
expect($client->calls)->toBe([]);
|
|
|
|
expect($redis->mget(['cache-key']))->toBe(['cached-value']);
|
|
expect($client->calls)->toBe([
|
|
['mget', ['cache-key']],
|
|
]);
|
|
});
|