github.com/mckael/restic@v0.8.3/internal/archiver/archive_reader_test.go (about) 1 package archiver 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "io" 8 "math/rand" 9 "testing" 10 11 "github.com/restic/restic/internal/checker" 12 "github.com/restic/restic/internal/repository" 13 "github.com/restic/restic/internal/restic" 14 ) 15 16 func loadBlob(t *testing.T, repo restic.Repository, id restic.ID, buf []byte) int { 17 n, err := repo.LoadBlob(context.TODO(), restic.DataBlob, id, buf) 18 if err != nil { 19 t.Fatalf("LoadBlob(%v) returned error %v", id, err) 20 } 21 22 return n 23 } 24 25 func checkSavedFile(t *testing.T, repo restic.Repository, treeID restic.ID, name string, rd io.Reader) { 26 tree, err := repo.LoadTree(context.TODO(), treeID) 27 if err != nil { 28 t.Fatalf("LoadTree() returned error %v", err) 29 } 30 31 if len(tree.Nodes) != 1 { 32 t.Fatalf("wrong number of nodes for tree, want %v, got %v", 1, len(tree.Nodes)) 33 } 34 35 node := tree.Nodes[0] 36 if node.Name != "fakefile" { 37 t.Fatalf("wrong filename, want %v, got %v", "fakefile", node.Name) 38 } 39 40 if len(node.Content) == 0 { 41 t.Fatalf("node.Content has length 0") 42 } 43 44 // check blobs 45 for i, id := range node.Content { 46 size, found := repo.LookupBlobSize(id, restic.DataBlob) 47 if !found { 48 t.Fatal("Failed to find blob", id.Str()) 49 } 50 51 buf := restic.NewBlobBuffer(int(size)) 52 n := loadBlob(t, repo, id, buf) 53 if n != len(buf) { 54 t.Errorf("wrong number of bytes read, want %d, got %d", len(buf), n) 55 } 56 57 buf2 := make([]byte, int(size)) 58 _, err := io.ReadFull(rd, buf2) 59 if err != nil { 60 t.Fatal(err) 61 } 62 63 if !bytes.Equal(buf, buf2) { 64 t.Fatalf("blob %d (%v) is wrong", i, id.Str()) 65 } 66 } 67 } 68 69 // fakeFile returns a reader which yields deterministic pseudo-random data. 70 func fakeFile(t testing.TB, seed, size int64) io.Reader { 71 return io.LimitReader(restic.NewRandReader(rand.New(rand.NewSource(seed))), size) 72 } 73 74 func TestArchiveReader(t *testing.T) { 75 repo, cleanup := repository.TestRepository(t) 76 defer cleanup() 77 78 seed := rand.Int63() 79 size := int64(rand.Intn(50*1024*1024) + 50*1024*1024) 80 t.Logf("seed is 0x%016x, size is %v", seed, size) 81 82 f := fakeFile(t, seed, size) 83 84 r := &Reader{ 85 Repository: repo, 86 Hostname: "localhost", 87 Tags: []string{"test"}, 88 } 89 90 sn, id, err := r.Archive(context.TODO(), "fakefile", f, nil) 91 if err != nil { 92 t.Fatalf("ArchiveReader() returned error %v", err) 93 } 94 95 if id.IsNull() { 96 t.Fatalf("ArchiveReader() returned null ID") 97 } 98 99 t.Logf("snapshot saved as %v, tree is %v", id.Str(), sn.Tree.Str()) 100 101 checkSavedFile(t, repo, *sn.Tree, "fakefile", fakeFile(t, seed, size)) 102 103 checker.TestCheckRepo(t, repo) 104 } 105 106 func TestArchiveReaderNull(t *testing.T) { 107 repo, cleanup := repository.TestRepository(t) 108 defer cleanup() 109 110 r := &Reader{ 111 Repository: repo, 112 Hostname: "localhost", 113 Tags: []string{"test"}, 114 } 115 116 sn, id, err := r.Archive(context.TODO(), "fakefile", bytes.NewReader(nil), nil) 117 if err != nil { 118 t.Fatalf("ArchiveReader() returned error %v", err) 119 } 120 121 if id.IsNull() { 122 t.Fatalf("ArchiveReader() returned null ID") 123 } 124 125 t.Logf("snapshot saved as %v, tree is %v", id.Str(), sn.Tree.Str()) 126 127 checker.TestCheckRepo(t, repo) 128 } 129 130 type errReader string 131 132 func (e errReader) Read([]byte) (int, error) { 133 return 0, errors.New(string(e)) 134 } 135 136 func countSnapshots(t testing.TB, repo restic.Repository) int { 137 snapshots := 0 138 err := repo.List(context.TODO(), restic.SnapshotFile, func(id restic.ID, size int64) error { 139 snapshots++ 140 return nil 141 }) 142 if err != nil { 143 t.Fatal(err) 144 } 145 return snapshots 146 } 147 148 func TestArchiveReaderError(t *testing.T) { 149 repo, cleanup := repository.TestRepository(t) 150 defer cleanup() 151 152 r := &Reader{ 153 Repository: repo, 154 Hostname: "localhost", 155 Tags: []string{"test"}, 156 } 157 158 sn, id, err := r.Archive(context.TODO(), "fakefile", errReader("error returned by reading stdin"), nil) 159 if err == nil { 160 t.Errorf("expected error not returned") 161 } 162 163 if sn != nil { 164 t.Errorf("Snapshot should be nil, but isn't") 165 } 166 167 if !id.IsNull() { 168 t.Errorf("id should be null, but %v returned", id.Str()) 169 } 170 171 n := countSnapshots(t, repo) 172 if n > 0 { 173 t.Errorf("expected zero snapshots, but got %d", n) 174 } 175 176 checker.TestCheckRepo(t, repo) 177 } 178 179 func BenchmarkArchiveReader(t *testing.B) { 180 repo, cleanup := repository.TestRepository(t) 181 defer cleanup() 182 183 const size = 50 * 1024 * 1024 184 185 buf := make([]byte, size) 186 _, err := io.ReadFull(fakeFile(t, 23, size), buf) 187 if err != nil { 188 t.Fatal(err) 189 } 190 191 r := &Reader{ 192 Repository: repo, 193 Hostname: "localhost", 194 Tags: []string{"test"}, 195 } 196 197 t.SetBytes(size) 198 t.ResetTimer() 199 200 for i := 0; i < t.N; i++ { 201 _, _, err := r.Archive(context.TODO(), "fakefile", bytes.NewReader(buf), nil) 202 if err != nil { 203 t.Fatal(err) 204 } 205 } 206 }