70 lines
3 KiB
Go
70 lines
3 KiB
Go
package runner
|
|
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
// The one claim this platform makes about `tmctl backup` that no unit test can make: that the LINE
|
|
// this side parses is the line THIS ENGINE prints, and that what it names is a file.
|
|
//
|
|
// ⚠ It is the whole reason the parse is allowed to exist. Reading a path out of another zone's prose
|
|
// is a coupling with no version on it (17-seam-inbound-law п.3), and the only honest way to hold it
|
|
// is against the real binary — a fixture string would prove that this file agrees with itself.
|
|
// When the engine grows a `--out` or a `--json` on this verb, this test is what says the prose form
|
|
// may go.
|
|
//
|
|
// Gated like every live-engine test: a bare clone stays green and says why.
|
|
func TestTheRealEngineNamesItsRestorePointInTheLineThisPlatformParses(t *testing.T) {
|
|
bin := os.Getenv("TM_PLATFORM_TEST_ENGINE_BIN")
|
|
tpl := os.Getenv("TM_PLATFORM_TEST_BOOK_TEMPLATE")
|
|
if bin == "" || tpl == "" {
|
|
t.Skip("TM_PLATFORM_TEST_ENGINE_BIN and TM_PLATFORM_TEST_BOOK_TEMPLATE not set: " +
|
|
"the backup verb's output is not checked against a real engine")
|
|
}
|
|
dir := t.TempDir()
|
|
writeProbeBook(t, tpl, dir, "bk_BACKUPPROBE")
|
|
|
|
// A book with no project database is the state a fresh directory is in, and the engine refuses
|
|
// there rather than failing — pinned first, because that refusal is what the backup pass reads as
|
|
// "nothing to copy yet" and it must not be an error.
|
|
empty, err := New(nil).Backup(t.Context(), bin, dir)
|
|
if err != nil {
|
|
t.Fatalf("a book with no database raised an error instead of answering: %v", err)
|
|
}
|
|
if !empty.Exited || empty.ExitCode == 0 || empty.Path != "" {
|
|
t.Fatalf("a book with no database was reported as backed up: %+v", empty)
|
|
}
|
|
|
|
// `manifest` is the $0 verb that CREATES and migrates the project database (backend/cmd/tmctl,
|
|
// manifestCmd: "it opens the store exactly as `status` does … EXCEPT on the first touch").
|
|
cmd := exec.CommandContext(t.Context(), bin, "manifest", "--config", filepath.Join(dir, ConfigFile))
|
|
cmd.Dir = dir
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
t.Fatalf("could not give the probe book a project database: %v\n%s", err, out)
|
|
}
|
|
|
|
out, err := New(nil).Backup(t.Context(), bin, dir)
|
|
if err != nil {
|
|
t.Fatalf("the live backup verb was not readable: %v (stderr %q)", err, out.Stderr)
|
|
}
|
|
if !out.Exited || out.ExitCode != 0 {
|
|
t.Fatalf("the live backup verb refused: %+v (stderr %q)", out, out.Stderr)
|
|
}
|
|
if out.Path == "" {
|
|
t.Fatal("the live backup verb exited 0 and this platform read no path out of it")
|
|
}
|
|
fi, err := os.Stat(out.Path)
|
|
if err != nil {
|
|
t.Fatalf("the path this platform parsed is not a file: %v", err)
|
|
}
|
|
if fi.Size() == 0 {
|
|
t.Errorf("the restore point the engine named is empty: %s", out.Path)
|
|
}
|
|
// Inside the book, which is the guard the parse enforces and the copier relies on.
|
|
if rel, err := filepath.Rel(dir, out.Path); err != nil || rel == ".." {
|
|
t.Errorf("the engine's restore point is not inside the book's directory: %s", out.Path)
|
|
}
|
|
}
|