package main_test import ( "encoding/json" "os" "os/exec" "path/filepath" "strings" "testing" ) // A failed snapshot dump keeps and says the real exit status (a container killed by a signal answers // 137), names the container's state, and leaves no partial archive. func TestTheDumpKeepsAndSaysTheStatusOfAFailedSnapshot(t *testing.T) { raw, err := os.ReadFile("module.json") if err != nil { t.Fatal(err) } var m struct { Data struct { Own []struct { ID string `json:"id"` Backup struct { Dump string `json:"dump"` } `json:"backup"` } `json:"own"` } `json:"data"` } if err := json.Unmarshal(raw, &m); err != nil { t.Fatal(err) } dump := "" for _, d := range m.Data.Own { if d.ID == "jetstream" { dump = d.Backup.Dump } } for _, c := range []struct { name string status string want string }{{"killed", "137", "exited 137 (killed by a signal)"}, {"failed", "3", "exited 3"}} { dir := t.TempDir() bin := filepath.Join(dir, "bin") os.MkdirAll(bin, 0o755) fake := "#!/bin/sh\nif [ \"$1\" = inspect ]; then echo 'container exited since yesterday'; exit 0; fi\necho partial-bytes\nexit " + c.status + "\n" os.WriteFile(filepath.Join(bin, "docker"), []byte(fake), 0o755) os.WriteFile(filepath.Join(dir, "broker"), nil, 0o644) cmdline := strings.NewReplacer("${dir:snapshots}", dir, "${dir:mesh-state}", dir).Replace(dump) cmd := exec.Command("sh", "-c", cmdline) cmd.Env = []string{"PATH=" + bin + ":/usr/bin:/bin"} out, err := cmd.CombinedOutput() ee, ok := err.(*exec.ExitError) if !ok || ee.ExitCode() != atoi(c.status) { t.Errorf("%s: exit %v, want %s; output %s", c.name, err, c.status, out) } if !strings.Contains(string(out), c.want) || !strings.Contains(string(out), "container exited since") { t.Errorf("%s: output %q", c.name, out) } if _, err := os.Stat(filepath.Join(dir, "bus.tar.partial")); err == nil { t.Errorf("%s: partial left", c.name) } } } func atoi(s string) int { n := 0 for _, r := range s { n = n*10 + int(r-'0') } return n }