mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-10-31 11:03:22 +01:00
Three tests stand a bare `new \Redis()` in for a store that cannot be read. That holds on phpredis 5, where every command of such an object throws. Since phpredis 6 the object dials 127.0.0.1:6379 on its first command, so the tests passed only while nothing answered there. The PHPUnit job installs a Redis on that port, and ConnectionTouchTest failed once on a pull request that does not touch the cluster code (#363). RedisServer::unreachable() returns a client whose connect() to a missing socket failed: it dials nothing on either version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AneTzAHPPkYWPQjwyZ2td9
65 lines
2.3 KiB
PHP
65 lines
2.3 KiB
PHP
<?php
|
|
|
|
namespace XcVm\Tests\Support;
|
|
|
|
/**
|
|
* A throwaway redis-server on 127.0.0.1 for tests, in the foreground and owned
|
|
* by the test process (a daemon would outlive a failed run and hold the test's
|
|
* output pipe open), never persisted.
|
|
*/
|
|
final class RedisServer {
|
|
/**
|
|
* Start one in $rDir, on a port the kernel picks free (a random one could be
|
|
* taken), giving it up to 10 s to listen: a busy CI runner was slower than
|
|
* 2.5 s (Connection refused). One that never listens is a redis not available.
|
|
*
|
|
* @param list<string> $rArgs extra redis-server arguments
|
|
* @param string|null $rSocket a unix socket ($rArgs' --unixsocket) to wait for as well
|
|
* @return array{0: resource, 1: int}|null the process and its port, or null (the caller skips)
|
|
*/
|
|
public static function start(string $rDir, array $rArgs = [], ?string $rSocket = null): ?array {
|
|
$rProbe = stream_socket_server('tcp://127.0.0.1:0');
|
|
if ($rProbe === false) {
|
|
return null;
|
|
}
|
|
$rPort = (int) substr((string) strrchr((string) stream_socket_get_name($rProbe, false), ':'), 1);
|
|
fclose($rProbe);
|
|
$rNull = ['file', '/dev/null', 'w'];
|
|
$rProc = proc_open(array_merge(['redis-server', '--port', (string) $rPort, '--bind', '127.0.0.1', '--save', '', '--appendonly', 'no', '--dir', $rDir], $rArgs), [0 => ['file', '/dev/null', 'r'], 1 => $rNull, 2 => $rNull], $rPipes);
|
|
if ($rProc === false) {
|
|
return null;
|
|
}
|
|
$rUp = static fn (): bool => @fsockopen('127.0.0.1', $rPort) !== false && ($rSocket === null || file_exists($rSocket));
|
|
for ($i = 0; $i < 200 && !$rUp(); $i++) {
|
|
usleep(50000);
|
|
}
|
|
if (!$rUp()) {
|
|
self::stop($rProc);
|
|
return null;
|
|
}
|
|
return [$rProc, $rPort];
|
|
}
|
|
|
|
/**
|
|
* A client of no server: every command throws. A bare `new \Redis()` is not
|
|
* one since phpredis 6, where its first command dials 127.0.0.1:6379 and is
|
|
* answered by whatever Redis the machine runs there. One whose connect()
|
|
* failed dials nothing, on phpredis 5 and 6 alike.
|
|
*/
|
|
public static function unreachable(): \Redis {
|
|
$rRedis = new \Redis();
|
|
try {
|
|
@$rRedis->connect('/nonexistent/xcvm-test-redis.sock');
|
|
} catch (\RedisException) {
|
|
// what a missing socket answers
|
|
}
|
|
return $rRedis;
|
|
}
|
|
|
|
/** @param resource $rProc */
|
|
public static function stop($rProc): void {
|
|
proc_terminate($rProc);
|
|
proc_close($rProc);
|
|
}
|
|
}
|