github.com/OpenFlowLabs/storage@v1.12.13/drivers/copy/copy_test.go (about)

     1  // +build linux
     2  
     3  package 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/containers/storage/pkg/system"
    16  	"golang.org/x/sys/unix"
    17  	"gotest.tools/assert"
    18  	is "gotest.tools/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
    71  		/// on filesystems that have granular ctimes
    72  		assert.Check(t, is.DeepEqual(srcFileSys.Mode, dstFileSys.Mode))
    73  		assert.Check(t, is.DeepEqual(srcFileSys.Uid, dstFileSys.Uid))
    74  		assert.Check(t, is.DeepEqual(srcFileSys.Gid, dstFileSys.Gid))
    75  		assert.Check(t, is.DeepEqual(srcFileSys.Mtim, dstFileSys.Mtim))
    76  
    77  		return nil
    78  	}))
    79  }
    80  
    81  func randomMode(baseMode int) os.FileMode {
    82  	for i := 0; i < 7; i++ {
    83  		baseMode = baseMode | (1&rand.Intn(2))<<uint(i)
    84  	}
    85  	return os.FileMode(baseMode)
    86  }
    87  
    88  func populateSrcDir(t *testing.T, srcDir string, remainingDepth int) {
    89  	if remainingDepth == 0 {
    90  		return
    91  	}
    92  	aTime := time.Unix(rand.Int63(), 0)
    93  	mTime := time.Unix(rand.Int63(), 0)
    94  
    95  	for i := 0; i < 10; i++ {
    96  		dirName := filepath.Join(srcDir, fmt.Sprintf("srcdir-%d", i))
    97  		// Owner all bits set
    98  		assert.NilError(t, os.Mkdir(dirName, randomMode(0700)))
    99  		populateSrcDir(t, dirName, remainingDepth-1)
   100  		assert.NilError(t, system.Chtimes(dirName, aTime, mTime))
   101  	}
   102  
   103  	for i := 0; i < 10; i++ {
   104  		fileName := filepath.Join(srcDir, fmt.Sprintf("srcfile-%d", i))
   105  		// Owner read bit set
   106  		assert.NilError(t, ioutil.WriteFile(fileName, []byte{}, randomMode(0400)))
   107  		assert.NilError(t, system.Chtimes(fileName, aTime, mTime))
   108  	}
   109  }
   110  
   111  func doCopyTest(t *testing.T, copyWithFileRange, copyWithFileClone *bool) {
   112  	dir, err := ioutil.TempDir("", "storage-copy-check")
   113  	assert.NilError(t, err)
   114  	defer os.RemoveAll(dir)
   115  	srcFilename := filepath.Join(dir, "srcFilename")
   116  	dstFilename := filepath.Join(dir, "dstilename")
   117  
   118  	r := rand.New(rand.NewSource(0))
   119  	buf := make([]byte, 1024)
   120  	_, err = r.Read(buf)
   121  	assert.NilError(t, err)
   122  	assert.NilError(t, ioutil.WriteFile(srcFilename, buf, 0777))
   123  	fileinfo, err := os.Stat(srcFilename)
   124  	assert.NilError(t, err)
   125  
   126  	assert.NilError(t, copyRegular(srcFilename, dstFilename, fileinfo, copyWithFileRange, copyWithFileClone))
   127  	readBuf, err := ioutil.ReadFile(dstFilename)
   128  	assert.NilError(t, err)
   129  	assert.Check(t, is.DeepEqual(buf, readBuf))
   130  }
   131  
   132  func TestCopyHardlink(t *testing.T) {
   133  	var srcFile1FileInfo, srcFile2FileInfo, dstFile1FileInfo, dstFile2FileInfo unix.Stat_t
   134  
   135  	srcDir, err := ioutil.TempDir("", "srcDir")
   136  	assert.NilError(t, err)
   137  	defer os.RemoveAll(srcDir)
   138  
   139  	dstDir, err := ioutil.TempDir("", "dstDir")
   140  	assert.NilError(t, err)
   141  	defer os.RemoveAll(dstDir)
   142  
   143  	srcFile1 := filepath.Join(srcDir, "file1")
   144  	srcFile2 := filepath.Join(srcDir, "file2")
   145  	dstFile1 := filepath.Join(dstDir, "file1")
   146  	dstFile2 := filepath.Join(dstDir, "file2")
   147  	assert.NilError(t, ioutil.WriteFile(srcFile1, []byte{}, 0777))
   148  	assert.NilError(t, os.Link(srcFile1, srcFile2))
   149  
   150  	assert.Check(t, DirCopy(srcDir, dstDir, Content, false))
   151  
   152  	assert.NilError(t, unix.Stat(srcFile1, &srcFile1FileInfo))
   153  	assert.NilError(t, unix.Stat(srcFile2, &srcFile2FileInfo))
   154  	assert.Equal(t, srcFile1FileInfo.Ino, srcFile2FileInfo.Ino)
   155  
   156  	assert.NilError(t, unix.Stat(dstFile1, &dstFile1FileInfo))
   157  	assert.NilError(t, unix.Stat(dstFile2, &dstFile2FileInfo))
   158  	assert.Check(t, is.Equal(dstFile1FileInfo.Ino, dstFile2FileInfo.Ino))
   159  }