| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | package restorer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2021-06-29 21:11:30 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/crypto" | 
					
						
							| 
									
										
										
										
											2021-01-01 09:50:47 +01:00
										 |  |  | 	"github.com/restic/restic/internal/errors" | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 	"github.com/restic/restic/internal/restic" | 
					
						
							|  |  |  | 	rtest "github.com/restic/restic/internal/test" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | type TestBlob struct { | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 	data string | 
					
						
							|  |  |  | 	pack string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | type TestFile struct { | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 	name  string | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 	blobs []TestBlob | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | type TestRepo struct { | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 	key *crypto.Key | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// pack names and ids | 
					
						
							|  |  |  | 	packsNameToID map[string]restic.ID | 
					
						
							|  |  |  | 	packsIDToName map[restic.ID]string | 
					
						
							|  |  |  | 	packsIDToData map[restic.ID][]byte | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// blobs and files | 
					
						
							|  |  |  | 	blobs              map[restic.ID][]restic.PackedBlob | 
					
						
							|  |  |  | 	files              []*fileInfo | 
					
						
							|  |  |  | 	filesPathToContent map[string]string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	loader func(ctx context.Context, h restic.Handle, length int, offset int64, fn func(rd io.Reader) error) error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 22:18:00 +01:00
										 |  |  | func (i *TestRepo) Lookup(bh restic.BlobHandle) []restic.PackedBlob { | 
					
						
							|  |  |  | 	packs := i.blobs[bh.ID] | 
					
						
							| 
									
										
										
										
											2020-06-14 13:26:10 +02:00
										 |  |  | 	return packs | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | func (i *TestRepo) fileContent(file *fileInfo) string { | 
					
						
							| 
									
										
										
										
											2018-09-14 20:18:37 -04:00
										 |  |  | 	return i.filesPathToContent[file.location] | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | func newTestRepo(content []TestFile) *TestRepo { | 
					
						
							|  |  |  | 	type Pack struct { | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		name  string | 
					
						
							|  |  |  | 		data  []byte | 
					
						
							|  |  |  | 		blobs map[restic.ID]restic.Blob | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 	packs := make(map[string]Pack) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	key := crypto.NewRandomKey() | 
					
						
							|  |  |  | 	seal := func(data []byte) []byte { | 
					
						
							|  |  |  | 		ciphertext := restic.NewBlobBuffer(len(data)) | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 		ciphertext = ciphertext[:0] // truncate the slice | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		nonce := crypto.NewRandomNonce() | 
					
						
							|  |  |  | 		ciphertext = append(ciphertext, nonce...) | 
					
						
							|  |  |  | 		return key.Seal(ciphertext, nonce, data, nil) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	filesPathToContent := make(map[string]string) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 	for _, file := range content { | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		var content string | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 		for _, blob := range file.blobs { | 
					
						
							|  |  |  | 			content += blob.data | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// get the pack, create as necessary | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 			var pack Pack | 
					
						
							|  |  |  | 			var found bool | 
					
						
							|  |  |  | 			if pack, found = packs[blob.pack]; !found { | 
					
						
							|  |  |  | 				pack = Pack{name: blob.pack, blobs: make(map[restic.ID]restic.Blob)} | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// calculate blob id and add to the pack as necessary | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 			blobID := restic.Hash([]byte(blob.data)) | 
					
						
							|  |  |  | 			if _, found := pack.blobs[blobID]; !found { | 
					
						
							|  |  |  | 				blobData := seal([]byte(blob.data)) | 
					
						
							|  |  |  | 				pack.blobs[blobID] = restic.Blob{ | 
					
						
							| 
									
										
										
										
											2020-11-05 21:52:34 +01:00
										 |  |  | 					BlobHandle: restic.BlobHandle{ | 
					
						
							|  |  |  | 						Type: restic.DataBlob, | 
					
						
							|  |  |  | 						ID:   blobID, | 
					
						
							|  |  |  | 					}, | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 					Length: uint(len(blobData)), | 
					
						
							|  |  |  | 					Offset: uint(len(pack.data)), | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 				pack.data = append(pack.data, blobData...) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 			packs[blob.pack] = pack | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 		filesPathToContent[file.name] = content | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	blobs := make(map[restic.ID][]restic.PackedBlob) | 
					
						
							|  |  |  | 	packsIDToName := make(map[restic.ID]string) | 
					
						
							|  |  |  | 	packsIDToData := make(map[restic.ID][]byte) | 
					
						
							|  |  |  | 	packsNameToID := make(map[string]restic.ID) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 	for _, pack := range packs { | 
					
						
							|  |  |  | 		packID := restic.Hash(pack.data) | 
					
						
							|  |  |  | 		packsIDToName[packID] = pack.name | 
					
						
							|  |  |  | 		packsIDToData[packID] = pack.data | 
					
						
							|  |  |  | 		packsNameToID[pack.name] = packID | 
					
						
							|  |  |  | 		for blobID, blob := range pack.blobs { | 
					
						
							|  |  |  | 			blobs[blobID] = append(blobs[blobID], restic.PackedBlob{Blob: blob, PackID: packID}) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var files []*fileInfo | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 	for _, file := range content { | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		content := restic.IDs{} | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 		for _, blob := range file.blobs { | 
					
						
							|  |  |  | 			content = append(content, restic.Hash([]byte(blob.data))) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-09-14 20:18:37 -04:00
										 |  |  | 		files = append(files, &fileInfo{location: file.name, blobs: content}) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 	repo := &TestRepo{ | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		key:                key, | 
					
						
							|  |  |  | 		packsIDToName:      packsIDToName, | 
					
						
							|  |  |  | 		packsIDToData:      packsIDToData, | 
					
						
							|  |  |  | 		packsNameToID:      packsNameToID, | 
					
						
							|  |  |  | 		blobs:              blobs, | 
					
						
							|  |  |  | 		files:              files, | 
					
						
							|  |  |  | 		filesPathToContent: filesPathToContent, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 	repo.loader = func(ctx context.Context, h restic.Handle, length int, offset int64, fn func(rd io.Reader) error) error { | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		packID, err := restic.ParseID(h.Name) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 		rd := bytes.NewReader(repo.packsIDToData[packID][int(offset) : int(offset)+length]) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		return fn(rd) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 	return repo | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 13:15:25 +01:00
										 |  |  | func restoreAndVerify(t *testing.T, tempdir string, content []TestFile, files map[string]bool) { | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 	repo := newTestRepo(content) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 07:22:38 -05:00
										 |  |  | 	r := newFileRestorer(tempdir, repo.loader, repo.key, repo.Lookup) | 
					
						
							| 
									
										
										
										
											2020-11-20 13:15:25 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if files == nil { | 
					
						
							|  |  |  | 		r.files = repo.files | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		for _, file := range repo.files { | 
					
						
							|  |  |  | 			if files[file.location] { | 
					
						
							|  |  |  | 				r.files = append(r.files, file) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 07:22:38 -05:00
										 |  |  | 	err := r.restoreFiles(context.TODO()) | 
					
						
							|  |  |  | 	rtest.OK(t, err) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-29 21:11:30 +02:00
										 |  |  | 	verifyRestore(t, r, repo) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func verifyRestore(t *testing.T, r *fileRestorer, repo *TestRepo) { | 
					
						
							| 
									
										
										
										
											2020-11-20 13:15:25 +01:00
										 |  |  | 	for _, file := range r.files { | 
					
						
							| 
									
										
										
										
											2018-09-14 20:18:37 -04:00
										 |  |  | 		target := r.targetPath(file.location) | 
					
						
							|  |  |  | 		data, err := ioutil.ReadFile(target) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2018-09-14 20:18:37 -04:00
										 |  |  | 			t.Errorf("unable to read file %v: %v", file.location, err) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 		content := repo.fileContent(file) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		if !bytes.Equal(data, []byte(content)) { | 
					
						
							| 
									
										
										
										
											2018-09-14 20:18:37 -04:00
										 |  |  | 			t.Errorf("file %v has wrong content: want %q, got %q", file.location, content, data) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | func TestFileRestorerBasic(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 	tempdir, cleanup := rtest.TempDir(t) | 
					
						
							|  |  |  | 	defer cleanup() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-14 20:18:37 -04:00
										 |  |  | 	restoreAndVerify(t, tempdir, []TestFile{ | 
					
						
							| 
									
										
										
										
											2020-04-10 11:43:42 +02:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2018-09-14 20:18:37 -04:00
										 |  |  | 			name: "file1", | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 			blobs: []TestBlob{ | 
					
						
							| 
									
										
										
										
											2020-04-10 11:43:42 +02:00
										 |  |  | 				{"data1-1", "pack1-1"}, | 
					
						
							|  |  |  | 				{"data1-2", "pack1-2"}, | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2020-04-10 11:43:42 +02:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2018-09-14 20:18:37 -04:00
										 |  |  | 			name: "file2", | 
					
						
							| 
									
										
										
										
											2018-07-11 21:33:36 +02:00
										 |  |  | 			blobs: []TestBlob{ | 
					
						
							| 
									
										
										
										
											2020-04-10 11:43:42 +02:00
										 |  |  | 				{"data2-1", "pack2-1"}, | 
					
						
							|  |  |  | 				{"data2-2", "pack2-2"}, | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2020-04-10 11:43:42 +02:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-11-27 07:22:38 -05:00
										 |  |  | 			name: "file3", | 
					
						
							|  |  |  | 			blobs: []TestBlob{ | 
					
						
							|  |  |  | 				// same blob multiple times | 
					
						
							| 
									
										
										
										
											2020-04-10 11:43:42 +02:00
										 |  |  | 				{"data3-1", "pack3-1"}, | 
					
						
							|  |  |  | 				{"data3-1", "pack3-1"}, | 
					
						
							| 
									
										
										
										
											2019-11-27 07:22:38 -05:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2020-11-20 13:15:25 +01:00
										 |  |  | 	}, nil) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestFileRestorerPackSkip(t *testing.T) { | 
					
						
							|  |  |  | 	tempdir, cleanup := rtest.TempDir(t) | 
					
						
							|  |  |  | 	defer cleanup() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	files := make(map[string]bool) | 
					
						
							|  |  |  | 	files["file2"] = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	restoreAndVerify(t, tempdir, []TestFile{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "file1", | 
					
						
							|  |  |  | 			blobs: []TestBlob{ | 
					
						
							|  |  |  | 				{"data1-1", "pack1"}, | 
					
						
							|  |  |  | 				{"data1-2", "pack1"}, | 
					
						
							|  |  |  | 				{"data1-3", "pack1"}, | 
					
						
							|  |  |  | 				{"data1-4", "pack1"}, | 
					
						
							|  |  |  | 				{"data1-5", "pack1"}, | 
					
						
							|  |  |  | 				{"data1-6", "pack1"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "file2", | 
					
						
							|  |  |  | 			blobs: []TestBlob{ | 
					
						
							|  |  |  | 				// file is contained in pack1 but need pack parts to be skipped | 
					
						
							|  |  |  | 				{"data1-2", "pack1"}, | 
					
						
							|  |  |  | 				{"data1-4", "pack1"}, | 
					
						
							|  |  |  | 				{"data1-6", "pack1"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, files) | 
					
						
							| 
									
										
										
										
											2018-04-08 08:02:30 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-01-01 09:50:47 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestErrorRestoreFiles(t *testing.T) { | 
					
						
							|  |  |  | 	tempdir, cleanup := rtest.TempDir(t) | 
					
						
							|  |  |  | 	defer cleanup() | 
					
						
							|  |  |  | 	content := []TestFile{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "file1", | 
					
						
							|  |  |  | 			blobs: []TestBlob{ | 
					
						
							|  |  |  | 				{"data1-1", "pack1-1"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	repo := newTestRepo(content) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	loadError := errors.New("load error") | 
					
						
							|  |  |  | 	// loader always returns an error | 
					
						
							|  |  |  | 	repo.loader = func(ctx context.Context, h restic.Handle, length int, offset int64, fn func(rd io.Reader) error) error { | 
					
						
							|  |  |  | 		return loadError | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r := newFileRestorer(tempdir, repo.loader, repo.key, repo.Lookup) | 
					
						
							|  |  |  | 	r.files = repo.files | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := r.restoreFiles(context.TODO()) | 
					
						
							| 
									
										
										
										
											2021-01-04 19:20:04 +01:00
										 |  |  | 	rtest.Equals(t, loadError, err) | 
					
						
							| 
									
										
										
										
											2021-01-01 09:50:47 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-29 21:11:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestDownloadError(t *testing.T) { | 
					
						
							|  |  |  | 	for i := 0; i < 100; i += 10 { | 
					
						
							|  |  |  | 		testPartialDownloadError(t, i) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testPartialDownloadError(t *testing.T, part int) { | 
					
						
							|  |  |  | 	tempdir, cleanup := rtest.TempDir(t) | 
					
						
							|  |  |  | 	defer cleanup() | 
					
						
							|  |  |  | 	content := []TestFile{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "file1", | 
					
						
							|  |  |  | 			blobs: []TestBlob{ | 
					
						
							|  |  |  | 				{"data1-1", "pack1"}, | 
					
						
							|  |  |  | 				{"data1-2", "pack1"}, | 
					
						
							|  |  |  | 				{"data1-3", "pack1"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	repo := newTestRepo(content) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// loader always returns an error | 
					
						
							|  |  |  | 	loader := repo.loader | 
					
						
							|  |  |  | 	repo.loader = func(ctx context.Context, h restic.Handle, length int, offset int64, fn func(rd io.Reader) error) error { | 
					
						
							|  |  |  | 		// only load partial data to execise fault handling in different places | 
					
						
							|  |  |  | 		err := loader(ctx, h, length*part/100, offset, fn) | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fmt.Println("Retry after error", err) | 
					
						
							|  |  |  | 		return loader(ctx, h, length, offset, fn) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r := newFileRestorer(tempdir, repo.loader, repo.key, repo.Lookup) | 
					
						
							|  |  |  | 	r.files = repo.files | 
					
						
							|  |  |  | 	r.Error = func(s string, e error) error { | 
					
						
							|  |  |  | 		// ignore errors as in the `restore` command | 
					
						
							|  |  |  | 		fmt.Println("error during restore", s, e) | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := r.restoreFiles(context.TODO()) | 
					
						
							|  |  |  | 	rtest.OK(t, err) | 
					
						
							|  |  |  | 	verifyRestore(t, r, repo) | 
					
						
							|  |  |  | } |