aboutsummaryrefslogtreecommitdiff
path: root/internal/apply/swap_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/apply/swap_test.go')
-rw-r--r--internal/apply/swap_test.go90
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")
+ }
+}