diff options
Diffstat (limited to 'internal/apply/swap_test.go')
| -rw-r--r-- | internal/apply/swap_test.go | 90 |
1 files changed, 88 insertions, 2 deletions
diff --git a/internal/apply/swap_test.go b/internal/apply/swap_test.go index d16d3f9..297db72 100644 --- a/internal/apply/swap_test.go +++ b/internal/apply/swap_test.go @@ -4,6 +4,7 @@ package apply import ( "context" + "errors" "os" "path/filepath" "strings" @@ -156,7 +157,7 @@ func TestChainLoggedReportsEachStepBeforeTheNext(t *testing.T) { } } return nil - }) + }, nil) if err != nil || len(calls) != 2 || res[1].Status != "ok" { t.Fatalf("calls %v, err %v, results %+v", calls, err, res) } @@ -206,7 +207,7 @@ func TestChainLoggedStopsBetweenStepsWhenInterrupted(t *testing.T) { cancel() } return nil - }) + }, nil) if err != nil { t.Fatal(err) } @@ -217,3 +218,88 @@ func TestChainLoggedStopsBetweenStepsWhenInterrupted(t *testing.T) { t.Errorf("the finished step was undone or never ran: %v", err) } } + +// TestDisplaceIsReportedBeforeTheStepThatNeededIt: trashing the file in the +// way is a destructive act of its own, and it is durable the moment +// trash.Put returns. Reporting it only when the whole step finishes leaves +// a window - the entire data transfer of a copy or a cross-device move - +// in which the user's file is in the Trash with nothing recording that it +// went there. Killed in that window, krino log said "nothing applied". +func TestDisplaceIsReportedBeforeTheStepThatNeededIt(t *testing.T) { + root := t.TempDir() + // The Trash must be on the same filesystem as the file being trashed. + t.Setenv("XDG_DATA_HOME", filepath.Join(root, "share")) + src := filepath.Join(root, "a.pdf") + dst := filepath.Join(root, "W", "a.pdf") + if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(dst, []byte("the file already there"), 0o644); err != nil { + t.Fatal(err) + } + c := planned(t, root, "a.pdf", "incoming", + plan.Step{Kind: plan.Copy, Src: src, Dst: dst, Displaces: dst}, + ) + + var order []string + res, err := ChainLogged(context.Background(), c, + func(i int, sr StepResult) error { + order = append(order, "step") + return nil + }, + func(i int, step plan.Step, entry string) error { + order = append(order, "displace") + if entry == "" { + t.Error("the displace was reported with no trash entry") + } + // The file is in the Trash already; the copy has not begun. + if b, err := os.ReadFile(dst); err == nil && string(b) == "incoming" { + t.Error("the displace was reported only after the copy had run") + } + return nil + }) + if err != nil { + t.Fatal(err) + } + if len(order) != 2 || order[0] != "displace" || order[1] != "step" { + t.Errorf("order = %v; want the displace reported first", order) + } + if res[0].Status != "ok" { + t.Errorf("step = %+v", res[0]) + } +} + +// TestDisplaceThatCannotBeReportedFailsTheStep: if the displace cannot be +// written to the log, the step must not go on to use the name - the user's +// file is already in the Trash and nothing would record it. +func TestDisplaceThatCannotBeReportedFailsTheStep(t *testing.T) { + root := t.TempDir() + t.Setenv("XDG_DATA_HOME", filepath.Join(root, "share")) + src := filepath.Join(root, "a.pdf") + dst := filepath.Join(root, "W", "a.pdf") + if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(dst, []byte("the file already there"), 0o644); err != nil { + t.Fatal(err) + } + c := planned(t, root, "a.pdf", "incoming", + plan.Step{Kind: plan.Copy, Src: src, Dst: dst, Displaces: dst}, + ) + res, err := ChainLogged(context.Background(), c, nil, + func(i int, step plan.Step, entry string) error { + return errors.New("log is closed") + }) + if err != nil { + t.Fatal(err) + } + if res[0].Status != "failed" || !strings.Contains(res[0].Detail, "could not be logged") { + t.Errorf("step = %+v; want a failure naming the unlogged displace", res[0]) + } + if res[0].DisplacedEntry == "" { + t.Error("the failure does not carry the trash entry, so nothing can say where the file went") + } + if b, rerr := os.ReadFile(dst); rerr == nil && string(b) == "incoming" { + t.Error("the copy ran even though the displace could not be logged") + } +} |
