github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/builder/dockerfile/internals_test.go (about) 1 package dockerfile // import "github.com/docker/docker/builder/dockerfile" 2 3 import ( 4 "fmt" 5 "os" 6 "runtime" 7 "testing" 8 9 "github.com/docker/docker/api/types" 10 "github.com/docker/docker/api/types/backend" 11 "github.com/docker/docker/api/types/container" 12 "github.com/docker/docker/builder" 13 "github.com/docker/docker/builder/remotecontext" 14 "github.com/docker/docker/pkg/archive" 15 "github.com/docker/go-connections/nat" 16 "gotest.tools/assert" 17 is "gotest.tools/assert/cmp" 18 "gotest.tools/skip" 19 ) 20 21 func TestEmptyDockerfile(t *testing.T) { 22 contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") 23 defer cleanup() 24 25 createTestTempFile(t, contextDir, builder.DefaultDockerfileName, "", 0777) 26 27 readAndCheckDockerfile(t, "emptyDockerfile", contextDir, "", "the Dockerfile (Dockerfile) cannot be empty") 28 } 29 30 func TestSymlinkDockerfile(t *testing.T) { 31 contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") 32 defer cleanup() 33 34 createTestSymlink(t, contextDir, builder.DefaultDockerfileName, "/etc/passwd") 35 36 // The reason the error is "Cannot locate specified Dockerfile" is because 37 // in the builder, the symlink is resolved within the context, therefore 38 // Dockerfile -> /etc/passwd becomes etc/passwd from the context which is 39 // a nonexistent file. 40 expectedError := fmt.Sprintf("Cannot locate specified Dockerfile: %s", builder.DefaultDockerfileName) 41 42 readAndCheckDockerfile(t, "symlinkDockerfile", contextDir, builder.DefaultDockerfileName, expectedError) 43 } 44 45 func TestDockerfileOutsideTheBuildContext(t *testing.T) { 46 contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") 47 defer cleanup() 48 49 expectedError := "Forbidden path outside the build context: ../../Dockerfile ()" 50 51 readAndCheckDockerfile(t, "DockerfileOutsideTheBuildContext", contextDir, "../../Dockerfile", expectedError) 52 } 53 54 func TestNonExistingDockerfile(t *testing.T) { 55 contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") 56 defer cleanup() 57 58 expectedError := "Cannot locate specified Dockerfile: Dockerfile" 59 60 readAndCheckDockerfile(t, "NonExistingDockerfile", contextDir, "Dockerfile", expectedError) 61 } 62 63 func readAndCheckDockerfile(t *testing.T, testName, contextDir, dockerfilePath, expectedError string) { 64 skip.If(t, os.Getuid() != 0, "skipping test that requires root") 65 tarStream, err := archive.Tar(contextDir, archive.Uncompressed) 66 assert.NilError(t, err) 67 68 defer func() { 69 if err = tarStream.Close(); err != nil { 70 t.Fatalf("Error when closing tar stream: %s", err) 71 } 72 }() 73 74 if dockerfilePath == "" { // handled in BuildWithContext 75 dockerfilePath = builder.DefaultDockerfileName 76 } 77 78 config := backend.BuildConfig{ 79 Options: &types.ImageBuildOptions{Dockerfile: dockerfilePath}, 80 Source: tarStream, 81 } 82 _, _, err = remotecontext.Detect(config) 83 assert.Check(t, is.Error(err, expectedError)) 84 } 85 86 func TestCopyRunConfig(t *testing.T) { 87 defaultEnv := []string{"foo=1"} 88 defaultCmd := []string{"old"} 89 90 var testcases = []struct { 91 doc string 92 modifiers []runConfigModifier 93 expected *container.Config 94 }{ 95 { 96 doc: "Set the command", 97 modifiers: []runConfigModifier{withCmd([]string{"new"})}, 98 expected: &container.Config{ 99 Cmd: []string{"new"}, 100 Env: defaultEnv, 101 }, 102 }, 103 { 104 doc: "Set the command to a comment", 105 modifiers: []runConfigModifier{withCmdComment("comment", runtime.GOOS)}, 106 expected: &container.Config{ 107 Cmd: append(defaultShellForOS(runtime.GOOS), "#(nop) ", "comment"), 108 Env: defaultEnv, 109 }, 110 }, 111 { 112 doc: "Set the command and env", 113 modifiers: []runConfigModifier{ 114 withCmd([]string{"new"}), 115 withEnv([]string{"one", "two"}), 116 }, 117 expected: &container.Config{ 118 Cmd: []string{"new"}, 119 Env: []string{"one", "two"}, 120 }, 121 }, 122 } 123 124 for _, testcase := range testcases { 125 runConfig := &container.Config{ 126 Cmd: defaultCmd, 127 Env: defaultEnv, 128 } 129 runConfigCopy := copyRunConfig(runConfig, testcase.modifiers...) 130 assert.Check(t, is.DeepEqual(testcase.expected, runConfigCopy), testcase.doc) 131 // Assert the original was not modified 132 assert.Check(t, runConfig != runConfigCopy, testcase.doc) 133 } 134 135 } 136 137 func fullMutableRunConfig() *container.Config { 138 return &container.Config{ 139 Cmd: []string{"command", "arg1"}, 140 Env: []string{"env1=foo", "env2=bar"}, 141 ExposedPorts: nat.PortSet{ 142 "1000/tcp": {}, 143 "1001/tcp": {}, 144 }, 145 Volumes: map[string]struct{}{ 146 "one": {}, 147 "two": {}, 148 }, 149 Entrypoint: []string{"entry", "arg1"}, 150 OnBuild: []string{"first", "next"}, 151 Labels: map[string]string{ 152 "label1": "value1", 153 "label2": "value2", 154 }, 155 Shell: []string{"shell", "-c"}, 156 } 157 } 158 159 func TestDeepCopyRunConfig(t *testing.T) { 160 runConfig := fullMutableRunConfig() 161 copy := copyRunConfig(runConfig) 162 assert.Check(t, is.DeepEqual(fullMutableRunConfig(), copy)) 163 164 copy.Cmd[1] = "arg2" 165 copy.Env[1] = "env2=new" 166 copy.ExposedPorts["10002"] = struct{}{} 167 copy.Volumes["three"] = struct{}{} 168 copy.Entrypoint[1] = "arg2" 169 copy.OnBuild[0] = "start" 170 copy.Labels["label3"] = "value3" 171 copy.Shell[0] = "sh" 172 assert.Check(t, is.DeepEqual(fullMutableRunConfig(), runConfig)) 173 }