$name, "detail" => $detail]; echo " ✓ $name" . ($detail ? " ($detail)" : '') . "\n"; } else { $failed++; $results[] = ["FAIL" => $name, "detail" => $detail]; echo " ✗ $name" . ($detail ? " ($detail)" : '') . "\n"; } } echo "=== MUA Selftest ===\n\n"; // ── 1. Tools-Definition ────────────────────────────────────────────────── echo "[1] Tools-Definition\n"; $tools = mua_tools(); check('21 Tools definiert', count($tools) === 21, count($tools) . ' Tools'); $names = array_column($tools, 'name'); $expected = [ 'unraid_docker_list', 'unraid_docker_inspect', 'unraid_docker_logs', 'unraid_docker_analyze_logs', 'unraid_docker_processes', 'unraid_docker_stats', 'unraid_docker_info', 'unraid_docker_start', 'unraid_docker_stop', 'unraid_docker_restart', 'unraid_docker_create', 'unraid_docker_modify', 'unraid_docker_update', 'unraid_docker_rebuild', 'unraid_network_inventory', 'unraid_network_list', 'unraid_network_inspect', 'unraid_network_host_state', 'unraid_network_audit_tcp', 'unraid_network_lan_probe', 'unraid_system_connection_test', ]; $missing = array_diff($expected, $names); check('Alle erwarteten Tools vorhanden', empty($missing), empty($missing) ? '' : 'Fehlt: ' . implode(', ', $missing)); // ── 2. Docker-Verbindung ───────────────────────────────────────────────── echo "\n[2] Docker-Verbindung\n"; try { $info = docker_exec("info --format '{{.ServerVersion}}'"); check('Docker erreichbar', $info !== '', 'Version: ' . trim($info)); } catch (Exception $e) { check('Docker erreichbar', false, $e->getMessage()); } // ── 3. Container-Liste ─────────────────────────────────────────────────── echo "\n[3] Container-Liste\n"; try { $summary = container_runtime_summary(); $decoded = json_decode($summary, true); check('container_runtime_summary() funktioniert', is_array($decoded) && isset($decoded['container_count'])); check('Container-Count > 0', ($decoded['container_count'] ?? 0) > 0, $decoded['container_count'] . ' Container'); } catch (Exception $e) { check('container_runtime_summary() funktioniert', false, $e->getMessage()); } // ── 3b. Kompakte Inspect-Ausgabe ───────────────────────────────────────── $fixture = json_encode([[ 'Id' => str_repeat('a', 64), 'Name' => '/test', 'State' => ['Status' => 'running', 'Running' => true, 'Pid' => 42, 'ExitCode' => 0], 'Config' => ['Image' => 'example:latest', 'Env' => ['SECRET=value']], 'HostConfig' => ['NetworkMode' => 'bridge'], 'NetworkSettings' => ['Ports' => []], 'Mounts' => [['Type' => 'bind', 'Source' => '/secret', 'Destination' => '/data']], 'RestartCount' => 0, 'Created' => 'now', ]]); $summaryInspect = json_decode(compact_container_inspect($fixture), true); $fullInspect = json_decode(compact_container_inspect($fixture, 'full'), true); check('Inspect summary laesst Env aus', !isset($summaryInspect['Env']) && !isset($summaryInspect['Mounts'])); check('Inspect full enthaelt Env und Mounts', isset($fullInspect['Env']) && isset($fullInspect['Mounts'])); check('Inspect full maskiert Secrets', ($fullInspect['Env'][0] ?? '') === 'SECRET='); // ── 4. Netzwerk-Inventur ───────────────────────────────────────────────── echo "\n[4] Netzwerk-Inventur\n"; try { $inventory = compact_network_inventory([]); $decoded = json_decode($inventory, true); check('compact_network_inventory() funktioniert', is_array($decoded) && isset($decoded['network_count'])); check('Netzwerk-Count > 0', ($decoded['network_count'] ?? 0) > 0, $decoded['network_count'] . ' Netzwerke'); } catch (Exception $e) { check('compact_network_inventory() funktioniert', false, $e->getMessage()); } // ── 5. Host-Adressen ───────────────────────────────────────────────────── echo "\n[5] Host-Adressen\n"; try { $raw = run_local('test', "ip -j address show"); $addrs = host_addresses($raw); check('IPv4-Adresse gefunden', $addrs['ipv4'] !== '', $addrs['ipv4']); check('IPv6-Adresse gefunden', $addrs['ipv6'] !== '', $addrs['ipv6']); } catch (Exception $e) { check('Host-Adressen', false, $e->getMessage()); } // ── 6. Validate-Name ───────────────────────────────────────────────────── echo "\n[6] Validate-Name\n"; try { validate_name('test-container', 'container'); check('Gültiger Name akzeptiert', true); } catch (Exception $e) { check('Gültiger Name akzeptiert', false, $e->getMessage()); } try { validate_name('bad;name', 'container'); check('Ungültiger Name abgelehnt', false, 'Sollte Exception werfen'); } catch (Exception $e) { check('Ungültiger Name abgelehnt', true); } // ── 7. PHP-Helper vorhanden ────────────────────────────────────────────── echo "\n[7] PHP-Helper\n"; $helper = '/usr/local/bin/unraid-docker-mcp-helper.php'; check('PHP-Helper vorhanden', file_exists($helper), $helper); // ── Zusammenfassung ────────────────────────────────────────────────────── echo "\n=== Zusammenfassung ===\n"; echo " Bestanden: $passed\n"; echo " Fehlgeschlagen: $failed\n"; echo " Gesamt: " . ($passed + $failed) . "\n"; exit($failed > 0 ? 1 : 0);