github.com/fawick/restic@v0.1.1-0.20171126184616-c02923fbfc79/internal/repository/index_test.go (about) 1 package repository_test 2 3 import ( 4 "bytes" 5 "testing" 6 7 "github.com/restic/restic/internal/repository" 8 "github.com/restic/restic/internal/restic" 9 rtest "github.com/restic/restic/internal/test" 10 ) 11 12 func TestIndexSerialize(t *testing.T) { 13 type testEntry struct { 14 id restic.ID 15 pack restic.ID 16 tpe restic.BlobType 17 offset, length uint 18 } 19 tests := []testEntry{} 20 21 idx := repository.NewIndex() 22 23 // create 50 packs with 20 blobs each 24 for i := 0; i < 50; i++ { 25 packID := restic.NewRandomID() 26 27 pos := uint(0) 28 for j := 0; j < 20; j++ { 29 id := restic.NewRandomID() 30 length := uint(i*100 + j) 31 idx.Store(restic.PackedBlob{ 32 Blob: restic.Blob{ 33 Type: restic.DataBlob, 34 ID: id, 35 Offset: pos, 36 Length: length, 37 }, 38 PackID: packID, 39 }) 40 41 tests = append(tests, testEntry{ 42 id: id, 43 pack: packID, 44 tpe: restic.DataBlob, 45 offset: pos, 46 length: length, 47 }) 48 49 pos += length 50 } 51 } 52 53 wr := bytes.NewBuffer(nil) 54 err := idx.Encode(wr) 55 rtest.OK(t, err) 56 57 idx2, err := repository.DecodeIndex(wr.Bytes()) 58 rtest.OK(t, err) 59 rtest.Assert(t, idx2 != nil, 60 "nil returned for decoded index") 61 62 wr2 := bytes.NewBuffer(nil) 63 err = idx2.Encode(wr2) 64 rtest.OK(t, err) 65 66 for _, testBlob := range tests { 67 list, err := idx.Lookup(testBlob.id, testBlob.tpe) 68 rtest.OK(t, err) 69 70 if len(list) != 1 { 71 t.Errorf("expected one result for blob %v, got %v: %v", testBlob.id.Str(), len(list), list) 72 } 73 result := list[0] 74 75 rtest.Equals(t, testBlob.pack, result.PackID) 76 rtest.Equals(t, testBlob.tpe, result.Type) 77 rtest.Equals(t, testBlob.offset, result.Offset) 78 rtest.Equals(t, testBlob.length, result.Length) 79 80 list2, err := idx2.Lookup(testBlob.id, testBlob.tpe) 81 rtest.OK(t, err) 82 83 if len(list2) != 1 { 84 t.Errorf("expected one result for blob %v, got %v: %v", testBlob.id.Str(), len(list2), list2) 85 } 86 result2 := list2[0] 87 88 rtest.Equals(t, testBlob.pack, result2.PackID) 89 rtest.Equals(t, testBlob.tpe, result2.Type) 90 rtest.Equals(t, testBlob.offset, result2.Offset) 91 rtest.Equals(t, testBlob.length, result2.Length) 92 } 93 94 // add more blobs to idx 95 newtests := []testEntry{} 96 for i := 0; i < 10; i++ { 97 packID := restic.NewRandomID() 98 99 pos := uint(0) 100 for j := 0; j < 10; j++ { 101 id := restic.NewRandomID() 102 length := uint(i*100 + j) 103 idx.Store(restic.PackedBlob{ 104 Blob: restic.Blob{ 105 Type: restic.DataBlob, 106 ID: id, 107 Offset: pos, 108 Length: length, 109 }, 110 PackID: packID, 111 }) 112 113 newtests = append(newtests, testEntry{ 114 id: id, 115 pack: packID, 116 tpe: restic.DataBlob, 117 offset: pos, 118 length: length, 119 }) 120 121 pos += length 122 } 123 } 124 125 // serialize idx, unserialize to idx3 126 wr3 := bytes.NewBuffer(nil) 127 err = idx.Finalize(wr3) 128 rtest.OK(t, err) 129 130 rtest.Assert(t, idx.Final(), 131 "index not final after encoding") 132 133 id := restic.NewRandomID() 134 rtest.OK(t, idx.SetID(id)) 135 id2, err := idx.ID() 136 rtest.Assert(t, id2.Equal(id), 137 "wrong ID returned: want %v, got %v", id, id2) 138 139 idx3, err := repository.DecodeIndex(wr3.Bytes()) 140 rtest.OK(t, err) 141 rtest.Assert(t, idx3 != nil, 142 "nil returned for decoded index") 143 rtest.Assert(t, idx3.Final(), 144 "decoded index is not final") 145 146 // all new blobs must be in the index 147 for _, testBlob := range newtests { 148 list, err := idx3.Lookup(testBlob.id, testBlob.tpe) 149 rtest.OK(t, err) 150 151 if len(list) != 1 { 152 t.Errorf("expected one result for blob %v, got %v: %v", testBlob.id.Str(), len(list), list) 153 } 154 155 blob := list[0] 156 157 rtest.Equals(t, testBlob.pack, blob.PackID) 158 rtest.Equals(t, testBlob.tpe, blob.Type) 159 rtest.Equals(t, testBlob.offset, blob.Offset) 160 rtest.Equals(t, testBlob.length, blob.Length) 161 } 162 } 163 164 func TestIndexSize(t *testing.T) { 165 idx := repository.NewIndex() 166 167 packs := 200 168 blobs := 100 169 for i := 0; i < packs; i++ { 170 packID := restic.NewRandomID() 171 172 pos := uint(0) 173 for j := 0; j < blobs; j++ { 174 id := restic.NewRandomID() 175 length := uint(i*100 + j) 176 idx.Store(restic.PackedBlob{ 177 Blob: restic.Blob{ 178 Type: restic.DataBlob, 179 ID: id, 180 Offset: pos, 181 Length: length, 182 }, 183 PackID: packID, 184 }) 185 186 pos += length 187 } 188 } 189 190 wr := bytes.NewBuffer(nil) 191 192 err := idx.Encode(wr) 193 rtest.OK(t, err) 194 195 t.Logf("Index file size for %d blobs in %d packs is %d", blobs*packs, packs, wr.Len()) 196 } 197 198 // example index serialization from doc/Design.rst 199 var docExample = []byte(` 200 { 201 "supersedes": [ 202 "ed54ae36197f4745ebc4b54d10e0f623eaaaedd03013eb7ae90df881b7781452" 203 ], 204 "packs": [ 205 { 206 "id": "73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c", 207 "blobs": [ 208 { 209 "id": "3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce", 210 "type": "data", 211 "offset": 0, 212 "length": 25 213 },{ 214 "id": "9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae", 215 "type": "tree", 216 "offset": 38, 217 "length": 100 218 }, 219 { 220 "id": "d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66", 221 "type": "data", 222 "offset": 150, 223 "length": 123 224 } 225 ] 226 } 227 ] 228 } 229 `) 230 231 var docOldExample = []byte(` 232 [ { 233 "id": "73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c", 234 "blobs": [ 235 { 236 "id": "3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce", 237 "type": "data", 238 "offset": 0, 239 "length": 25 240 },{ 241 "id": "9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae", 242 "type": "tree", 243 "offset": 38, 244 "length": 100 245 }, 246 { 247 "id": "d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66", 248 "type": "data", 249 "offset": 150, 250 "length": 123 251 } 252 ] 253 } ] 254 `) 255 256 var exampleTests = []struct { 257 id, packID restic.ID 258 tpe restic.BlobType 259 offset, length uint 260 }{ 261 { 262 restic.TestParseID("3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce"), 263 restic.TestParseID("73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c"), 264 restic.DataBlob, 0, 25, 265 }, { 266 restic.TestParseID("9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae"), 267 restic.TestParseID("73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c"), 268 restic.TreeBlob, 38, 100, 269 }, { 270 restic.TestParseID("d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66"), 271 restic.TestParseID("73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c"), 272 restic.DataBlob, 150, 123, 273 }, 274 } 275 276 var exampleLookupTest = struct { 277 packID restic.ID 278 blobs map[restic.ID]restic.BlobType 279 }{ 280 restic.TestParseID("73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c"), 281 map[restic.ID]restic.BlobType{ 282 restic.TestParseID("3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce"): restic.DataBlob, 283 restic.TestParseID("9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae"): restic.TreeBlob, 284 restic.TestParseID("d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66"): restic.DataBlob, 285 }, 286 } 287 288 func TestIndexUnserialize(t *testing.T) { 289 oldIdx := restic.IDs{restic.TestParseID("ed54ae36197f4745ebc4b54d10e0f623eaaaedd03013eb7ae90df881b7781452")} 290 291 idx, err := repository.DecodeIndex(docExample) 292 rtest.OK(t, err) 293 294 for _, test := range exampleTests { 295 list, err := idx.Lookup(test.id, test.tpe) 296 rtest.OK(t, err) 297 298 if len(list) != 1 { 299 t.Errorf("expected one result for blob %v, got %v: %v", test.id.Str(), len(list), list) 300 } 301 blob := list[0] 302 303 t.Logf("looking for blob %v/%v, got %v", test.tpe, test.id.Str(), blob) 304 305 rtest.Equals(t, test.packID, blob.PackID) 306 rtest.Equals(t, test.tpe, blob.Type) 307 rtest.Equals(t, test.offset, blob.Offset) 308 rtest.Equals(t, test.length, blob.Length) 309 } 310 311 rtest.Equals(t, oldIdx, idx.Supersedes()) 312 313 blobs := idx.ListPack(exampleLookupTest.packID) 314 if len(blobs) != len(exampleLookupTest.blobs) { 315 t.Fatalf("expected %d blobs in pack, got %d", len(exampleLookupTest.blobs), len(blobs)) 316 } 317 318 for _, blob := range blobs { 319 b, ok := exampleLookupTest.blobs[blob.ID] 320 if !ok { 321 t.Errorf("unexpected blob %v found", blob.ID.Str()) 322 } 323 if blob.Type != b { 324 t.Errorf("unexpected type for blob %v: want %v, got %v", blob.ID.Str(), b, blob.Type) 325 } 326 } 327 } 328 329 func BenchmarkDecodeIndex(b *testing.B) { 330 b.ResetTimer() 331 332 for i := 0; i < b.N; i++ { 333 _, err := repository.DecodeIndex(docExample) 334 rtest.OK(b, err) 335 } 336 } 337 338 func TestIndexUnserializeOld(t *testing.T) { 339 idx, err := repository.DecodeOldIndex(docOldExample) 340 rtest.OK(t, err) 341 342 for _, test := range exampleTests { 343 list, err := idx.Lookup(test.id, test.tpe) 344 rtest.OK(t, err) 345 346 if len(list) != 1 { 347 t.Errorf("expected one result for blob %v, got %v: %v", test.id.Str(), len(list), list) 348 } 349 blob := list[0] 350 351 rtest.Equals(t, test.packID, blob.PackID) 352 rtest.Equals(t, test.tpe, blob.Type) 353 rtest.Equals(t, test.offset, blob.Offset) 354 rtest.Equals(t, test.length, blob.Length) 355 } 356 357 rtest.Equals(t, 0, len(idx.Supersedes())) 358 } 359 360 func TestIndexPacks(t *testing.T) { 361 idx := repository.NewIndex() 362 packs := restic.NewIDSet() 363 364 for i := 0; i < 20; i++ { 365 packID := restic.NewRandomID() 366 idx.Store(restic.PackedBlob{ 367 Blob: restic.Blob{ 368 Type: restic.DataBlob, 369 ID: restic.NewRandomID(), 370 Offset: 0, 371 Length: 23, 372 }, 373 PackID: packID, 374 }) 375 376 packs.Insert(packID) 377 } 378 379 idxPacks := idx.Packs() 380 rtest.Assert(t, packs.Equals(idxPacks), "packs in index do not match packs added to index") 381 }