// +build linux package copy // import "github.com/docker/docker/daemon/graphdriver/copy" import ( "fmt" "io/ioutil" "math/rand" "os" "path/filepath" "syscall" "testing" "time" "github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/docker/pkg/system" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/sys/unix" ) func TestIsCopyFileRangeSyscallAvailable(t *testing.T) { // Verifies: // 1. That copyFileRangeEnabled is being set to true when copy_file_range syscall is available // 2. That isCopyFileRangeSyscallAvailable() works on "new" kernels v, err := kernel.GetKernelVersion() require.NoError(t, err) copyWithFileRange := true copyWithFileClone := false doCopyTest(t, ©WithFileRange, ©WithFileClone) if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: 4, Major: 5, Minor: 0}) < 0 { assert.False(t, copyWithFileRange) } else { assert.True(t, copyWithFileRange) } } func TestCopy(t *testing.T) { copyWithFileRange := true copyWithFileClone := true doCopyTest(t, ©WithFileRange, ©WithFileClone) } func TestCopyWithoutRange(t *testing.T) { copyWithFileRange := false copyWithFileClone := false doCopyTest(t, ©WithFileRange, ©WithFileClone) } func TestCopyDir(t *testing.T) { srcDir, err := ioutil.TempDir("", "srcDir") require.NoError(t, err) populateSrcDir(t, srcDir, 3) dstDir, err := ioutil.TempDir("", "testdst") require.NoError(t, err) defer os.RemoveAll(dstDir) assert.NoError(t, DirCopy(srcDir, dstDir, Content, false)) require.NoError(t, filepath.Walk(srcDir, func(srcPath string, f os.FileInfo, err error) error { if err != nil { return err } // Rebase path relPath, err := filepath.Rel(srcDir, srcPath) require.NoError(t, err) if relPath == "." { return nil } dstPath := filepath.Join(dstDir, relPath) require.NoError(t, err) // If we add non-regular dirs and files to the test // then we need to add more checks here. dstFileInfo, err := os.Lstat(dstPath) require.NoError(t, err) srcFileSys := f.Sys().(*syscall.Stat_t) dstFileSys := dstFileInfo.Sys().(*syscall.Stat_t) t.Log(relPath) if srcFileSys.Dev == dstFileSys.Dev { assert.NotEqual(t, srcFileSys.Ino, dstFileSys.Ino) } // Todo: check size, and ctim is not equal /// on filesystems that have granular ctimes assert.Equal(t, srcFileSys.Mode, dstFileSys.Mode) assert.Equal(t, srcFileSys.Uid, dstFileSys.Uid) assert.Equal(t, srcFileSys.Gid, dstFileSys.Gid) assert.Equal(t, srcFileSys.Mtim, dstFileSys.Mtim) return nil })) } func randomMode(baseMode int) os.FileMode { for i := 0; i < 7; i++ { baseMode = baseMode | (1&rand.Intn(2))<