github.com/mgoltzsche/ctnr@v0.7.1-alpha/pkg/fs/testutils/writermocks.go (about) 1 package testutils 2 3 import ( 4 "net/url" 5 "path/filepath" 6 "strings" 7 "testing" 8 9 "github.com/mgoltzsche/ctnr/pkg/fs" 10 "github.com/stretchr/testify/require" 11 ) 12 13 type TestNode interface { 14 Write(fs.Writer) error 15 } 16 17 func MockWrites(t *testing.T, f TestNode) *WriterMock { 18 mockWriter := NewWriterMock(t, fs.AttrsHash) 19 err := f.Write(mockWriter) 20 require.NoError(t, err) 21 return mockWriter 22 } 23 24 type WriterMock struct { 25 t *testing.T 26 Written []string 27 WrittenPaths map[string]bool 28 Nodes []string 29 attrs fs.AttrSet 30 } 31 32 func NewWriterMock(t *testing.T, attrs fs.AttrSet) *WriterMock { 33 return &WriterMock{t, []string{}, map[string]bool{}, []string{}, attrs} 34 } 35 func (w *WriterMock) Parent() error { 36 return nil 37 } 38 func (w *WriterMock) Mkdir(dir string) error { 39 return nil 40 } 41 func (s *WriterMock) LowerNode(path, name string, a *fs.NodeAttrs) error { 42 line := s.opString(a.NodeType, path, &a.FileAttrs) 43 if a.Hash != "" { 44 line += " hash=" + a.Hash 45 } 46 if a.URL != "" { 47 line += " url=" + a.URL 48 } 49 if a.HTTPInfo != "" { 50 line += " http=" + a.HTTPInfo 51 } 52 s.Nodes = append(s.Nodes, line) 53 return nil 54 } 55 func (s *WriterMock) Lazy(path, name string, src fs.LazySource, _ map[fs.Source]string) error { 56 a := src.Attrs() 57 da, err := src.DeriveAttrs() 58 require.NoError(s.t, err) 59 require.True(s.t, a.Symlink == "", "%s: link != ''", path) 60 require.NotNil(s.t, src, "%s: source not provided", path) 61 line := s.opString(a.NodeType, path, &a.FileAttrs) + " hash=" + da.Hash 62 s.Nodes = append(s.Nodes, line) 63 s.Written = append(s.Written, line) 64 s.WrittenPaths[filepath.Clean("/"+path)] = true 65 return nil 66 } 67 func (s *WriterMock) File(path string, src fs.FileSource) (fs.Source, error) { 68 require.NotNil(s.t, src, "%s: source not provided", path) 69 a := src.Attrs() 70 require.True(s.t, a.Mode != 0 || strings.Contains(path, "blockA") || strings.Contains(path, "chrdevA"), "%s: mode != 0", path) 71 require.True(s.t, a.Symlink == "", "%s: link != ''", path) 72 line := s.opString("file", path, &a.FileAttrs) 73 if s.attrs&fs.AttrsHash != 0 { 74 da, err := src.DeriveAttrs() 75 require.NoError(s.t, err) 76 require.True(s.t, da.Hash != "" || da.HTTPInfo != "", "%s: hash|http == ''; hash=%q, http=%q", path, da.Hash, da.HTTPInfo) 77 if da.Hash != "" { 78 line += " hash=" + da.Hash 79 } 80 if da.URL != "" { 81 line += " url=" + da.URL 82 } 83 if da.HTTPInfo != "" { 84 line += " http=" + da.HTTPInfo 85 } 86 } 87 s.Nodes = append(s.Nodes, line) 88 s.Written = append(s.Written, line) 89 s.WrittenPaths[filepath.Clean("/"+path)] = true 90 return src, nil 91 } 92 func (s *WriterMock) Link(path, target string) error { 93 s.link(path, target) 94 line := path + " hlink=" + target 95 s.Written = append(s.Written, line) 96 s.WrittenPaths[filepath.Clean("/"+path)] = true 97 return nil 98 } 99 func (s *WriterMock) LowerLink(path, target string, a *fs.NodeAttrs) error { 100 s.link(path, target) 101 return nil 102 } 103 func (s *WriterMock) link(path, target string) { 104 require.True(s.t, target != "", "%s: link target must be provided", path) 105 line := path + " hlink=" + target 106 s.Nodes = append(s.Nodes, line) 107 } 108 func (s *WriterMock) Symlink(path string, a fs.FileAttrs) error { 109 require.True(s.t, a.Symlink != "", "%s: symlink dest must be provided", path) 110 line := s.opString(fs.TypeSymlink, path, &a) 111 s.Nodes = append(s.Nodes, line) 112 s.Written = append(s.Written, line) 113 s.WrittenPaths[filepath.Clean("/"+path)] = true 114 return nil 115 } 116 func (s *WriterMock) Dir(path, name string, a fs.FileAttrs) error { 117 require.True(s.t, a.Mode != 0, "%s: mode != 0", path) 118 require.True(s.t, a.Symlink == "", "%s: link != ''", path) 119 line := s.opString(fs.TypeDir, path, &a) 120 s.Nodes = append(s.Nodes, line) 121 s.Written = append(s.Written, line) 122 s.WrittenPaths[filepath.Clean("/"+path)] = true 123 return nil 124 } 125 func (s *WriterMock) Fifo(path string, a fs.DeviceAttrs) error { 126 line := s.opString(fs.TypeFifo, path, &a.FileAttrs) 127 s.Nodes = append(s.Nodes, line) 128 s.Written = append(s.Written, line) 129 s.WrittenPaths[filepath.Clean("/"+path)] = true 130 return nil 131 } 132 func (s *WriterMock) Device(path string, a fs.DeviceAttrs) error { 133 line := s.opString(fs.TypeDevice, path, &a.FileAttrs) 134 s.Nodes = append(s.Nodes, line) 135 s.Written = append(s.Written, line) 136 s.WrittenPaths[filepath.Clean("/"+path)] = true 137 return nil 138 } 139 func (s *WriterMock) Remove(path string) error { 140 line := path + " type=whiteout" 141 s.Nodes = append(s.Nodes, line) 142 s.Written = append(s.Written, line) 143 s.WrittenPaths[filepath.Clean("/"+path)] = true 144 return nil 145 } 146 func (s *WriterMock) opString(t fs.NodeType, path string, a *fs.FileAttrs) string { 147 return encodePath(path) + " " + (&fs.NodeInfo{t, *a}).AttrString(s.attrs) 148 } 149 150 type ExpandingWriterMock struct { 151 *WriterMock 152 } 153 154 func (s *ExpandingWriterMock) Lazy(path, name string, src fs.LazySource, written map[fs.Source]string) error { 155 return src.Expand(path, s, written) 156 } 157 158 func encodePath(p string) string { 159 l := strings.Split(p, string(filepath.Separator)) 160 for i, s := range l { 161 l[i] = url.PathEscape(s) 162 } 163 return strings.Join(l, string(filepath.Separator)) 164 }