github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/daemon/graphdriver/copy/copy_test.go (about)

     1  // +build linux
     2  
     3  package copy // import "github.com/demonoid81/moby/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/demonoid81/moby/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  		assert.NilError(t, err)
    57  
    58  		// If we add non-regular dirs and files to the test
    59  		// then we need to add more checks here.
    60  		dstFileInfo, err := os.Lstat(dstPath)
    61  		assert.NilError(t, err)
    62  
    63  		srcFileSys := f.Sys().(*syscall.Stat_t)
    64  		dstFileSys := dstFileInfo.Sys().(*syscall.Stat_t)
    65  
    66  		t.Log(relPath)
    67  		if srcFileSys.Dev == dstFileSys.Dev {
    68  			assert.Check(t, srcFileSys.Ino != dstFileSys.Ino)
    69  		}
    70  		// Todo: check size, and ctim is not equal on filesystems that have granular ctimes
    71  		assert.Check(t, is.DeepEqual(srcFileSys.Mode, dstFileSys.Mode))
    72  		assert.Check(t, is.DeepEqual(srcFileSys.Uid, dstFileSys.Uid))
    73  		assert.Check(t, is.DeepEqual(srcFileSys.Gid, dstFileSys.Gid))
    74  		assert.Check(t, is.DeepEqual(srcFileSys.Mtim, dstFileSys.Mtim))
    75  
    76  		return nil
    77  	}))
    78  }
    79  
    80  func randomMode(baseMode int) os.FileMode {
    81  	for i := 0; i < 7; i++ {
    82  		baseMode = baseMode | (1&rand.Intn(2))<<uint(i)
    83  	}
    84  	return os.FileMode(baseMode)
    85  }
    86  
    87  func populateSrcDir(t *testing.T, srcDir string, remainingDepth int) {
    88  	if remainingDepth == 0 {
    89  		return
    90  	}
    91  	aTime := time.Unix(rand.Int63(), 0)
    92  	mTime := time.Unix(rand.Int63(), 0)
    93  
    94  	for i := 0; i < 10; i++ {
    95  		dirName := filepath.Join(srcDir, fmt.Sprintf("srcdir-%d", i))
    96  		// Owner all bits set
    97  		assert.NilError(t, os.Mkdir(dirName, randomMode(0700)))
    98  		populateSrcDir(t, dirName, remainingDepth-1)
    99  		assert.NilError(t, system.Chtimes(dirName, aTime, mTime))
   100  	}
   101  
   102  	for i := 0; i < 10; i++ {
   103  		fileName := filepath.Join(srcDir, fmt.Sprintf("srcfile-%d", i))
   104  		// Owner read bit set
   105  		assert.NilError(t, ioutil.WriteFile(fileName, []byte{}, randomMode(0400)))
   106  		assert.NilError(t, system.Chtimes(fileName, aTime, mTime))
   107  	}
   108  }
   109  
   110  func doCopyTest(t *testing.T, copyWithFileRange, copyWithFileClone *bool) {
   111  	dir, err := ioutil.TempDir("", "docker-copy-check")
   112  	assert.NilError(t, err)
   113  	defer os.RemoveAll(dir)
   114  	srcFilename := filepath.Join(dir, "srcFilename")
   115  	dstFilename := filepath.Join(dir, "dstilename")
   116  
   117  	r := rand.New(rand.NewSource(0))
   118  	buf := make([]byte, 1024)
   119  	_, err = r.Read(buf)
   120  	assert.NilError(t, err)
   121  	assert.NilError(t, ioutil.WriteFile(srcFilename, buf, 0777))
   122  	fileinfo, err := os.Stat(srcFilename)
   123  	assert.NilError(t, err)
   124  
   125  	assert.NilError(t, copyRegular(srcFilename, dstFilename, fileinfo, copyWithFileRange, copyWithFileClone))
   126  	readBuf, err := ioutil.ReadFile(dstFilename)
   127  	assert.NilError(t, err)
   128  	assert.Check(t, is.DeepEqual(buf, readBuf))
   129  }
   130  
   131  func TestCopyHardlink(t *testing.T) {
   132  	var srcFile1FileInfo, srcFile2FileInfo, dstFile1FileInfo, dstFile2FileInfo unix.Stat_t
   133  
   134  	srcDir, err := ioutil.TempDir("", "srcDir")
   135  	assert.NilError(t, err)
   136  	defer os.RemoveAll(srcDir)
   137  
   138  	dstDir, err := ioutil.TempDir("", "dstDir")
   139  	assert.NilError(t, err)
   140  	defer os.RemoveAll(dstDir)
   141  
   142  	srcFile1 := filepath.Join(srcDir, "file1")
   143  	srcFile2 := filepath.Join(srcDir, "file2")
   144  	dstFile1 := filepath.Join(dstDir, "file1")
   145  	dstFile2 := filepath.Join(dstDir, "file2")
   146  	assert.NilError(t, ioutil.WriteFile(srcFile1, []byte{}, 0777))
   147  	assert.NilError(t, os.Link(srcFile1, srcFile2))
   148  
   149  	assert.Check(t, DirCopy(srcDir, dstDir, Content, false))
   150  
   151  	assert.NilError(t, unix.Stat(srcFile1, &srcFile1FileInfo))
   152  	assert.NilError(t, unix.Stat(srcFile2, &srcFile2FileInfo))
   153  	assert.Equal(t, srcFile1FileInfo.Ino, srcFile2FileInfo.Ino)
   154  
   155  	assert.NilError(t, unix.Stat(dstFile1, &dstFile1FileInfo))
   156  	assert.NilError(t, unix.Stat(dstFile2, &dstFile2FileInfo))
   157  	assert.Check(t, is.Equal(dstFile1FileInfo.Ino, dstFile2FileInfo.Ino))
   158  }