diff options
| author | 2023-04-28 01:36:44 +0800 | |
|---|---|---|
| committer | 2023-04-28 01:36:44 +0800 | |
| commit | dd84b9d64fb98746a230cd24233ff50a562c39c9 (patch) | |
| tree | b583261ef00b3afe72ec4d6dacb31e57779a6faf /cli/internal/fs/copy_file_test.go | |
| parent | 0b46fcd72ac34382387b2bcf9095233efbcc52f4 (diff) | |
| download | HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.tar.gz HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.zip | |
Diffstat (limited to 'cli/internal/fs/copy_file_test.go')
| -rw-r--r-- | cli/internal/fs/copy_file_test.go | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/cli/internal/fs/copy_file_test.go b/cli/internal/fs/copy_file_test.go new file mode 100644 index 0000000..6a61576 --- /dev/null +++ b/cli/internal/fs/copy_file_test.go @@ -0,0 +1,198 @@ +package fs + +import ( + "errors" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/vercel/turbo/cli/internal/turbopath" + "gotest.tools/v3/assert" + "gotest.tools/v3/fs" +) + +func TestCopyFile(t *testing.T) { + srcTmpDir := turbopath.AbsoluteSystemPath(t.TempDir()) + destTmpDir := turbopath.AbsoluteSystemPath(t.TempDir()) + srcFilePath := srcTmpDir.UntypedJoin("src") + destFilePath := destTmpDir.UntypedJoin("dest") + from := &LstatCachedFile{Path: srcFilePath} + + // The src file doesn't exist, will error. + err := CopyFile(from, destFilePath.ToString()) + pathErr := &os.PathError{} + if !errors.As(err, &pathErr) { + t.Errorf("got %v, want PathError", err) + } + + // Create the src file. + srcFile, err := srcFilePath.Create() + assert.NilError(t, err, "Create") + _, err = srcFile.WriteString("src") + assert.NilError(t, err, "WriteString") + assert.NilError(t, srcFile.Close(), "Close") + + // Copy the src to the dest. + err = CopyFile(from, destFilePath.ToString()) + assert.NilError(t, err, "src exists dest does not, should not error.") + + // Now test for symlinks. + symlinkSrcDir := turbopath.AbsoluteSystemPath(t.TempDir()) + symlinkTargetDir := turbopath.AbsoluteSystemPath(t.TempDir()) + symlinkDestDir := turbopath.AbsoluteSystemPath(t.TempDir()) + symlinkSrcPath := symlinkSrcDir.UntypedJoin("symlink") + symlinkTargetPath := symlinkTargetDir.UntypedJoin("target") + symlinkDestPath := symlinkDestDir.UntypedJoin("dest") + fromSymlink := &LstatCachedFile{Path: symlinkSrcPath} + + // Create the symlink target. + symlinkTargetFile, err := symlinkTargetPath.Create() + assert.NilError(t, err, "Create") + _, err = symlinkTargetFile.WriteString("Target") + assert.NilError(t, err, "WriteString") + assert.NilError(t, symlinkTargetFile.Close(), "Close") + + // Link things up. + err = symlinkSrcPath.Symlink(symlinkTargetPath.ToString()) + assert.NilError(t, err, "Symlink") + + // Run the test. + err = CopyFile(fromSymlink, symlinkDestPath.ToString()) + assert.NilError(t, err, "Copying a valid symlink does not error.") + + // Break the symlink. + err = symlinkTargetPath.Remove() + assert.NilError(t, err, "breaking the symlink") + + // Remove the existing copy. + err = symlinkDestPath.Remove() + assert.NilError(t, err, "existing copy is removed") + + // Try copying the now-broken symlink. + err = CopyFile(fromSymlink, symlinkDestPath.ToString()) + assert.NilError(t, err, "CopyFile") + + // Confirm that it copied + target, err := symlinkDestPath.Readlink() + assert.NilError(t, err, "Readlink") + assert.Equal(t, target, symlinkTargetPath.ToString()) +} + +func TestCopyOrLinkFileWithPerms(t *testing.T) { + // Directory layout: + // + // <src>/ + // foo + readonlyMode := os.FileMode(0444) + srcDir := turbopath.AbsoluteSystemPath(t.TempDir()) + dstDir := turbopath.AbsoluteSystemPath(t.TempDir()) + srcFilePath := srcDir.UntypedJoin("src") + dstFilePath := dstDir.UntypedJoin("dst") + srcFile, err := srcFilePath.Create() + defer func() { _ = srcFile.Close() }() + assert.NilError(t, err, "Create") + err = srcFile.Chmod(readonlyMode) + assert.NilError(t, err, "Chmod") + err = CopyFile(&LstatCachedFile{Path: srcFilePath}, dstFilePath.ToStringDuringMigration()) + assert.NilError(t, err, "CopyOrLinkFile") + info, err := dstFilePath.Lstat() + assert.NilError(t, err, "Lstat") + assert.Equal(t, info.Mode(), readonlyMode, "expected dest to have matching permissions") +} + +func TestRecursiveCopy(t *testing.T) { + // Directory layout: + // + // <src>/ + // b + // child/ + // a + // link -> ../b + // broken -> missing + // circle -> ../child + src := fs.NewDir(t, "recursive-copy-or-link") + dst := fs.NewDir(t, "recursive-copy-or-link-dist") + childDir := filepath.Join(src.Path(), "child") + err := os.Mkdir(childDir, os.ModeDir|0777) + assert.NilError(t, err, "Mkdir") + aPath := filepath.Join(childDir, "a") + aFile, err := os.Create(aPath) + assert.NilError(t, err, "Create") + _, err = aFile.WriteString("hello") + assert.NilError(t, err, "WriteString") + assert.NilError(t, aFile.Close(), "Close") + + bPath := filepath.Join(src.Path(), "b") + bFile, err := os.Create(bPath) + assert.NilError(t, err, "Create") + _, err = bFile.WriteString("bFile") + assert.NilError(t, err, "WriteString") + assert.NilError(t, bFile.Close(), "Close") + + srcLinkPath := filepath.Join(childDir, "link") + assert.NilError(t, os.Symlink(filepath.FromSlash("../b"), srcLinkPath), "Symlink") + + srcBrokenLinkPath := filepath.Join(childDir, "broken") + assert.NilError(t, os.Symlink("missing", srcBrokenLinkPath), "Symlink") + circlePath := filepath.Join(childDir, "circle") + assert.NilError(t, os.Symlink(filepath.FromSlash("../child"), circlePath), "Symlink") + + err = RecursiveCopy(src.Path(), dst.Path()) + assert.NilError(t, err, "RecursiveCopy") + // For ensure multiple times copy will not broken + err = RecursiveCopy(src.Path(), dst.Path()) + assert.NilError(t, err, "RecursiveCopy") + + dstChildDir := filepath.Join(dst.Path(), "child") + assertDirMatches(t, childDir, dstChildDir) + dstAPath := filepath.Join(dst.Path(), "child", "a") + assertFileMatches(t, aPath, dstAPath) + dstBPath := filepath.Join(dst.Path(), "b") + assertFileMatches(t, bPath, dstBPath) + dstLinkPath := filepath.Join(dst.Path(), "child", "link") + dstLinkDest, err := os.Readlink(dstLinkPath) + assert.NilError(t, err, "Readlink") + expectedLinkDest := filepath.FromSlash("../b") + if dstLinkDest != expectedLinkDest { + t.Errorf("Readlink got %v, want %v", dstLinkDest, expectedLinkDest) + } + dstBrokenLinkPath := filepath.Join(dst.Path(), "child", "broken") + brokenLinkExists := PathExists(dstBrokenLinkPath) + if brokenLinkExists { + t.Errorf("We cached a broken link at %v", dstBrokenLinkPath) + } + // Currently, we convert symlink-to-directory to empty-directory + // This is very likely not ideal behavior, but leaving this test here to verify + // that it is what we expect at this point in time. + dstCirclePath := filepath.Join(dst.Path(), "child", "circle") + circleStat, err := os.Lstat(dstCirclePath) + assert.NilError(t, err, "Lstat") + assert.Equal(t, circleStat.IsDir(), true) + entries, err := os.ReadDir(dstCirclePath) + assert.NilError(t, err, "ReadDir") + assert.Equal(t, len(entries), 0) +} + +func assertFileMatches(t *testing.T, orig string, copy string) { + t.Helper() + origBytes, err := ioutil.ReadFile(orig) + assert.NilError(t, err, "ReadFile") + copyBytes, err := ioutil.ReadFile(copy) + assert.NilError(t, err, "ReadFile") + assert.DeepEqual(t, origBytes, copyBytes) + origStat, err := os.Lstat(orig) + assert.NilError(t, err, "Lstat") + copyStat, err := os.Lstat(copy) + assert.NilError(t, err, "Lstat") + assert.Equal(t, origStat.Mode(), copyStat.Mode()) +} + +func assertDirMatches(t *testing.T, orig string, copy string) { + t.Helper() + origStat, err := os.Lstat(orig) + assert.NilError(t, err, "Lstat") + copyStat, err := os.Lstat(copy) + assert.NilError(t, err, "Lstat") + assert.Equal(t, origStat.Mode(), copyStat.Mode()) +} |
