func DoTestPatchFileAppend(t *testing.T, mkrepo repoMaker) { tg := treegen.New() treeSpec := tg.D("foo", tg.F("bar", tg.B(42, 65537), tg.B(43, 65537))) srcpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(srcpath) srcRepo := mkrepo(t) defer srcRepo.Close() srcStore, err := fs.NewLocalStore(srcpath, srcRepo) assert.T(t, err == nil) tg = treegen.New() treeSpec = tg.D("foo", tg.F("bar", tg.B(42, 65537))) dstpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(dstpath) dstRepo := mkrepo(t) defer dstRepo.Close() dstStore, err := fs.NewLocalStore(dstpath, dstRepo) assert.T(t, err == nil) patchPlan := NewPatchPlan(srcStore, dstStore) // printPlan(patchPlan) complete := false for i, cmd := range patchPlan.Cmds { switch { case i == 0: localTemp, isTemp := cmd.(*LocalTemp) assert.T(t, isTemp) assert.Equal(t, filepath.Join(dstpath, "foo", "bar"), localTemp.Path.Resolve()) case i >= 1 && i <= 8: ltc, isLtc := cmd.(*LocalTempCopy) assert.Tf(t, isLtc, "cmd %d", i) assert.Equal(t, ltc.LocalOffset, ltc.TempOffset) assert.Equal(t, int64(fs.BLOCKSIZE), ltc.Length) assert.Equal(t, int64(0), ltc.LocalOffset%int64(fs.BLOCKSIZE)) case i == 9: stc, isStc := cmd.(*SrcTempCopy) assert.T(t, isStc) assert.Equal(t, int64(65538), stc.Length) case i == 10: _, isRwt := cmd.(*ReplaceWithTemp) assert.T(t, isRwt) complete = true case i > 10: t.Fatalf("too many commands") } } assert.T(t, complete, "missing expected number of commands") failedCmd, err := patchPlan.Exec() assert.Tf(t, failedCmd == nil && err == nil, "%v: %v", failedCmd, err) srcRoot, errors := fs.IndexDir(srcpath, fs.NewMemRepo()) assert.Equalf(t, 0, len(errors), "%v", errors) dstRoot, errors := fs.IndexDir(dstpath, fs.NewMemRepo()) assert.Equalf(t, 0, len(errors), "%v", errors) assert.Equal(t, srcRoot.Info().Strong, dstRoot.Info().Strong) }
func TestPatchRenameScope(t *testing.T) { tg := treegen.New() treeSpec := tg.D("foo", tg.F("bar", tg.B(6806, 65536)), tg.F("baz", tg.B(6806, 65536))) srcpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(srcpath) srcStore, err := fs.NewLocalStore(srcpath) assert.T(t, err == nil) tg = treegen.New() treeSpec = tg.D("foo", tg.F("baz", tg.B(6806, 65536)), tg.F("blop", tg.B(6806, 65536))) dstpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(dstpath) dstStore, err := fs.NewLocalStore(dstpath) assert.T(t, err == nil) patchPlan := NewPatchPlan(srcStore, dstStore) // printPlan(patchPlan) failedCmd, err := patchPlan.Exec() assert.Tf(t, failedCmd == nil && err == nil, "%v: %v", failedCmd, err) srcDir, err := fs.IndexDir(srcpath) assert.T(t, err == nil) dstDir, err := fs.IndexDir(dstpath) assert.T(t, err == nil) assert.Equal(t, srcDir.Strong(), dstDir.Strong()) }
func DoTestPatchRenameScope(t *testing.T, mkrepo repoMaker) { tg := treegen.New() treeSpec := tg.D("foo", tg.F("bar", tg.B(6806, 65536)), tg.F("baz", tg.B(6806, 65536))) srcpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(srcpath) srcRepo := mkrepo(t) defer srcRepo.Close() srcStore, err := fs.NewLocalStore(srcpath, srcRepo) assert.T(t, err == nil) tg = treegen.New() treeSpec = tg.D("foo", tg.F("baz", tg.B(6806, 65536)), tg.F("blop", tg.B(6806, 65536))) dstpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(dstpath) dstRepo := mkrepo(t) defer dstRepo.Close() dstStore, err := fs.NewLocalStore(dstpath, dstRepo) assert.T(t, err == nil) patchPlan := NewPatchPlan(srcStore, dstStore) // printPlan(patchPlan) failedCmd, err := patchPlan.Exec() assert.Tf(t, failedCmd == nil && err == nil, "%v: %v", failedCmd, err) // The actual content of dst after the patch depends on // which file the repo chooses when matching foo/bar // to baz or blop in dst. // // If blop matches, it will get renamed to bar and the trees will // become identical. However if baz matches, blop will be left in place. srcDir, errors := fs.IndexDir(srcpath, fs.NewMemRepo()) assert.Equalf(t, 0, len(errors), "%v", errors) dstDir, errors := fs.IndexDir(dstpath, fs.NewMemRepo()) assert.Equalf(t, 0, len(errors), "%v", errors) for _, path := range []string{"foo/bar", "foo/baz"} { srcNode, has := fs.Lookup(srcDir, path) assert.T(t, has) dstNode, has := fs.Lookup(dstDir, path) assert.T(t, has) assert.Equal(t, srcNode.(fs.File).Info().Strong, dstNode.(fs.File).Info().Strong) } }
// Test the patch planner on a case where the source file is a shorter, // truncated version of the destination. // Execute the patch plan and check both resulting trees are identical. func TestPatchFileTruncate(t *testing.T) { tg := treegen.New() treeSpec := tg.D("foo", tg.F("bar", tg.B(42, 65537))) srcpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(srcpath) srcStore, err := fs.NewLocalStore(srcpath) assert.T(t, err == nil) tg = treegen.New() treeSpec = tg.D("foo", tg.F("bar", tg.B(42, 65537), tg.B(43, 65537))) dstpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(dstpath) dstStore, err := fs.NewLocalStore(dstpath) assert.T(t, err == nil) patchPlan := NewPatchPlan(srcStore, dstStore) // printPlan(patchPlan) complete := false for i, cmd := range patchPlan.Cmds { switch { case i == 0: localTemp, isTemp := cmd.(*LocalTemp) assert.T(t, isTemp) assert.Equal(t, filepath.Join(dstpath, "foo", "bar"), localTemp.Path.Resolve()) case i >= 1 && i <= 8: ltc, isLtc := cmd.(*LocalTempCopy) assert.Tf(t, isLtc, "cmd %d", i) assert.Equal(t, ltc.LocalOffset, ltc.TempOffset) assert.Equal(t, int64(fs.BLOCKSIZE), ltc.Length) assert.Equal(t, int64(0), ltc.LocalOffset%int64(fs.BLOCKSIZE)) case i == 9: stc, isStc := cmd.(*SrcTempCopy) assert.T(t, isStc) assert.Equal(t, int64(1), stc.Length) complete = true case i > 10: t.Fatalf("too many commands") } } assert.T(t, complete, "missing expected number of commands") failedCmd, err := patchPlan.Exec() assert.Tf(t, failedCmd == nil && err == nil, "%v: %v", failedCmd, err) srcRoot, _ := fs.IndexDir(srcpath) dstRoot, _ := fs.IndexDir(dstpath) assert.Equal(t, srcRoot.Strong(), dstRoot.Strong()) }
func DoTestVisitBlocks(t *testing.T, repo fs.NodeRepo) { dir, errors := fs.IndexDir("../../testroot/", repo) assert.T(t, dir != nil) assert.Equalf(t, 0, len(errors), "%v", errors) collect := []fs.Block{} fs.Walk(dir, func(node fs.Node) bool { b, ok := node.(fs.Block) if ok { collect = append(collect, b) } return true }) matched := false for _, block := range collect { if block.Info().Strong == "d1f11a93449fa4d3f320234743204ce157bbf1f3" { matched = true } } assert.Tf(t, matched, "Failed to find expected block") }
func DoTestVisitDirsOnly(t *testing.T, repo fs.NodeRepo) { dir, errors := fs.IndexDir("../../testroot/", repo) assert.T(t, dir != nil) assert.Equalf(t, 0, len(errors), "%v", errors) collect := []fs.Dir{} visited := []fs.Node{} fs.Walk(dir, func(node fs.Node) bool { visited = append(visited, node) d, ok := node.(fs.Dir) if ok { collect = append(collect, d) return true } _, ok = node.(fs.File) if ok { return false } t.Errorf("Unexpected type during visit: %v", node) return true }) assert.Equalf(t, 3, len(collect), "Unexpected dirs in testroot/: %v", collect) for _, node := range visited { _, ok := node.(fs.Block) if ok { t.Fatalf("Should not have gotten a block, we told visitor to stop at file level.") } } }
func DoTestDirDescent(t *testing.T, repo fs.NodeRepo) { tg := treegen.New() treeSpec := tg.D("foo", tg.F("baobab", tg.B(91, 65537)), tg.D("bar", tg.D("aleph", tg.F("a", tg.B(42, 65537)))), tg.F("bar3003", tg.B(777, 65537))) path := treegen.TestTree(t, treeSpec) defer os.RemoveAll(path) dir, errors := fs.IndexDir(path, repo) assert.Equalf(t, 0, len(errors), "%v", errors) for _, fpath := range []string{ filepath.Join("foo", "baobab"), filepath.Join("foo", "bar", "aleph", "a"), filepath.Join("foo", "bar3003")} { node, found := fs.Lookup(dir, fpath) assert.Tf(t, found, "not found: %s", fpath) _, isFile := node.(fs.File) assert.T(t, isFile) } node, found := fs.Lookup(dir, filepath.Join("foo", "bar")) assert.T(t, found) _, isDir := node.(fs.Dir) assert.T(t, isDir) }
func DoTestPatchWeakCollision(t *testing.T, mkrepo repoMaker) { tg := treegen.New() treeSpec := tg.D("foo", tg.F("bar", tg.B(6806, 65536))) srcpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(srcpath) srcRepo := mkrepo(t) defer srcRepo.Close() srcStore, err := fs.NewLocalStore(srcpath, srcRepo) assert.T(t, err == nil) tg = treegen.New() treeSpec = tg.D("foo", tg.F("bar", tg.B(9869, 65536))) dstpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(dstpath) dstRepo := mkrepo(t) defer dstRepo.Close() dstStore, err := fs.NewLocalStore(dstpath, dstRepo) assert.T(t, err == nil) // Src and dst blocks have same weak checksum assert.Equal(t, (srcStore.Repo().Root().(fs.Dir)).SubDirs()[0].Files()[0].Blocks()[0].Info().Weak, (dstStore.Repo().Root().(fs.Dir)).SubDirs()[0].Files()[0].Blocks()[0].Info().Weak) // Src and dst blocks have different strong checksum srcRoot := srcStore.Repo().Root().(fs.Dir) dstRoot := dstStore.Repo().Root().(fs.Dir) assert.Tf(t, srcRoot.Info().Strong != dstRoot.Info().Strong, "wtf: %v == %v", srcRoot.Info().Strong, dstRoot.Info().Strong) patchPlan := NewPatchPlan(srcStore, dstStore) // printPlan(patchPlan) failedCmd, err := patchPlan.Exec() assert.Tf(t, failedCmd == nil && err == nil, "%v: %v", failedCmd, err) srcDir, errors := fs.IndexDir(srcpath, fs.NewMemRepo()) assert.Equalf(t, 0, len(errors), "%v", errors) dstDir, errors := fs.IndexDir(dstpath, fs.NewMemRepo()) assert.Equalf(t, 0, len(errors), "%v", errors) assert.Equal(t, srcDir.Info().Strong, dstDir.Info().Strong) }
func TestDbRepo(t *testing.T) { dbrepo, dbpath := createDbRepo(t) log.SetFlags(log.LstdFlags | log.Lshortfile) defer os.Remove(dbpath) defer dbrepo.Close() tg := treegen.New() treeSpec := tg.D("foo", tg.D("bar", tg.D("aleph", tg.F("A", tg.B(42, 65537)), tg.F("a", tg.B(42, 65537))), tg.D("beth", tg.F("B", tg.B(43, 65537)), tg.F("b", tg.B(43, 65537))), tg.D("jimmy", tg.F("G", tg.B(44, 65537)), tg.F("g", tg.B(44, 65537)))), tg.D("baz", tg.D("uno", tg.F("1", tg.B(1, 65537)), tg.F("I", tg.B(1, 65537))), tg.D("dos", tg.F("2", tg.B(11, 65537)), tg.F("II", tg.B(11, 65537))), tg.D("tres", tg.F("3", tg.B(111, 65537)), tg.F("III", tg.B(111, 65537))))) path := treegen.TestTree(t, treeSpec) defer os.RemoveAll(path) foo, errors := fs.IndexDir(filepath.Join(path, "foo"), dbrepo) assert.Equalf(t, 0, len(errors), "%v", errors) dbmemrepo, err := NewDbRepo(":memory:") assert.T(t, err == nil) memfoo, errors := fs.IndexDir(filepath.Join(path, "foo"), dbmemrepo) assert.Equalf(t, 0, len(errors), "%v", errors) assert.Equal(t, foo.Info().Strong, memfoo.Info().Strong) }
func DoTestParentRefs(t *testing.T, repo fs.NodeRepo) { tg := treegen.New() treeSpec := tg.D("foo", tg.D("bar", tg.D("aleph", tg.F("A", tg.B(42, 65537)), tg.F("a", tg.B(42, 65537))), tg.D("beth", tg.F("B", tg.B(43, 65537)), tg.F("b", tg.B(43, 65537))), tg.D("jimmy", tg.F("G", tg.B(44, 65537)), tg.F("g", tg.B(44, 65537)))), tg.D("baz", tg.D("uno", tg.F("1", tg.B(1, 65537)), tg.F("I", tg.B(1, 65537))), tg.D("dos", tg.F("2", tg.B(11, 65537)), tg.F("II", tg.B(11, 65537))), tg.D("tres", tg.F("3", tg.B(111, 65537)), tg.F("III", tg.B(111, 65537))))) path := treegen.TestTree(t, treeSpec) defer os.RemoveAll(path) foo, errors := fs.IndexDir(filepath.Join(path, "foo"), repo) assert.Equalf(t, 0, len(errors), "%v", errors) rootCount := 0 fs.Walk(foo, func(node fs.Node) bool { switch node.(type) { case fs.Dir: dir := node.(fs.Dir) if _, hasParent := dir.Parent(); !hasParent { rootCount++ } break case fs.File: file := node.(fs.File) _, hasParent := file.Parent() assert.Tf(t, hasParent, "%v is root?!", file.Info()) break case fs.Block: block := node.(fs.Block) _, hasParent := block.Parent() assert.Tf(t, hasParent, "%v is root?!", block.Info()) break } return true }) assert.Equal(t, 1, rootCount) }
func TestPatchWeakCollision(t *testing.T) { tg := treegen.New() treeSpec := tg.D("foo", tg.F("bar", tg.B(6806, 65536))) srcpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(srcpath) srcStore, err := fs.NewLocalStore(srcpath) assert.T(t, err == nil) tg = treegen.New() treeSpec = tg.D("foo", tg.F("bar", tg.B(9869, 65536))) dstpath := treegen.TestTree(t, treeSpec) defer os.RemoveAll(dstpath) dstStore, err := fs.NewLocalStore(dstpath) assert.T(t, err == nil) // Src and dst blocks have same weak checksum assert.Equal(t, srcStore.Root().SubDirs[0].Files[0].Blocks[0].Weak(), dstStore.Root().SubDirs[0].Files[0].Blocks[0].Weak()) // Src and dst blocks have different strong checksum assert.Tf(t, srcStore.Root().Strong() != dstStore.Root().Strong(), "wtf: %v == %v", srcStore.Root().Strong(), dstStore.Root().Strong()) patchPlan := NewPatchPlan(srcStore, dstStore) // printPlan(patchPlan) failedCmd, err := patchPlan.Exec() assert.Tf(t, failedCmd == nil && err == nil, "%v: %v", failedCmd, err) srcDir, err := fs.IndexDir(srcpath) assert.T(t, err == nil) dstDir, err := fs.IndexDir(dstpath) assert.T(t, err == nil) assert.Equal(t, srcDir.Strong(), dstDir.Strong()) }
func TestRootWorks(t *testing.T) { tg := treegen.New() treeSpec := tg.D("foo", tg.F("bar", tg.B(42, 65537))) path := treegen.TestTree(t, treeSpec) defer os.RemoveAll(path) dbrepo, err := NewDbRepo(":memory:") assert.T(t, err == nil) _, errors := fs.IndexDir(filepath.Join(path, "foo"), dbrepo) assert.Equalf(t, 0, len(errors), "%v", errors) }
func DoTestDirResolve(t *testing.T, repo fs.NodeRepo) { tg := treegen.New() treeSpec := tg.D("foo", tg.D("bar", tg.D("aleph", tg.F("A", tg.B(42, 65537)), tg.F("a", tg.B(42, 65537))), tg.D("beth", tg.F("B", tg.B(43, 65537)), tg.F("b", tg.B(43, 65537))), tg.D("jimmy", tg.F("G", tg.B(44, 65537)), tg.F("g", tg.B(44, 65537)))), tg.D("baz", tg.D("uno", tg.F("1", tg.B(1, 65537)), tg.F("I", tg.B(1, 65537))), tg.D("dos", tg.F("2", tg.B(11, 65537)), tg.F("II", tg.B(11, 65537))), tg.D("tres", tg.F("3", tg.B(111, 65537)), tg.F("III", tg.B(111, 65537))))) path := treegen.TestTree(t, treeSpec) defer os.RemoveAll(path) foo, errors := fs.IndexDir(filepath.Join(path, "foo"), repo) assert.Equalf(t, 0, len(errors), "%v", errors) var node fs.FsNode var found bool node, found = fs.Lookup(foo, "bar") assert.T(t, found) _, isDir := node.(fs.Dir) assert.T(t, isDir) node, found = fs.Lookup(foo, filepath.Join("bar", "aleph")) assert.T(t, found) _, isDir = node.(fs.Dir) assert.T(t, isDir) node, found = fs.Lookup(foo, filepath.Join("bar", "aleph", "A")) assert.T(t, found) _, isFile := node.(fs.File) assert.T(t, isFile) }
func DoTestNodeRelPath(t *testing.T, repo fs.NodeRepo) { tg := treegen.New() treeSpec := tg.D("foo", tg.F("bar", tg.B(42, 65537))) path := treegen.TestTree(t, treeSpec) defer os.RemoveAll(path) dir, errors := fs.IndexDir(path, repo) assert.Equalf(t, 0, len(errors), "%v", errors) assert.Equal(t, "", fs.RelPath(dir)) assert.Equal(t, "foo", fs.RelPath(dir.SubDirs()[0])) assert.Equal(t, filepath.Join("foo", "bar"), fs.RelPath(dir.SubDirs()[0].Files()[0])) assert.Equal(t, filepath.Join("foo", "bar"), fs.RelPath(dir.SubDirs()[0].Files()[0])) }
func DoTestDirIndex(t *testing.T, repo fs.NodeRepo) { dir, errors := fs.IndexDir("../../testroot", repo) assert.T(t, dir != nil) assert.Equalf(t, 0, len(errors), "%v", errors) assert.Equal(t, 2, len(dir.SubDirs())) assert.Equal(t, 4, len(dir.Files())) assert.Equal(t, "feab33f9685531a1c1c9c22d5d8af98267ca9426", dir.Info().Strong) var myMusic fs.Dir = dir.SubDirs()[0] assert.Equal(t, "My Music", myMusic.Name()) for i := 0; i < 2; i++ { var mp4file fs.FsNode = myMusic.Files()[i] assert.Tf(t, strings.HasPrefix(mp4file.Name(), "0 10k 30"), "Unexpected d -> d -> f name: %s", mp4file.Name()) } }