using System.Diagnostics; using System.Globalization; namespace Azaion.Missions.E2E.Helpers; /// /// Scrapes docker logs from inside the e2e-consumer container, used /// to assert "unhandled exception" and structured log lines emitted by the /// SUT (NFT-SEC-08 stack-not-leaked, NFT-RES-01..04 cascade/migrator log /// invariants, NFT-RES-06 Npgsql 3D000). /// /// /// Like the docker-compose fixtures, this helper requires docker CLI access /// (and typically a docker socket bind). Tests that depend on it must /// when the CLI is not /// available — silent passing is rejected. /// public static class DockerLogs { public static bool Contains(string container, string needle, DateTime sinceUtc) => Read(container, sinceUtc).Contains(needle, StringComparison.Ordinal); /// Returns the combined stdout+stderr log slice since . public static string Read(string container, DateTime? sinceUtc = null) { var args = sinceUtc is { } cutoff ? $"logs --since {cutoff.ToString("yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture)} {container}" : $"logs {container}"; var psi = new ProcessStartInfo("docker", args) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false }; try { using var p = Process.Start(psi) ?? throw new InvalidOperationException("docker command not available"); var stdout = p.StandardOutput.ReadToEnd(); var stderr = p.StandardError.ReadToEnd(); p.WaitForExit(); return stdout + stderr; } catch (System.ComponentModel.Win32Exception) { // No docker CLI in PATH — surface, do not silently pass. throw new InvalidOperationException( $"docker CLI not available; cannot scrape logs for '{container}'. " + "Mount /var/run/docker.sock and install docker-cli in the e2e-consumer image."); } } }