44ae4dea70
gates / gates (push) Successful in 26s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
67 lines
2.7 KiB
Go
67 lines
2.7 KiB
Go
package stacks
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// R-670 (v0.272.0) — every undo logged `[ERROR] .felhom.yml backup block rejected … docker-compose.yml
|
|
// unreadable`, because the undo read the previous version's `.felhom.yml` from `pre-update-meta/`, which has
|
|
// no compose beside it, through the validating loader. The consequence asserted: a REAL undo of an app whose
|
|
// `.felhom.yml` carries a backup block writes no such line to the process log.
|
|
//
|
|
// COMPANION RED-PROOF (REPORT.md): read PrevMeta with LoadMetadata again — this test fails at "the undo logged
|
|
// a false backup-block ERROR".
|
|
func TestR670_ProbeLoaderLogsNoFalseError(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
prev := log.Writer()
|
|
log.SetOutput(&buf)
|
|
defer log.SetOutput(prev)
|
|
|
|
m, dir, _, _, _ := ladderManager(t, true)
|
|
withBlock := "display_name: Nextcloud\nbackup:\n userdata:\n - path: data\n class: excluded\n"
|
|
mustWrite(t, filepath.Join(dir, ".felhom.yml"), withBlock)
|
|
if err := os.MkdirAll(filepath.Join(dir, appliedMetaDir), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mustWrite(t, filepath.Join(dir, appliedMetaDir, ".felhom.yml"), withBlock)
|
|
m.undoCopier = newFakeCopier(map[string]string{undoVol: "OLD"})
|
|
m.updateHealthFn = func(context.Context, string, time.Duration) (bool, string) { return false, "B unhealthy" }
|
|
m.updateUndoHealthFn = func(context.Context, string, time.Duration, *Metadata) (bool, string) { return true, "A answers" }
|
|
if err := m.StartGuardedUpdate("nextcloud"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if st := waitUpdateDone(t, m, "nextcloud"); st.UpdatePhase != UpdatePhaseUndone {
|
|
t.Fatalf("the scenario must reach an undo; ended %q", st.UpdatePhase)
|
|
}
|
|
if strings.Contains(buf.String(), "docker-compose.yml unreadable") {
|
|
t.Fatalf("the undo logged a false backup-block ERROR:\n%s", buf.String())
|
|
}
|
|
// control: the validating loader on the same compose-less copy DOES log it (the line is real elsewhere)
|
|
buf.Reset()
|
|
LoadMetadata(filepath.Join(dir, preUpdateMetaDirForTest(t, dir, withBlock)))
|
|
if !strings.Contains(buf.String(), "docker-compose.yml unreadable") {
|
|
t.Fatal("control failed: LoadMetadata on a compose-less copy must still reject the block")
|
|
}
|
|
if pm := LoadProbeMetadata(filepath.Join(dir, "probe-copy")); pm.Backup != nil || pm.DataPaths != nil {
|
|
t.Fatal("the probe loader must never hand out a backup block")
|
|
}
|
|
}
|
|
|
|
// preUpdateMetaDirForTest writes a compose-less copy and returns its dir name (relative to dir).
|
|
func preUpdateMetaDirForTest(t *testing.T, dir, body string) string {
|
|
t.Helper()
|
|
d := filepath.Join(dir, "probe-copy")
|
|
if err := os.MkdirAll(d, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mustWrite(t, filepath.Join(d, ".felhom.yml"), body)
|
|
return "probe-copy"
|
|
}
|