tinyrelayfile
tinyrelay/internal/blob/metadata_test.go/

internal/blob/metadata_test.go raw
1package blob
2
3import (
4 "context"
5 "errors"
6 "net/http"
7 "net/http/httptest"
8 "strings"
9 "testing"
10)
11
12func TestUploadStoresClaimScopedNameAndPath(t *testing.T) {
13 s := testService(t)
14 body := "same bytes"
15 request := httptest.NewRequest(http.MethodPut, "https://relay.test/upload?filename=note.txt&path=docs%2Fnote.txt", strings.NewReader(body))
16 request.Header.Set("Content-Type", "text/plain")
17 if response := record(s.Handler(), request); response.Code != http.StatusOK {
18 t.Fatalf("upload status = %d: %s", response.Code, response.Body.String())
19 }
20 entries, err := s.ListClaimMetadata(context.Background(), "uploader")
21 if err != nil || len(entries) != 1 || entries[0].Name != "note.txt" || entries[0].Path != "docs/note.txt" {
22 t.Fatalf("metadata = %+v, %v", entries, err)
23 }
24 other := strings.Repeat("b", 64)
25 if _, err := s.Put(context.Background(), PutOptions{Reader: strings.NewReader(body), Type: "text/plain", Uploader: other, Name: "other.txt", Path: "other.txt"}); err != nil {
26 t.Fatal(err)
27 }
28 entries, err = s.ListClaimMetadata(context.Background(), other)
29 if err != nil || len(entries) != 1 || entries[0].Name != "other.txt" {
30 t.Fatalf("deduplicated metadata = %+v, %v", entries, err)
31 }
32}
33
34func TestBlobAccessIsDurableAndCannotChangeOnDeduplication(t *testing.T) {
35 s := testService(t)
36 ctx := context.Background()
37 entry, err := s.Put(ctx, PutOptions{Reader: strings.NewReader("member bytes"), Type: "text/plain", Uploader: "uploader", Access: AccessMembers})
38 if err != nil {
39 t.Fatal(err)
40 }
41 if access, err := s.BlobAccess(ctx, entry.SHA256); err != nil || access != AccessMembers {
42 t.Fatalf("access = %q, %v", access, err)
43 }
44 if _, err := s.Put(ctx, PutOptions{Reader: strings.NewReader("member bytes"), Type: "text/plain", Uploader: "other", Access: AccessPublic}); !errors.Is(err, ErrAccessConflict) {
45 t.Fatalf("public deduplication error = %v", err)
46 }
47 if access, err := s.BlobAccess(ctx, entry.SHA256); err != nil || access != AccessMembers {
48 t.Fatalf("access changed after rejected deduplication = %q, %v", access, err)
49 }
50}
51
52func TestValidateClaimPath(t *testing.T) {
53 for _, path := range []string{"", "file.txt", "dir/file.txt"} {
54 if _, err := validateClaimPath(path); err != nil {
55 t.Errorf("validateClaimPath(%q): %v", path, err)
56 }
57 }
58 for _, path := range []string{"/file.txt", "../file.txt", "dir/../../file.txt", "dir/../secret.txt", "dir/./file.txt", "dir//file.txt", "dir\\file.txt", "dir/", "a\x00b"} {
59 if _, err := validateClaimPath(path); err == nil {
60 t.Errorf("validateClaimPath(%q) succeeded", path)
61 }
62 }
63 if !errors.Is(validateClaimName("dir/file.txt"), errInvalidClaimName) {
64 t.Fatal("path was accepted as a filename")
65 }
66 if _, _, err := claimMetadata("other.txt", "dir/file.txt"); !errors.Is(err, errMismatchedClaimName) {
67 t.Fatalf("mismatched filename accepted: %v", err)
68 }
69 if name, cleanPath, err := claimMetadata("", "dir/file.txt"); err != nil || name != "file.txt" || cleanPath != "dir/file.txt" {
70 t.Fatalf("path basename metadata = %q, %q, %v", name, cleanPath, err)
71 }
72 if err := validateClaimName(string([]byte{0xff})); !errors.Is(err, errInvalidClaimName) {
73 t.Fatalf("invalid UTF-8 filename accepted: %v", err)
74 }
75}
76
77func TestIdenticalFilesPreserveDistinctFolderPaths(t *testing.T) {
78 s := testService(t)
79 ctx := context.Background()
80 for _, filePath := range []string{"one/note.txt", "two/note.txt", "one/note.txt"} {
81 if _, err := s.Put(ctx, PutOptions{Reader: strings.NewReader("same bytes"), Type: "text/plain", Uploader: "uploader", Name: "note.txt", Path: filePath}); err != nil {
82 t.Fatal(err)
83 }
84 }
85 entries, err := s.ListClaimMetadata(ctx, "uploader")
86 if err != nil || len(entries) != 2 {
87 t.Fatalf("distinct paths lost or repeated: %#v, %v", entries, err)
88 }
89 if entries[0].SHA256 != entries[1].SHA256 || entries[0].Path == entries[1].Path {
90 t.Fatalf("same content should retain both paths: %#v", entries)
91 }
92}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs