github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/integration/container/copy_test.go (about) 1 package container // import "github.com/Prakhar-Agarwal-byte/moby/integration/container" 2 3 import ( 4 "archive/tar" 5 "bytes" 6 "encoding/json" 7 "io" 8 "os" 9 "path/filepath" 10 "testing" 11 12 "github.com/Prakhar-Agarwal-byte/moby/api/types" 13 "github.com/Prakhar-Agarwal-byte/moby/errdefs" 14 "github.com/Prakhar-Agarwal-byte/moby/integration/internal/container" 15 "github.com/Prakhar-Agarwal-byte/moby/pkg/archive" 16 "github.com/Prakhar-Agarwal-byte/moby/pkg/jsonmessage" 17 "github.com/Prakhar-Agarwal-byte/moby/testutil/fakecontext" 18 "gotest.tools/v3/assert" 19 is "gotest.tools/v3/assert/cmp" 20 "gotest.tools/v3/skip" 21 ) 22 23 func TestCopyFromContainerPathDoesNotExist(t *testing.T) { 24 ctx := setupTest(t) 25 26 apiClient := testEnv.APIClient() 27 cid := container.Create(ctx, t, apiClient) 28 29 _, _, err := apiClient.CopyFromContainer(ctx, cid, "/dne") 30 assert.Check(t, is.ErrorType(err, errdefs.IsNotFound)) 31 assert.Check(t, is.ErrorContains(err, "Could not find the file /dne in container "+cid)) 32 } 33 34 func TestCopyFromContainerPathIsNotDir(t *testing.T) { 35 ctx := setupTest(t) 36 37 apiClient := testEnv.APIClient() 38 cid := container.Create(ctx, t, apiClient) 39 40 path := "/etc/passwd/" 41 expected := "not a directory" 42 if testEnv.DaemonInfo.OSType == "windows" { 43 path = "c:/windows/system32/drivers/etc/hosts/" 44 expected = "The filename, directory name, or volume label syntax is incorrect." 45 } 46 _, _, err := apiClient.CopyFromContainer(ctx, cid, path) 47 assert.Assert(t, is.ErrorContains(err, expected)) 48 } 49 50 func TestCopyToContainerPathDoesNotExist(t *testing.T) { 51 ctx := setupTest(t) 52 53 apiClient := testEnv.APIClient() 54 cid := container.Create(ctx, t, apiClient) 55 56 err := apiClient.CopyToContainer(ctx, cid, "/dne", nil, types.CopyToContainerOptions{}) 57 assert.Check(t, is.ErrorType(err, errdefs.IsNotFound)) 58 assert.Check(t, is.ErrorContains(err, "Could not find the file /dne in container "+cid)) 59 } 60 61 func TestCopyEmptyFile(t *testing.T) { 62 ctx := setupTest(t) 63 64 apiClient := testEnv.APIClient() 65 cid := container.Create(ctx, t, apiClient) 66 67 // empty content 68 dstDir, _ := makeEmptyArchive(t) 69 err := apiClient.CopyToContainer(ctx, cid, dstDir, bytes.NewReader([]byte("")), types.CopyToContainerOptions{}) 70 assert.NilError(t, err) 71 72 // tar with empty file 73 dstDir, preparedArchive := makeEmptyArchive(t) 74 err = apiClient.CopyToContainer(ctx, cid, dstDir, preparedArchive, types.CopyToContainerOptions{}) 75 assert.NilError(t, err) 76 77 // tar with empty file archive mode 78 dstDir, preparedArchive = makeEmptyArchive(t) 79 err = apiClient.CopyToContainer(ctx, cid, dstDir, preparedArchive, types.CopyToContainerOptions{ 80 CopyUIDGID: true, 81 }) 82 assert.NilError(t, err) 83 84 // copy from empty file 85 rdr, _, err := apiClient.CopyFromContainer(ctx, cid, dstDir) 86 assert.NilError(t, err) 87 defer rdr.Close() 88 } 89 90 func makeEmptyArchive(t *testing.T) (string, io.ReadCloser) { 91 tmpDir := t.TempDir() 92 srcPath := filepath.Join(tmpDir, "empty-file.txt") 93 err := os.WriteFile(srcPath, []byte(""), 0o400) 94 assert.NilError(t, err) 95 96 // TODO(thaJeztah) Add utilities to the client to make steps below less complicated. 97 // Code below is taken from copyToContainer() in docker/cli. 98 srcInfo, err := archive.CopyInfoSourcePath(srcPath, false) 99 assert.NilError(t, err) 100 101 srcArchive, err := archive.TarResource(srcInfo) 102 assert.NilError(t, err) 103 t.Cleanup(func() { 104 srcArchive.Close() 105 }) 106 107 ctrPath := "/empty-file.txt" 108 dstInfo := archive.CopyInfo{Path: ctrPath} 109 dstDir, preparedArchive, err := archive.PrepareArchiveCopy(srcArchive, srcInfo, dstInfo) 110 assert.NilError(t, err) 111 t.Cleanup(func() { 112 preparedArchive.Close() 113 }) 114 return dstDir, preparedArchive 115 } 116 117 func TestCopyToContainerPathIsNotDir(t *testing.T) { 118 ctx := setupTest(t) 119 120 apiClient := testEnv.APIClient() 121 cid := container.Create(ctx, t, apiClient) 122 123 path := "/etc/passwd/" 124 if testEnv.DaemonInfo.OSType == "windows" { 125 path = "c:/windows/system32/drivers/etc/hosts/" 126 } 127 err := apiClient.CopyToContainer(ctx, cid, path, nil, types.CopyToContainerOptions{}) 128 assert.Check(t, is.ErrorContains(err, "not a directory")) 129 } 130 131 func TestCopyFromContainer(t *testing.T) { 132 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 133 ctx := setupTest(t) 134 135 apiClient := testEnv.APIClient() 136 137 dir, err := os.MkdirTemp("", t.Name()) 138 assert.NilError(t, err) 139 defer os.RemoveAll(dir) 140 141 buildCtx := fakecontext.New(t, dir, fakecontext.WithFile("foo", "hello"), fakecontext.WithFile("baz", "world"), fakecontext.WithDockerfile(` 142 FROM busybox 143 COPY foo /foo 144 COPY baz /bar/quux/baz 145 RUN ln -s notexist /bar/notarget && ln -s quux/baz /bar/filesymlink && ln -s quux /bar/dirsymlink && ln -s / /bar/root 146 CMD /fake 147 `)) 148 defer buildCtx.Close() 149 150 resp, err := apiClient.ImageBuild(ctx, buildCtx.AsTarReader(t), types.ImageBuildOptions{}) 151 assert.NilError(t, err) 152 defer resp.Body.Close() 153 154 var imageID string 155 err = jsonmessage.DisplayJSONMessagesStream(resp.Body, io.Discard, 0, false, func(msg jsonmessage.JSONMessage) { 156 var r types.BuildResult 157 assert.NilError(t, json.Unmarshal(*msg.Aux, &r)) 158 imageID = r.ID 159 }) 160 assert.NilError(t, err) 161 assert.Assert(t, imageID != "") 162 163 cid := container.Create(ctx, t, apiClient, container.WithImage(imageID)) 164 165 for _, x := range []struct { 166 src string 167 expect map[string]string 168 }{ 169 {"/", map[string]string{"/": "", "/foo": "hello", "/bar/quux/baz": "world", "/bar/filesymlink": "", "/bar/dirsymlink": "", "/bar/notarget": ""}}, 170 {".", map[string]string{"./": "", "./foo": "hello", "./bar/quux/baz": "world", "./bar/filesymlink": "", "./bar/dirsymlink": "", "./bar/notarget": ""}}, 171 {"/.", map[string]string{"./": "", "./foo": "hello", "./bar/quux/baz": "world", "./bar/filesymlink": "", "./bar/dirsymlink": "", "./bar/notarget": ""}}, 172 {"./", map[string]string{"./": "", "./foo": "hello", "./bar/quux/baz": "world", "./bar/filesymlink": "", "./bar/dirsymlink": "", "./bar/notarget": ""}}, 173 {"/./", map[string]string{"./": "", "./foo": "hello", "./bar/quux/baz": "world", "./bar/filesymlink": "", "./bar/dirsymlink": "", "./bar/notarget": ""}}, 174 {"/bar/root", map[string]string{"root": ""}}, 175 {"/bar/root/", map[string]string{"root/": "", "root/foo": "hello", "root/bar/quux/baz": "world", "root/bar/filesymlink": "", "root/bar/dirsymlink": "", "root/bar/notarget": ""}}, 176 {"/bar/root/.", map[string]string{"./": "", "./foo": "hello", "./bar/quux/baz": "world", "./bar/filesymlink": "", "./bar/dirsymlink": "", "./bar/notarget": ""}}, 177 178 {"bar/quux", map[string]string{"quux/": "", "quux/baz": "world"}}, 179 {"bar/quux/", map[string]string{"quux/": "", "quux/baz": "world"}}, 180 {"bar/quux/.", map[string]string{"./": "", "./baz": "world"}}, 181 {"bar/quux/baz", map[string]string{"baz": "world"}}, 182 183 {"bar/filesymlink", map[string]string{"filesymlink": ""}}, 184 {"bar/dirsymlink", map[string]string{"dirsymlink": ""}}, 185 {"bar/dirsymlink/", map[string]string{"dirsymlink/": "", "dirsymlink/baz": "world"}}, 186 {"bar/dirsymlink/.", map[string]string{"./": "", "./baz": "world"}}, 187 {"bar/notarget", map[string]string{"notarget": ""}}, 188 } { 189 t.Run(x.src, func(t *testing.T) { 190 rdr, _, err := apiClient.CopyFromContainer(ctx, cid, x.src) 191 assert.NilError(t, err) 192 defer rdr.Close() 193 194 found := make(map[string]bool, len(x.expect)) 195 var numFound int 196 tr := tar.NewReader(rdr) 197 for numFound < len(x.expect) { 198 h, err := tr.Next() 199 if err == io.EOF { 200 break 201 } 202 assert.NilError(t, err) 203 204 expected, exists := x.expect[h.Name] 205 if !exists { 206 // this archive will have extra stuff in it since we are copying from root 207 // and docker adds a bunch of stuff 208 continue 209 } 210 211 numFound++ 212 found[h.Name] = true 213 214 buf, err := io.ReadAll(tr) 215 if err == nil { 216 assert.Check(t, is.Equal(string(buf), expected)) 217 } 218 } 219 220 for f := range x.expect { 221 assert.Check(t, found[f], f+" not found in archive") 222 } 223 }) 224 } 225 }