package volsnap import ( "archive/tar" "compress/gzip" "io" "os" "path/filepath" "testing" ) func TestWriteArchiveRoundTrip(t *testing.T) { root := t.TempDir() mustWrite(t, filepath.Join(root, "a.txt"), "hello") if err := os.MkdirAll(filepath.Join(root, "sub"), 0o755); err != nil { t.Fatal(err) } mustWrite(t, filepath.Join(root, "sub", "b.txt"), "world") dest := filepath.Join(t.TempDir(), "snap.tar.gz") refs := []VolumeRef{{Target: "/data", Scope: "project", Source: "data", HostPath: root}} manifest, err := writeArchive(dest, refs) if err != nil { t.Fatalf("writeArchive: %v", err) } if len(manifest) != 1 || manifest[0].Index != 0 || manifest[0].Target != "/data" || manifest[0].Scope != "project" { t.Fatalf("unexpected manifest: %+v", manifest) } entries := readArchive(t, dest) for _, want := range []string{"0/a.txt", "0/sub/b.txt", "manifest.json"} { if _, ok := entries[want]; !ok { keys := make([]string, 0, len(entries)) for k := range entries { keys = append(keys, k) } t.Fatalf("archive missing %q; got %v", want, keys) } } if got := entries["0/a.txt"]; got != "hello" { t.Errorf("0/a.txt = %q, want %q", got, "hello") } } func TestWriteArchiveRefusesExisting(t *testing.T) { dest := filepath.Join(t.TempDir(), "snap.tar.gz") mustWrite(t, dest, "existing") if _, err := writeArchive(dest, nil); err == nil { t.Fatal("expected error writing over an existing file (O_EXCL)") } } func TestWriteArchiveSkipsSymlinks(t *testing.T) { root := t.TempDir() mustWrite(t, filepath.Join(root, "real.txt"), "data") if err := os.Symlink(filepath.Join(root, "real.txt"), filepath.Join(root, "link.txt")); err != nil { t.Skipf("symlinks unavailable on this platform: %v", err) } dest := filepath.Join(t.TempDir(), "snap.tar.gz") if _, err := writeArchive(dest, []VolumeRef{{Target: "/d", Scope: "project", HostPath: root}}); err != nil { t.Fatalf("writeArchive: %v", err) } entries := readArchive(t, dest) if _, ok := entries["0/link.txt"]; ok { t.Error("symlink should have been skipped, but it is in the archive") } if _, ok := entries["0/real.txt"]; !ok { t.Error("regular file should be archived") } } func mustWrite(t *testing.T, path, content string) { t.Helper() if err := os.WriteFile(path, []byte(content), 0o644); err != nil { t.Fatal(err) } } // readArchive returns a map of regular-file entry name -> content. Directory // entries are recorded with an empty string so their presence can be asserted. func readArchive(t *testing.T, path string) map[string]string { t.Helper() f, err := os.Open(path) if err != nil { t.Fatal(err) } defer f.Close() gz, err := gzip.NewReader(f) if err != nil { t.Fatal(err) } defer gz.Close() out := map[string]string{} tr := tar.NewReader(gz) for { hdr, err := tr.Next() if err == io.EOF { break } if err != nil { t.Fatal(err) } if hdr.Typeflag == tar.TypeDir { out[hdr.Name] = "" continue } data, err := io.ReadAll(tr) if err != nil { t.Fatal(err) } out[hdr.Name] = string(data) } return out }