7861bf9dde
gates / gates (push) Successful in 28s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
62 lines
2.6 KiB
Go
62 lines
2.6 KiB
Go
package stacks
|
|
|
|
import (
|
|
"bytes"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// R-864 (v0.294.0): a failed compose command logs and returns the TAIL of stderr. THE NIGHT'S SHAPE (2026-10-04,
|
|
// BookStack on the fresh Tester 1 box, audits/night-2026-10-04/tester1/t8-*): the stderr opened with the pull
|
|
// progress below (the first line is verbatim from that night) and the reason came last; v0.293.0 kept the first
|
|
// 500 bytes and logged only "Image … Pulling" — the reason was lost. The night's last line itself was lost by
|
|
// exactly this defect; the one here is Docker's message for an image deleted under compose (R-863).
|
|
// COMPANION RED-PROOF: use truncateStr instead of tailStr for stderr in composeExecCustomEnv → "the reason was cut".
|
|
func TestR864_FailedComposeLogsTheReasonNotThePullProgress(t *testing.T) {
|
|
var lines []string
|
|
lines = append(lines, "Image lscr.io/linuxserver/bookstack:26.09.1@sha256:99cd1f5707c1911afad213adec5c9739763b76f843d1477142231834ecdcb6f7 Pulling")
|
|
lines = append(lines, "Image mariadb:11.4@sha256:dfff46ef3f9d Pulling")
|
|
for i := 0; i < 16; i++ {
|
|
lines = append(lines, " a1b2c3d4e5f6 Pull complete")
|
|
}
|
|
lines = append(lines, "Image mariadb:11.4@sha256:dfff46ef3f9d Pulled")
|
|
reason := "Error response from daemon: No such image: mariadb@sha256:dfff46ef3f9d — árvíztűrő"
|
|
lines = append(lines, reason)
|
|
stderr := strings.Join(lines, "\n")
|
|
if len(stderr) < 700 {
|
|
t.Fatalf("the fixture must exceed the 500-byte cut (%d)", len(stderr))
|
|
}
|
|
m := gateManager(t, "display_name: G\n")
|
|
dir := t.TempDir() // a stub under os.TempDir(): R-650's sanctioned seam, never this host's Docker
|
|
errf := filepath.Join(dir, "stderr.txt")
|
|
must(t, os.WriteFile(errf, []byte(stderr), 0o644))
|
|
must(t, os.WriteFile(filepath.Join(dir, "docker"), []byte("#!/bin/sh\nwhile IFS= read -r l || [ -n \"$l\" ]; do printf '%s\\n' \"$l\" >&2; done < "+errf+"\nexit 1\n"), 0o755))
|
|
t.Setenv("PATH", dir)
|
|
var buf bytes.Buffer
|
|
m.logger = log.New(&buf, "", 0)
|
|
_, err := m.composeExecCustomEnv(dir, []string{"PATH=" + dir}, "up", "-d")
|
|
if err == nil {
|
|
t.Fatal("no error from a failed compose")
|
|
}
|
|
if !strings.Contains(err.Error(), reason) {
|
|
t.Fatalf("the reason was cut from the returned error: %q", err.Error())
|
|
}
|
|
if !strings.Contains(buf.String(), reason) {
|
|
t.Fatalf("the reason was cut from the log:\n%s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestR864_TailStrKeepsTheEndOnARuneBoundary(t *testing.T) {
|
|
s := strings.Repeat("x", 10) + "őőő"
|
|
got := tailStr(s, 5) // the cut falls inside "ő" (2 bytes each)
|
|
if got != "...őő" {
|
|
t.Fatalf("tailStr = %q", got)
|
|
}
|
|
if tailStr("short", 500) != "short" {
|
|
t.Fatal("a short string must pass unchanged")
|
|
}
|
|
}
|