delivery.NamedTree hashes the manifest digest with each named path's git object; catalogue.Manifest.NamedPaths gives the union of the paths, only when every artifact names some. The named: prefix keeps the value apart from a git tree id.
69 lines
2.9 KiB
Go
69 lines
2.9 KiB
Go
package delivery
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func sha256Of(s string) string { h := sha256.Sum256([]byte(s)); return hex.EncodeToString(h[:]) }
|
|
|
|
// A module whose every artifact names its paths takes its tree from its manifest and those paths alone (novox/hq ADR
|
|
// 0499 clause 2): a change outside them leaves the value equal, a change to a named path or to the manifest changes it,
|
|
// and the order the paths are given in changes nothing.
|
|
func TestTheNamedTreeIsOfTheManifestAndTheNamedPathsAlone(t *testing.T) {
|
|
manifest := sha256Of(`{"module":"mesh-sdk"}`)
|
|
paths := map[string]string{"src": strings.Repeat("a", 40), "package.json": strings.Repeat("b", 40)}
|
|
v, err := NamedTree(manifest, paths)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.HasPrefix(v, NamedTreePrefix) || !isHex64(strings.TrimPrefix(v, NamedTreePrefix)) {
|
|
t.Fatalf("the value %q is not %s and 64 hex digits", v, NamedTreePrefix)
|
|
}
|
|
// A change outside the named paths is no input at all: the same inputs give the same value, in any map order.
|
|
again, _ := NamedTree(manifest, map[string]string{"package.json": strings.Repeat("b", 40), "src": strings.Repeat("a", 40)})
|
|
if again != v {
|
|
t.Fatalf("the same inputs gave %q and %q", v, again)
|
|
}
|
|
changed, _ := NamedTree(manifest, map[string]string{"src": strings.Repeat("c", 40), "package.json": strings.Repeat("b", 40)})
|
|
if changed == v {
|
|
t.Fatal("a changed named path left the value equal")
|
|
}
|
|
otherManifest, _ := NamedTree(sha256Of(`{"module":"mesh-sdk","version":"2"}`), paths)
|
|
if otherManifest == v {
|
|
t.Fatal("a changed manifest left the value equal")
|
|
}
|
|
renamed, _ := NamedTree(manifest, map[string]string{"lib": strings.Repeat("a", 40), "package.json": strings.Repeat("b", 40)})
|
|
if renamed == v {
|
|
t.Fatal("a path named differently with the same object left the value equal")
|
|
}
|
|
|
|
// The lines are fixed, so every computation of it agrees: pinned here.
|
|
want := "named:" + sha256Of("manifest "+manifest+"\npath package.json "+strings.Repeat("b", 40)+"\npath src "+strings.Repeat("a", 40))
|
|
if v != want {
|
|
t.Fatalf("NamedTree = %q, want %q", v, want)
|
|
}
|
|
}
|
|
|
|
func TestTheNamedTreeRefusesWhatItCannotPin(t *testing.T) {
|
|
manifest := sha256Of("{}")
|
|
for _, c := range []struct {
|
|
manifest string
|
|
paths map[string]string
|
|
says string
|
|
}{
|
|
{manifest, nil, "names no path"},
|
|
{manifest, map[string]string{"src": ""}, `the named path "src" has no git object`},
|
|
{"abc", map[string]string{"src": "x"}, "not a manifest digest"},
|
|
{manifest, map[string]string{"src/../x": "x"}, "is not a clean path"},
|
|
{manifest, map[string]string{"": "x"}, "is not a clean path"},
|
|
{manifest, map[string]string{"/src": "x"}, "is not a clean path"},
|
|
} {
|
|
if _, err := NamedTree(c.manifest, c.paths); err == nil || !strings.Contains(err.Error(), c.says) {
|
|
t.Errorf("NamedTree(%q, %v) = %v, wanted a refusal saying %q", c.manifest, c.paths, err, c.says)
|
|
}
|
|
}
|
|
}
|