diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-14 21:26:12 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-14 21:26:12 +0200 |
| commit | 3bfafbc8664a2a1ba8efc3f64376ff63c3dc11b9 (patch) | |
| tree | 1b2de6bd79c7c0225a2f3e4a0fccc51c3cc627ba /internal/apply/swap_test.go | |
| parent | 8c6afca96a9f0af41c5a9d05beb7f1dedb994740 (diff) | |
| download | krino-3bfafbc8664a2a1ba8efc3f64376ff63c3dc11b9.tar.gz krino-3bfafbc8664a2a1ba8efc3f64376ff63c3dc11b9.zip | |
plan 9: apply logs each step as it completes and stops a chain that landed elsewhere
Diffstat (limited to 'internal/apply/swap_test.go')
| -rw-r--r-- | internal/apply/swap_test.go | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/internal/apply/swap_test.go b/internal/apply/swap_test.go index fe7542e..c185686 100644 --- a/internal/apply/swap_test.go +++ b/internal/apply/swap_test.go @@ -99,3 +99,89 @@ func TestChainFollowsItsOwnFile(t *testing.T) { } } } + +// TestChainStopsWhenAStepLandsElsewhere: a move that found its planned name +// taken at apply time lands at a free name, and every later step - planned +// against the name it did not get - is skipped rather than acting on +// whatever is at the planned path (review M3). +func TestChainStopsWhenAStepLandsElsewhere(t *testing.T) { + root := t.TempDir() + p := filepath.Join(root, "a.pdf") + plannedPath := filepath.Join(root, "W", "a.pdf") + c := planned(t, root, "a.pdf", "planned-file", + plan.Step{Kind: plan.Move, Src: p, Dst: plannedPath}, + plan.Step{Kind: plan.DeletePermanent, Src: plannedPath}, + ) + if err := os.MkdirAll(filepath.Dir(plannedPath), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(plannedPath, []byte("OTHER--FILE!"), 0o644); err != nil { + t.Fatal(err) + } + if err := os.Chtimes(plannedPath, c.File.ModTime, c.File.ModTime); err != nil { + t.Fatal(err) + } + res := Chain(c) + if res[0].Status != "ok" || res[1].Status != "skipped" || !strings.Contains(res[1].Detail, "not the planned") { + t.Fatalf("steps = %s %q, %s %q; want ok, then skipped naming the planned path", res[0].Status, res[0].Dst, res[1].Status, res[1].Detail) + } + if b, err := os.ReadFile(plannedPath); err != nil || string(b) != "OTHER--FILE!" { + t.Errorf("the file at the planned path was acted on: %q %v", b, err) + } +} + +// TestChainLoggedReportsEachStepBeforeTheNext: done is called for each step +// as soon as it has run - the file is at the first step's destination and +// the second step has not happened yet - so a caller logging from done +// never has a completed step missing from the log (review M9). +func TestChainLoggedReportsEachStepBeforeTheNext(t *testing.T) { + root := t.TempDir() + p := filepath.Join(root, "a.pdf") + moved := filepath.Join(root, "W", "a.pdf") + renamed := filepath.Join(root, "W", "b.pdf") + c := planned(t, root, "a.pdf", "body", + plan.Step{Kind: plan.Move, Src: p, Dst: moved}, + plan.Step{Kind: plan.Rename, Src: moved, Dst: renamed}, + ) + var calls []int + res, err := ChainLogged(c, func(i int, sr StepResult) error { + calls = append(calls, i) + if i == 0 { + if _, err := os.Lstat(moved); err != nil { + t.Errorf("at done(0) the move has not happened: %v", err) + } + if _, err := os.Lstat(renamed); !os.IsNotExist(err) { + t.Errorf("at done(0) the rename already happened") + } + } + return nil + }) + if err != nil || len(calls) != 2 || res[1].Status != "ok" { + t.Fatalf("calls %v, err %v, results %+v", calls, err, res) + } +} + +// TestChainRefusesToDisplaceANonRegularTarget: the file overwrite was +// planned to replace is re-checked before it is trashed; a directory now in +// its place is left alone (review M4). +func TestChainRefusesToDisplaceANonRegularTarget(t *testing.T) { + root := t.TempDir() + t.Setenv("HOME", root) + t.Setenv("XDG_DATA_HOME", filepath.Join(root, "share")) + t.Setenv("XDG_STATE_HOME", "") + t.Setenv("XDG_CONFIG_HOME", "") + t.Setenv("XDG_CACHE_HOME", "") + p := filepath.Join(root, "a.pdf") + target := filepath.Join(root, "W", "a.pdf") + c := planned(t, root, "a.pdf", "body", plan.Step{Kind: plan.Move, Src: p, Dst: target, Displaces: target}) + if err := os.MkdirAll(filepath.Join(target, "inside"), 0o755); err != nil { + t.Fatal(err) + } + res := Chain(c) + if res[0].Status != "failed" { + t.Fatalf("step = %s %q; want failed", res[0].Status, res[0].Detail) + } + if _, err := os.Stat(filepath.Join(target, "inside")); err != nil { + t.Errorf("the directory was displaced: %v", err) + } +} |
