github.com/wozhu6104/docker@v20.10.10+incompatible/daemon/graphdriver/copy/copy_test.go (about)

     1  // +build linux
     2  
     3  package copy // import "github.com/docker/docker/daemon/graphdriver/copy"
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"math/rand"
     9  	"os"
    10  	"path/filepath"
    11  	"syscall"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/docker/docker/pkg/system"
    16  	"golang.org/x/sys/unix"
    17  	"gotest.tools/v3/assert"
    18  	is "gotest.tools/v3/assert/cmp"
    19  )
    20  
    21  func TestCopy(t *testing.T) {
    22  	copyWithFileRange := true
    23  	copyWithFileClone := true
    24  	doCopyTest(t, &copyWithFileRange, &copyWithFileClone)
    25  }
    26  
    27  func TestCopyWithoutRange(t *testing.T) {
    28  	copyWithFileRange := false
    29  	copyWithFileClone := false
    30  	doCopyTest(t, &copyWithFileRange, &copyWithFileClone)
    31  }
    32  
    33  func TestCopyDir(t *testing.T) {
    34  	srcDir, err := ioutil.TempDir("", "srcDir")
    35  	assert.NilError(t, err)
    36  	populateSrcDir(t, srcDir, 3)
    37  
    38  	dstDir, err := ioutil.TempDir("", "testdst")
    39  	assert.NilError(t, err)
    40  	defer os.RemoveAll(dstDir)
    41  
    42  	assert.Check(t, DirCopy(srcDir, dstDir, Content, false))
    43  	assert.NilError(t, filepath.Walk(srcDir, func(srcPath string, f os.FileInfo, err error) error {
    44  		if err != nil {
    45  			return err
    46  		}
    47  
    48  		// Rebase path
    49  		relPath, err := filepath.Rel(srcDir, srcPath)
    50  		assert.NilError(t, err)
    51  		if relPath == "." {
    52  			return nil
    53  		}
    54  
    55  		dstPath := filepath.Join(dstDir, relPath)
    56  
    57  		// If we add non-regular dirs and files to the test
    58  		// then we need to add more checks here.
    59  		dstFileInfo, err := os.Lstat(dstPath)
    60  		assert.NilError(t, err)
    61  
    62  		srcFileSys := f.Sys().(*syscall.Stat_t)
    63  		dstFileSys := dstFileInfo.Sys().(*syscall.Stat_t)
    64  
    65  		t.Log(relPath)
    66  		if srcFileSys.Dev == dstFileSys.Dev {
    67  			assert.Check(t, srcFileSys.Ino != dstFileSys.Ino)
    68  		}
    69  		// Todo: check size, and ctim is not equal on filesystems that have granular ctimes
    70  		assert.Check(t, is.DeepEqual(srcFileSys.Mode, dstFileSys.Mode))
    71  		assert.Check(t, is.DeepEqual(srcFileSys.Uid, dstFileSys.Uid))
    72  		assert.Check(t, is.DeepEqual(srcFileSys.Gid, dstFileSys.Gid))
    73  		assert.Check(t, is.DeepEqual(srcFileSys.Mtim, dstFileSys.Mtim))
    74  
    75  		return nil
    76  	}))
    77  }
    78  
    79  func randomMode(baseMode int) os.FileMode {
    80  	for i := 0; i < 7; i++ {
    81  		baseMode = baseMode | (1&rand.Intn(2))<<uint(i)
    82  	}
    83  	return os.FileMode(baseMode)
    84  }
    85  
    86  func populateSrcDir(t *testing.T, srcDir string, remainingDepth int) {
    87  	if remainingDepth == 0 {
    88  		return
    89  	}
    90  	aTime := time.Unix(rand.Int63(), 0)
    91  	mTime := time.Unix(rand.Int63(), 0)
    92  
    93  	for i := 0; i < 10; i++ {
    94  		dirName := filepath.Join(srcDir, fmt.Sprintf("srcdir-%d", i))
    95  		// Owner all bits set
    96  		assert.NilError(t, os.Mkdir(dirName, randomMode(0700)))
    97  		populateSrcDir(t, dirName, remainingDepth-1)
    98  		assert.NilError(t, system.Chtimes(dirName, aTime, mTime))
    99  	}
   100  
   101  	for i := 0; i < 10; i++ {
   102  		fileName := filepath.Join(srcDir, fmt.Sprintf("srcfile-%d", i))
   103  		// Owner read bit set
   104  		assert.NilError(t, ioutil.WriteFile(fileName, []byte{}, randomMode(0400)))
   105  		assert.NilError(t, system.Chtimes(fileName, aTime, mTime))
   106  	}
   107  }
   108  
   109  func doCopyTest(t *testing.T, copyWithFileRange, copyWithFileClone *bool) {
   110  	dir, err := ioutil.TempDir("", "docker-copy-check")
   111  	assert.NilError(t, err)
   112  	defer os.RemoveAll(dir)
   113  	srcFilename := filepath.Join(dir, "srcFilename")
   114  	dstFilename := filepath.Join(dir, "dstilename")
   115  
   116  	r := rand.New(rand.NewSource(0))
   117  	buf := make([]byte, 1024)
   118  	_, err = r.Read(buf)
   119  	assert.NilError(t, err)
   120  	assert.NilError(t, ioutil.WriteFile(srcFilename, buf, 0777))
   121  	fileinfo, err := os.Stat(srcFilename)
   122  	assert.NilError(t, err)
   123  
   124  	assert.NilError(t, copyRegular(srcFilename, dstFilename, fileinfo, copyWithFileRange, copyWithFileClone))
   125  	readBuf, err := ioutil.ReadFile(dstFilename)
   126  	assert.NilError(t, err)
   127  	assert.Check(t, is.DeepEqual(buf, readBuf))
   128  }
   129  
   130  func TestCopyHardlink(t *testing.T) {
   131  	var srcFile1FileInfo, srcFile2FileInfo, dstFile1FileInfo, dstFile2FileInfo unix.Stat_t
   132  
   133  	srcDir, err := ioutil.TempDir("", "srcDir")
   134  	assert.NilError(t, err)
   135  	defer os.RemoveAll(srcDir)
   136  
   137  	dstDir, err := ioutil.TempDir("", "dstDir")
   138  	assert.NilError(t, err)
   139  	defer os.RemoveAll(dstDir)
   140  
   141  	srcFile1 := filepath.Join(srcDir, "file1")
   142  	srcFile2 := filepath.Join(srcDir, "file2")
   143  	dstFile1 := filepath.Join(dstDir, "file1")
   144  	dstFile2 := filepath.Join(dstDir, "file2")
   145  	assert.NilError(t, ioutil.WriteFile(srcFile1, []byte{}, 0777))
   146  	assert.NilError(t, os.Link(srcFile1, srcFile2))
   147  
   148  	assert.Check(t, DirCopy(srcDir, dstDir, Content, false))
   149  
   150  	assert.NilError(t, unix.Stat(srcFile1, &srcFile1FileInfo))
   151  	assert.NilError(t, unix.Stat(srcFile2, &srcFile2FileInfo))
   152  	assert.Equal(t, srcFile1FileInfo.Ino, srcFile2FileInfo.Ino)
   153  
   154  	assert.NilError(t, unix.Stat(dstFile1, &dstFile1FileInfo))
   155  	assert.NilError(t, unix.Stat(dstFile2, &dstFile2FileInfo))
   156  	assert.Check(t, is.Equal(dstFile1FileInfo.Ino, dstFile2FileInfo.Ino))
   157  }