Keep an original by its path and its content, so a second original at one path is not discarded (hq ADR 0100)
This commit is contained in:
+11
-5
@@ -22,13 +22,19 @@ import (
|
||||
// first copy is the one that was there before the mesh.
|
||||
type Keep func(path string, content []byte, mode os.FileMode) (string, error)
|
||||
|
||||
// KeepIn keeps originals under dir/kept, each named for the path it came from, readable by root
|
||||
// alone — a predecessor's configuration may carry its credentials.
|
||||
// KeepIn keeps originals under dir/kept, each named for the path it came from AND for what was in
|
||||
// it, readable by root alone — a predecessor's configuration may carry its credentials.
|
||||
//
|
||||
// **By content as well as path, because a path has more than one original.** A file held, let go
|
||||
// when its module was unassigned, rewritten by the predecessor and found again is a second
|
||||
// original; named by path alone the second copy was silently discarded while the report said it
|
||||
// was kept (novox/hq ADR 0100). The same content at the same path is kept once.
|
||||
func KeepIn(dir string) Keep {
|
||||
return func(path string, content []byte, _ os.FileMode) (string, error) {
|
||||
sum := sha256.Sum256([]byte(path))
|
||||
kept := filepath.Join(dir, "kept",
|
||||
hex.EncodeToString(sum[:])[:16]+"-"+filepath.Base(path))
|
||||
where := sha256.Sum256([]byte(path))
|
||||
what := sha256.Sum256(content)
|
||||
kept := filepath.Join(dir, "kept", hex.EncodeToString(where[:])[:12]+"-"+
|
||||
hex.EncodeToString(what[:])[:12]+"-"+filepath.Base(path))
|
||||
if _, err := os.Lstat(kept); err == nil {
|
||||
return kept, nil
|
||||
}
|
||||
|
||||
@@ -382,8 +382,13 @@ func TestAHoldNoLongerDeclaredIsLetGoAndFoundAgainIfItsModuleReturns(t *testing.
|
||||
t.Fatalf("a returning module's found file was not held again: %+v", o)
|
||||
}
|
||||
again, _ := state.HeldAt("hello-web.page")
|
||||
if kept, _ := os.ReadFile(again.Kept); again.Kept != first.Kept || string(kept) != "the predecessor's page\n" {
|
||||
t.Errorf("the first kept original was lost: %s %q", again.Kept, kept)
|
||||
// The predecessor rewrote it while nothing held it, so that is a second original, kept beside
|
||||
// the first rather than in place of it (novox/hq ADR 0100).
|
||||
if kept, _ := os.ReadFile(again.Kept); string(kept) != "the predecessor wrote again\n" {
|
||||
t.Errorf("what is named as kept is %q", kept)
|
||||
}
|
||||
if kept, _ := os.ReadFile(first.Kept); string(kept) != "the predecessor's page\n" {
|
||||
t.Errorf("the first kept original was lost: %q", kept)
|
||||
}
|
||||
if got, _ := os.ReadFile(page); string(got) != "the predecessor wrote again\n" {
|
||||
t.Errorf("the found file was touched: %q", got)
|
||||
@@ -958,3 +963,60 @@ func TestAPackagedUnitTheMachineUsesIsStillHeld(t *testing.T) {
|
||||
t.Errorf("the predecessor's service was restarted: %v", m.asked)
|
||||
}
|
||||
}
|
||||
|
||||
func TestASecondOriginalAtTheSamePathIsKeptToo(t *testing.T) {
|
||||
// Held, let go when the module was unassigned, rewritten by the predecessor, found again:
|
||||
// both originals are kept, and the report names the one it kept (novox/hq ADR 0100).
|
||||
dir := t.TempDir()
|
||||
page := filepath.Join(dir, "index.html")
|
||||
keep := KeepIn(dir)
|
||||
first, err := keep(page, []byte("the predecessor's page\n"), 0o640)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
same, err := keep(page, []byte("the predecessor's page\n"), 0o640)
|
||||
if err != nil || same != first {
|
||||
t.Errorf("the same original was kept twice: %s %s %v", first, same, err)
|
||||
}
|
||||
second, err := keep(page, []byte("the predecessor wrote again\n"), 0o640)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if second == first {
|
||||
t.Fatal("a second original was kept under the first's name")
|
||||
}
|
||||
if got, _ := os.ReadFile(first); string(got) != "the predecessor's page\n" {
|
||||
t.Errorf("the first original is %q", got)
|
||||
}
|
||||
if got, _ := os.ReadFile(second); string(got) != "the predecessor wrote again\n" {
|
||||
t.Errorf("the second original is %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAHoldLetGoAndFoundAgainKeepsBothOriginals(t *testing.T) {
|
||||
dir, page, m := predecessor(t)
|
||||
_, state := applyAdopted(t, adopted(t, untaken("hello-web.page", "hello-web.server"), webResources(page)),
|
||||
store.State{}, m, dir)
|
||||
first, _ := state.HeldAt("hello-web.page")
|
||||
|
||||
// Unassigned, then the predecessor writes again, then assigned once more.
|
||||
_, state = applyAdopted(t, adopted(t, `{"taken":[]}`, withConf(dir)), state, m, dir)
|
||||
if err := os.WriteFile(page, []byte("the predecessor wrote again\n"), 0o640); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
report, state := applyAdopted(t, adopted(t, untaken("hello-web.page", "hello-web.server"), webResources(page)),
|
||||
state, m, dir)
|
||||
again, _ := state.HeldAt("hello-web.page")
|
||||
if again.Kept == first.Kept {
|
||||
t.Fatalf("the second original was kept under the first's name: %s", again.Kept)
|
||||
}
|
||||
if got, _ := os.ReadFile(again.Kept); string(got) != "the predecessor wrote again\n" {
|
||||
t.Errorf("what the report names as kept is %q", got)
|
||||
}
|
||||
if got, _ := os.ReadFile(first.Kept); string(got) != "the predecessor's page\n" {
|
||||
t.Errorf("the first original was lost: %q", got)
|
||||
}
|
||||
if o := outcomeOf(report, "hello-web.page"); o.Action != "held" {
|
||||
t.Errorf("the file found again was not held: %+v", o)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user