| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | package walker | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/pkg/errors" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/restic" | 
					
						
							| 
									
										
										
										
											2022-12-28 11:34:55 +01:00
										 |  |  | 	"github.com/restic/restic/internal/test" | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WritableTreeMap also support saving | 
					
						
							|  |  |  | type WritableTreeMap struct { | 
					
						
							|  |  |  | 	TreeMap | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 19:18:09 +02:00
										 |  |  | func (t WritableTreeMap) SaveBlob(_ context.Context, tpe restic.BlobType, buf []byte, id restic.ID, _ bool) (newID restic.ID, known bool, size int, err error) { | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 	if tpe != restic.TreeBlob { | 
					
						
							|  |  |  | 		return restic.ID{}, false, 0, errors.New("can only save trees") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if id.IsNull() { | 
					
						
							|  |  |  | 		id = restic.Hash(buf) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	_, ok := t.TreeMap[id] | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		return id, false, 0, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.TreeMap[id] = append([]byte{}, buf...) | 
					
						
							|  |  |  | 	return id, true, len(buf), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (t WritableTreeMap) Dump() { | 
					
						
							|  |  |  | 	for k, v := range t.TreeMap { | 
					
						
							|  |  |  | 		fmt.Printf("%v: %v", k, string(v)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | type checkRewriteFunc func(t testing.TB) (rewriter *TreeRewriter, final func(testing.TB)) | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // checkRewriteItemOrder ensures that the order of the 'path' arguments is the one passed in as 'want'. | 
					
						
							|  |  |  | func checkRewriteItemOrder(want []string) checkRewriteFunc { | 
					
						
							|  |  |  | 	pos := 0 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 	return func(t testing.TB) (rewriter *TreeRewriter, final func(testing.TB)) { | 
					
						
							|  |  |  | 		rewriter = NewTreeRewriter(RewriteOpts{ | 
					
						
							|  |  |  | 			RewriteNode: func(node *restic.Node, path string) *restic.Node { | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 				if pos >= len(want) { | 
					
						
							|  |  |  | 					t.Errorf("additional unexpected path found: %v", path) | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 					return nil | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if path != want[pos] { | 
					
						
							|  |  |  | 					t.Errorf("wrong path found, want %q, got %q", want[pos], path) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				pos++ | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 				return node | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		final = func(t testing.TB) { | 
					
						
							|  |  |  | 			if pos != len(want) { | 
					
						
							|  |  |  | 				t.Errorf("not enough items returned, want %d, got %d", len(want), pos) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 		return rewriter, final | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | // checkRewriteSkips excludes nodes if path is in skipFor, it checks that rewriting proceedes in the correct order. | 
					
						
							| 
									
										
										
										
											2022-12-28 11:34:55 +01:00
										 |  |  | func checkRewriteSkips(skipFor map[string]struct{}, want []string, disableCache bool) checkRewriteFunc { | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 	var pos int | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 	return func(t testing.TB) (rewriter *TreeRewriter, final func(testing.TB)) { | 
					
						
							|  |  |  | 		rewriter = NewTreeRewriter(RewriteOpts{ | 
					
						
							|  |  |  | 			RewriteNode: func(node *restic.Node, path string) *restic.Node { | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 				if pos >= len(want) { | 
					
						
							|  |  |  | 					t.Errorf("additional unexpected path found: %v", path) | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 					return nil | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if path != want[pos] { | 
					
						
							|  |  |  | 					t.Errorf("wrong path found, want %q, got %q", want[pos], path) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				pos++ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 				_, skip := skipFor[path] | 
					
						
							|  |  |  | 				if skip { | 
					
						
							|  |  |  | 					return nil | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 				return node | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2022-12-28 11:34:55 +01:00
										 |  |  | 			DisableNodeCache: disableCache, | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		final = func(t testing.TB) { | 
					
						
							|  |  |  | 			if pos != len(want) { | 
					
						
							|  |  |  | 				t.Errorf("not enough items returned, want %d, got %d", len(want), pos) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 		return rewriter, final | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // checkIncreaseNodeSize modifies each node by changing its size. | 
					
						
							|  |  |  | func checkIncreaseNodeSize(increase uint64) checkRewriteFunc { | 
					
						
							|  |  |  | 	return func(t testing.TB) (rewriter *TreeRewriter, final func(testing.TB)) { | 
					
						
							|  |  |  | 		rewriter = NewTreeRewriter(RewriteOpts{ | 
					
						
							|  |  |  | 			RewriteNode: func(node *restic.Node, path string) *restic.Node { | 
					
						
							|  |  |  | 				if node.Type == "file" { | 
					
						
							|  |  |  | 					node.Size += increase | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return node | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		final = func(t testing.TB) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return rewriter, final | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestRewriter(t *testing.T) { | 
					
						
							|  |  |  | 	var tests = []struct { | 
					
						
							|  |  |  | 		tree    TestTree | 
					
						
							|  |  |  | 		newTree TestTree | 
					
						
							|  |  |  | 		check   checkRewriteFunc | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ // don't change | 
					
						
							|  |  |  | 			tree: TestTree{ | 
					
						
							|  |  |  | 				"foo": TestFile{}, | 
					
						
							|  |  |  | 				"subdir": TestTree{ | 
					
						
							|  |  |  | 					"subfile": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			check: checkRewriteItemOrder([]string{ | 
					
						
							|  |  |  | 				"/foo", | 
					
						
							|  |  |  | 				"/subdir", | 
					
						
							|  |  |  | 				"/subdir/subfile", | 
					
						
							|  |  |  | 			}), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ // exclude file | 
					
						
							|  |  |  | 			tree: TestTree{ | 
					
						
							|  |  |  | 				"foo": TestFile{}, | 
					
						
							|  |  |  | 				"subdir": TestTree{ | 
					
						
							|  |  |  | 					"subfile": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			newTree: TestTree{ | 
					
						
							|  |  |  | 				"foo":    TestFile{}, | 
					
						
							|  |  |  | 				"subdir": TestTree{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			check: checkRewriteSkips( | 
					
						
							|  |  |  | 				map[string]struct{}{ | 
					
						
							|  |  |  | 					"/subdir/subfile": {}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				[]string{ | 
					
						
							|  |  |  | 					"/foo", | 
					
						
							|  |  |  | 					"/subdir", | 
					
						
							|  |  |  | 					"/subdir/subfile", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2022-12-28 11:34:55 +01:00
										 |  |  | 				false, | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ // exclude dir | 
					
						
							|  |  |  | 			tree: TestTree{ | 
					
						
							|  |  |  | 				"foo": TestFile{}, | 
					
						
							|  |  |  | 				"subdir": TestTree{ | 
					
						
							|  |  |  | 					"subfile": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			newTree: TestTree{ | 
					
						
							|  |  |  | 				"foo": TestFile{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			check: checkRewriteSkips( | 
					
						
							|  |  |  | 				map[string]struct{}{ | 
					
						
							|  |  |  | 					"/subdir": {}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				[]string{ | 
					
						
							|  |  |  | 					"/foo", | 
					
						
							|  |  |  | 					"/subdir", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2022-12-28 11:34:55 +01:00
										 |  |  | 				false, | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 		{ // modify node | 
					
						
							|  |  |  | 			tree: TestTree{ | 
					
						
							|  |  |  | 				"foo": TestFile{Size: 21}, | 
					
						
							|  |  |  | 				"subdir": TestTree{ | 
					
						
							|  |  |  | 					"subfile": TestFile{Size: 21}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			newTree: TestTree{ | 
					
						
							|  |  |  | 				"foo": TestFile{Size: 42}, | 
					
						
							|  |  |  | 				"subdir": TestTree{ | 
					
						
							|  |  |  | 					"subfile": TestFile{Size: 42}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			check: checkIncreaseNodeSize(21), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-12-28 11:34:55 +01:00
										 |  |  | 		{ // test cache | 
					
						
							|  |  |  | 			tree: TestTree{ | 
					
						
							|  |  |  | 				// both subdirs are identical | 
					
						
							|  |  |  | 				"subdir1": TestTree{ | 
					
						
							|  |  |  | 					"subfile":  TestFile{}, | 
					
						
							|  |  |  | 					"subfile2": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"subdir2": TestTree{ | 
					
						
							|  |  |  | 					"subfile":  TestFile{}, | 
					
						
							|  |  |  | 					"subfile2": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			newTree: TestTree{ | 
					
						
							|  |  |  | 				"subdir1": TestTree{ | 
					
						
							|  |  |  | 					"subfile2": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"subdir2": TestTree{ | 
					
						
							|  |  |  | 					"subfile2": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			check: checkRewriteSkips( | 
					
						
							|  |  |  | 				map[string]struct{}{ | 
					
						
							|  |  |  | 					"/subdir1/subfile": {}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				[]string{ | 
					
						
							|  |  |  | 					"/subdir1", | 
					
						
							|  |  |  | 					"/subdir1/subfile", | 
					
						
							|  |  |  | 					"/subdir1/subfile2", | 
					
						
							|  |  |  | 					"/subdir2", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				false, | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ // test disabled cache | 
					
						
							|  |  |  | 			tree: TestTree{ | 
					
						
							|  |  |  | 				// both subdirs are identical | 
					
						
							|  |  |  | 				"subdir1": TestTree{ | 
					
						
							|  |  |  | 					"subfile":  TestFile{}, | 
					
						
							|  |  |  | 					"subfile2": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"subdir2": TestTree{ | 
					
						
							|  |  |  | 					"subfile":  TestFile{}, | 
					
						
							|  |  |  | 					"subfile2": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			newTree: TestTree{ | 
					
						
							|  |  |  | 				"subdir1": TestTree{ | 
					
						
							|  |  |  | 					"subfile2": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"subdir2": TestTree{ | 
					
						
							|  |  |  | 					"subfile":  TestFile{}, | 
					
						
							|  |  |  | 					"subfile2": TestFile{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			check: checkRewriteSkips( | 
					
						
							|  |  |  | 				map[string]struct{}{ | 
					
						
							|  |  |  | 					"/subdir1/subfile": {}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				[]string{ | 
					
						
							|  |  |  | 					"/subdir1", | 
					
						
							|  |  |  | 					"/subdir1/subfile", | 
					
						
							|  |  |  | 					"/subdir1/subfile2", | 
					
						
							|  |  |  | 					"/subdir2", | 
					
						
							|  |  |  | 					"/subdir2/subfile", | 
					
						
							|  |  |  | 					"/subdir2/subfile2", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				true, | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							|  |  |  | 		t.Run("", func(t *testing.T) { | 
					
						
							|  |  |  | 			repo, root := BuildTreeMap(test.tree) | 
					
						
							|  |  |  | 			if test.newTree == nil { | 
					
						
							|  |  |  | 				test.newTree = test.tree | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			expRepo, expRoot := BuildTreeMap(test.newTree) | 
					
						
							|  |  |  | 			modrepo := WritableTreeMap{repo} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ctx, cancel := context.WithCancel(context.TODO()) | 
					
						
							|  |  |  | 			defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 			rewriter, last := test.check(t) | 
					
						
							|  |  |  | 			newRoot, err := rewriter.RewriteTree(ctx, modrepo, "/", root) | 
					
						
							| 
									
										
										
										
											2022-10-14 23:26:13 +02:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Error(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			last(t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// verifying against the expected tree root also implicitly checks the structural integrity | 
					
						
							|  |  |  | 			if newRoot != expRoot { | 
					
						
							|  |  |  | 				t.Error("hash mismatch") | 
					
						
							|  |  |  | 				fmt.Println("Got") | 
					
						
							|  |  |  | 				modrepo.Dump() | 
					
						
							|  |  |  | 				fmt.Println("Expected") | 
					
						
							|  |  |  | 				WritableTreeMap{expRepo}.Dump() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-10-15 10:14:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestRewriterFailOnUnknownFields(t *testing.T) { | 
					
						
							|  |  |  | 	tm := WritableTreeMap{TreeMap{}} | 
					
						
							|  |  |  | 	node := []byte(`{"nodes":[{"name":"subfile","type":"file","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","uid":0,"gid":0,"content":null,"unknown_field":42}]}`) | 
					
						
							|  |  |  | 	id := restic.Hash(node) | 
					
						
							|  |  |  | 	tm.TreeMap[id] = node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctx, cancel := context.WithCancel(context.TODO()) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							| 
									
										
										
										
											2022-12-28 11:04:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rewriter := NewTreeRewriter(RewriteOpts{ | 
					
						
							|  |  |  | 		RewriteNode: func(node *restic.Node, path string) *restic.Node { | 
					
						
							|  |  |  | 			// tree loading must not succeed | 
					
						
							|  |  |  | 			t.Fail() | 
					
						
							|  |  |  | 			return node | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	_, err := rewriter.RewriteTree(ctx, tm, "/", id) | 
					
						
							| 
									
										
										
										
											2022-10-15 10:14:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		t.Error("missing error on unknown field") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-12-28 11:34:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// check that the serialization check can be disabled | 
					
						
							|  |  |  | 	rewriter = NewTreeRewriter(RewriteOpts{ | 
					
						
							|  |  |  | 		AllowUnstableSerialization: true, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	root, err := rewriter.RewriteTree(ctx, tm, "/", id) | 
					
						
							|  |  |  | 	test.OK(t, err) | 
					
						
							|  |  |  | 	_, expRoot := BuildTreeMap(TestTree{ | 
					
						
							|  |  |  | 		"subfile": TestFile{}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	test.Assert(t, root == expRoot, "mismatched trees") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestRewriterTreeLoadError(t *testing.T) { | 
					
						
							|  |  |  | 	tm := WritableTreeMap{TreeMap{}} | 
					
						
							|  |  |  | 	id := restic.NewRandomID() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctx, cancel := context.WithCancel(context.TODO()) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// also check that load error by default cause the operation to fail | 
					
						
							|  |  |  | 	rewriter := NewTreeRewriter(RewriteOpts{}) | 
					
						
							|  |  |  | 	_, err := rewriter.RewriteTree(ctx, tm, "/", id) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		t.Fatal("missing error on unloadable tree") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	replacementID := restic.NewRandomID() | 
					
						
							|  |  |  | 	rewriter = NewTreeRewriter(RewriteOpts{ | 
					
						
							|  |  |  | 		RewriteFailedTree: func(nodeID restic.ID, path string, err error) (restic.ID, error) { | 
					
						
							|  |  |  | 			if nodeID != id || path != "/" { | 
					
						
							|  |  |  | 				t.Fail() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return replacementID, nil | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	newRoot, err := rewriter.RewriteTree(ctx, tm, "/", id) | 
					
						
							|  |  |  | 	test.OK(t, err) | 
					
						
							|  |  |  | 	test.Equals(t, replacementID, newRoot) | 
					
						
							| 
									
										
										
										
											2022-10-15 10:14:50 +02:00
										 |  |  | } |