~bigbes/ci-cacher

ref: c22d27ee9830bc6ed3152c1df526b47ef59e5315 ci-cacher/internal/hash/hash_test.go -rw-r--r-- 3.4 KiB
c22d27ee — Eugene Blikh test.yml: collapse cache_garage_image to single 'cacher docker download --pull' a day ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package hash

import (
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
)

// TestSingleFileMatchesSha256sumCutC116 asserts the central parity claim:
// Derive([f], 16) == `sha256sum f | cut -c1-16`. This is what the existing
// shell helper does (HASH=$(sha256sum docker/conformance.Dockerfile | cut -c1-16))
// and the new tool must produce the same key for the same input.
func TestSingleFileMatchesSha256sumCutC116(t *testing.T) {
	if _, err := exec.LookPath("sha256sum"); err != nil {
		t.Skip("sha256sum not on PATH; skipping shell parity check")
	}
	path := filepath.Join(t.TempDir(), "sample")
	if err := os.WriteFile(path, []byte("hello world\n"), 0o600); err != nil {
		t.Fatal(err)
	}
	out, err := exec.Command("sha256sum", path).Output()
	if err != nil {
		t.Fatalf("sha256sum: %v", err)
	}
	want := strings.Fields(string(out))[0][:16]

	got, err := Derive([]string{path}, 16)
	if err != nil {
		t.Fatalf("Derive: %v", err)
	}
	if got != want {
		t.Errorf("Derive=%q  want=%q", got, want)
	}
}

func TestDirHashIsStable(t *testing.T) {
	dir := t.TempDir()
	mustWrite := func(rel, body string) {
		p := filepath.Join(dir, rel)
		if err := os.MkdirAll(filepath.Dir(p), 0o700); err != nil {
			t.Fatal(err)
		}
		if err := os.WriteFile(p, []byte(body), 0o600); err != nil {
			t.Fatal(err)
		}
	}
	mustWrite("a/x", "x-body")
	mustWrite("b/y/z", "z-body")

	h1, err := Derive([]string{dir}, 32)
	if err != nil {
		t.Fatal(err)
	}
	h2, err := Derive([]string{dir}, 32)
	if err != nil {
		t.Fatal(err)
	}
	if h1 != h2 {
		t.Errorf("dir hash not stable: %q vs %q", h1, h2)
	}
}

func TestDirHashChangesOnContentChange(t *testing.T) {
	dir := t.TempDir()
	path := filepath.Join(dir, "f")
	_ = os.WriteFile(path, []byte("v1"), 0o600)
	h1, _ := Derive([]string{dir}, 32)
	_ = os.WriteFile(path, []byte("v2"), 0o600)
	h2, _ := Derive([]string{dir}, 32)
	if h1 == h2 {
		t.Error("dir hash unchanged after content change")
	}
}

func TestMultiPathCombines(t *testing.T) {
	dir := t.TempDir()
	a := filepath.Join(dir, "a")
	b := filepath.Join(dir, "b")
	_ = os.WriteFile(a, []byte("A"), 0o600)
	_ = os.WriteFile(b, []byte("B"), 0o600)

	ha, _ := Derive([]string{a}, 16)
	hab, _ := Derive([]string{a, b}, 16)
	hba, _ := Derive([]string{b, a}, 16)
	if ha == hab {
		t.Error("combining two paths produced same hash as single path")
	}
	if hab == hba {
		t.Error("order of --hash-from paths should matter")
	}
}

func TestApplyTemplateHashPlaceholder(t *testing.T) {
	got := ApplyTemplate("img/{hash}.tar.zst", "abcd1234", "linux", "amd64", false)
	if got != "img/abcd1234.tar.zst" {
		t.Errorf("ApplyTemplate placeholder = %q", got)
	}
}

func TestApplyTemplateNoPlaceholderAppends(t *testing.T) {
	got := ApplyTemplate("img/build.tar.zst", "abcd1234", "linux", "amd64", false)
	if got != "img/build-abcd1234.tar.zst" {
		t.Errorf("ApplyTemplate append = %q", got)
	}
}

func TestApplyTemplateArchSuffix(t *testing.T) {
	got := ApplyTemplate("img/build.tar.zst", "abcd", "linux", "amd64", true)
	if got != "img/build-abcd-linux-amd64.tar.zst" {
		t.Errorf("ApplyTemplate arch = %q", got)
	}
}

func TestApplyTemplateArchSuffixSimpleExt(t *testing.T) {
	got := ApplyTemplate("bin/cacher", "", "linux", "amd64", true)
	if got != "bin/cacher-linux-amd64" {
		t.Errorf("ApplyTemplate arch no-ext = %q", got)
	}
}

func TestDeriveRejectsEmpty(t *testing.T) {
	if _, err := Derive(nil, 16); err == nil {
		t.Error("expected error for empty paths")
	}
}