Files
MeshVault/tests/Integration/TaskRunnerTest.php
T
Keith Solomon d3e8cf8fae build: M1 Dockerized development stack with PHP skeleton, config/logging, Tailwind assets, and wrappers
Implements MeshVault M1 (issues #6–11):

- Four-service Docker Compose stack (nginx, PHP-FPM 8.3, PostgreSQL 17, Node assets)
- Slim 4 + PHP-DI routing with escaped PHP views and production/dev error handling
- Immutable validated AppConfig with redacted diagnostics
- JSON stdout Monolog logging with job-scoped context
- Tailwind CSS v4 deterministic locked builds with template scanning
- POSIX and PowerShell dev wrappers (up/down/test/lint/assets/watch)
- Startup config validation fails before FPM serves as unprivileged www-data
- migrate/seed explicitly unavailable until M2 (#12); #10 remains open

Verified via clean-start acceptance on remote host (keith@192.168.2.23).
2026-10-11 16:45:45 -05:00

66 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
namespace MeshVault\Tests\Integration;
use PHPUnit\Framework\TestCase;
final class TaskRunnerTest extends TestCase
{
public function testCommandsFromAnotherWorkingDirectory(): void
{
$root = dirname(__DIR__, 2);
$temporary = sys_get_temp_dir() . '/meshvault-runner-' . bin2hex(random_bytes(6));
mkdir($temporary);
$windows = PHP_OS_FAMILY === 'Windows';
$fake = $temporary . ($windows ? '/docker.cmd' : '/docker');
file_put_contents($fake, $windows
? "@echo off\r\necho cwd=%CD%\r\necho %*\r\nexit /b 37\r\n"
: "#!/bin/sh\nprintf 'cwd=%s\\n' \"\$PWD\"\nprintf '%s\\n' \"\$@\"\nexit 37\n");
chmod($fake, 0755);
$environment = getenv();
$environment[$windows ? 'Path' : 'PATH'] = $temporary . PATH_SEPARATOR . getenv('PATH');
$runner = $windows
? ['powershell.exe', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $root . '/dev.ps1']
: ['sh', $root . '/dev.sh'];
try {
foreach (['up', 'down', 'test', 'lint', 'assets', 'watch'] as $command) {
[$code, $output] = $this->invoke(
[...$runner, $command, '--probe', 'two words'],
$temporary,
$environment
);
self::assertSame(37, $code, $command . ': ' . $output);
self::assertStringContainsString('compose', $output);
self::assertStringContainsString('--probe', $output);
self::assertStringContainsString('two words', $output);
self::assertStringContainsString(str_replace('\\', '/', $root), str_replace('\\', '/', $output));
}
foreach (['unknown', 'migrate', 'seed'] as $command) {
[$code, $output] = $this->invoke([...$runner, $command], $temporary, $environment);
self::assertNotSame(0, $code);
self::assertStringNotContainsString('cwd=', $output);
}
foreach (['-v', '--volumes', '--volumes=true'] as $flag) {
[$code, $output] = $this->invoke([...$runner, 'down', $flag], $temporary, $environment);
self::assertNotSame(0, $code);
self::assertStringNotContainsString('cwd=', $output);
}
} finally {
unlink($fake);
rmdir($temporary);
}
}
private function invoke(array $command, string $cwd, array $environment): array
{
$process = proc_open($command, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, $cwd, $environment);
self::assertIsResource($process);
$output = stream_get_contents($pipes[1]) . stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
return [proc_close($process), $output];
}
}