1package snapshot
2
3import (
4 "bytes"
5 "errors"
6 "os"
7 "path/filepath"
8 "testing"
9)
10
11func TestWriteImmutablePublishesAndReusesIdenticalData(t *testing.T) {
12 repo := NewRepository(privateDir(t))
13 dir := filepath.Join(repo.dir, "immutable")
14 if err := repo.ensurePrivateDirectory(dir); err != nil {
15 t.Fatal(err)
16 }
17
18 path := filepath.Join(dir, "object")
19 data := []byte("immutable")
20 verify := func(existing []byte) error {
21 if !bytes.Equal(existing, data) {
22 return errors.New("unexpected immutable data")
23 }
24 return nil
25 }
26 if err := repo.writeImmutable(path, data, verify); err != nil {
27 t.Fatal(err)
28 }
29 if err := repo.writeImmutable(path, data, verify); err != nil {
30 t.Fatal(err)
31 }
32 got, err := os.ReadFile(path)
33 if err != nil {
34 t.Fatal(err)
35 }
36 if !bytes.Equal(got, data) {
37 t.Fatalf("immutable data = %q, want %q", got, data)
38 }
39}
40
41func TestWithAtomicTempRemovesPublishedTemporaryFile(t *testing.T) {
42 repo := NewRepository(privateDir(t))
43 dir := filepath.Join(repo.dir, "temporary")
44 if err := repo.ensurePrivateDirectory(dir); err != nil {
45 t.Fatal(err)
46 }
47
48 var temporary string
49 if err := repo.withAtomicTemp(dir, []byte("data"), func(path string) (bool, error) {
50 temporary = path
51 info, err := os.Stat(path)
52 if err != nil {
53 return true, err
54 }
55 if got := info.Mode().Perm(); got != 0o600 {
56 t.Fatalf("temporary file mode = %o, want 600", got)
57 }
58 return true, nil
59 }); err != nil {
60 t.Fatal(err)
61 }
62 if _, err := os.Stat(temporary); !errors.Is(err, os.ErrNotExist) {
63 t.Fatalf("temporary file remains after publication: %v", err)
64 }
65}
66
67func TestWriteMutableConsumesTemporaryFile(t *testing.T) {
68 repo := NewRepository(privateDir(t))
69 path := filepath.Join(repo.dir, "HEAD")
70
71 if err := repo.writeMutable(path, []byte("head")); err != nil {
72 t.Fatalf("writeMutable error = %v", err)
73 }
74 got, err := os.ReadFile(path)
75 if err != nil {
76 t.Fatal(err)
77 }
78 if !bytes.Equal(got, []byte("head")) {
79 t.Fatalf("HEAD = %q, want %q", got, "head")
80 }
81 matches, err := filepath.Glob(filepath.Join(repo.dir, ".tmp-*"))
82 if err != nil || len(matches) != 0 {
83 t.Fatalf("temporary files after mutable write = %v, glob error = %v", matches, err)
84 }
85}