github.com/mgoltzsche/ctnr@v0.7.1-alpha/pkg/fs/source/sources_test.go (about) 1 package source 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/mgoltzsche/ctnr/pkg/fs" 13 "github.com/mgoltzsche/ctnr/pkg/fs/testutils" 14 "github.com/mgoltzsche/ctnr/pkg/idutils" 15 "github.com/openSUSE/umoci/pkg/fseval" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 func TestSources(t *testing.T) { 21 tmpDir, rootfs := createTestFileSystem(t) 22 defer os.RemoveAll(tmpDir) 23 24 // Prepare source files 25 tarFile := filepath.Join(tmpDir, "archive.tar") 26 tarGzFile := filepath.Join(tmpDir, "archive.tar.gz") 27 tarBzFile := filepath.Join(tmpDir, "archive.tar.bz") 28 tarDir(t, rootfs, "-cf", tarFile) 29 tarDir(t, rootfs, "-czf", tarGzFile) 30 tarDir(t, rootfs, "-cjf", tarBzFile) 31 srcFile := filepath.Join(tmpDir, "sourcefile") 32 srcLink := filepath.Join(tmpDir, "sourcelink") 33 err := ioutil.WriteFile(srcFile, []byte("content"), 0644) 34 require.NoError(t, err) 35 err = os.Symlink(srcFile, srcLink) 36 require.NoError(t, err) 37 38 mtime, err := time.Parse(time.RFC3339, "2018-01-23T01:01:42Z") 39 require.NoError(t, err) 40 atime, err := time.Parse(time.RFC3339, "2018-01-23T01:02:42Z") 41 require.NoError(t, err) 42 43 // Test source file overlay variants 44 testee := NewSources(fseval.RootlessFsEval, fs.NewRootlessAttrMapper(idutils.MapRootless)) 45 factory := func(file string, fi os.FileInfo, usr *idutils.UserIds) (fs.Source, error) { 46 return testee.File(file, fi, usr) 47 } 48 factoryX := func(file string, fi os.FileInfo, usr *idutils.UserIds) (fs.Source, error) { 49 return testee.FileOverlay(file, fi, usr) 50 } 51 expectedArchivePaths := toWrittenPathMap(expectedWrittenPaths("/overlayx")) 52 expectedArchivePaths["/"] = true 53 expectedFilePaths := map[string]bool{"/": true, "/overlayx": true} 54 for _, c := range []struct { 55 t fs.NodeType 56 factory func(file string, fi os.FileInfo, usr *idutils.UserIds) (fs.Source, error) 57 file string 58 expectedUsr *idutils.UserIds 59 expectedPaths map[string]bool 60 }{ 61 {fs.TypeFile, factory, srcFile, &idutils.UserIds{1, 33}, expectedFilePaths}, 62 {fs.TypeFile, factoryX, srcFile, nil, expectedFilePaths}, 63 {fs.TypeSymlink, factory, srcLink, nil, expectedFilePaths}, 64 {fs.TypeSymlink, factoryX, srcLink, nil, expectedFilePaths}, 65 {fs.TypeOverlay, factoryX, tarFile, nil, expectedArchivePaths}, 66 {fs.TypeOverlay, factoryX, tarGzFile, nil, expectedArchivePaths}, 67 {fs.TypeOverlay, factoryX, tarBzFile, nil, expectedArchivePaths}, 68 // TODO: test device and URL 69 } { 70 writerMock := testutils.NewWriterMock(t, fs.AttrsAll) 71 fi, err := os.Lstat(c.file) 72 require.NoError(t, err) 73 src, err := c.factory(c.file, fi, nil) 74 require.NoError(t, err) 75 a := src.Attrs() 76 st := a.NodeType 77 if st != c.t { 78 t.Errorf("%s: expected type %s but was %s", c.file, c.t, st) 79 t.FailNow() 80 } 81 82 // Test hash 83 wa, err := src.DeriveAttrs() 84 require.NoError(t, err) 85 hash1 := wa.Hash 86 87 src, err = c.factory(c.file, fi, &idutils.UserIds{99997, 99997}) 88 require.NoError(t, err) 89 wa, err = src.DeriveAttrs() 90 require.NoError(t, err) 91 hash2 := wa.Hash 92 if hash2 == "" && c.t == fs.TypeFile { 93 t.Errorf("%s: source file hash is empty", c.file) 94 } 95 if hash1 != hash2 { 96 t.Errorf("%s: hash1 != hash1", c.file) 97 } 98 99 // Test write 100 writerMock.Dir("/", "", fs.FileAttrs{Mode: 0755}) 101 err = src.Write("/overlayx", "", &testutils.ExpandingWriterMock{writerMock}, map[fs.Source]string{}) 102 require.NoError(t, err) 103 if !assert.Equal(t, c.expectedPaths, writerMock.WrittenPaths, c.file) { 104 t.FailNow() 105 } 106 } 107 108 // Test if actual file attributes applied 109 testee = NewSources(fseval.RootlessFsEval, fs.NewAttrMapper(idutils.MapIdentity)) 110 err = fseval.RootlessFsEval.Lutimes(srcFile, atime, mtime) 111 require.NoError(t, err) 112 uid := os.Geteuid() 113 gid := os.Getegid() 114 writerMock := testutils.NewWriterMock(t, fs.AttrsAll) 115 fi, err := os.Lstat(srcFile) 116 require.NoError(t, err) 117 r, err := testee.File(srcFile, fi, nil) 118 require.NoError(t, err) 119 err = r.Write("/file1", "file1", writerMock, map[fs.Source]string{}) 120 require.NoError(t, err) 121 usr := "" 122 if uid != 0 || gid != 0 { 123 usr = fmt.Sprintf(" usr=%d:%d", uid, gid) 124 } 125 expected := fmt.Sprintf("/file1 type=file%s mode=644 size=7 mtime=1516669302", usr) 126 expected += " atime=1516669362 hash=sha256:ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73" 127 assert.Equal(t, []string{expected}, writerMock.Written, "sources should map file attributes") 128 } 129 130 func toWrittenPathMap(paths []string) map[string]bool { 131 r := map[string]bool{} 132 for _, line := range paths { 133 r[strings.Split(line, " ")[0]] = true 134 } 135 return r 136 }