github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cmd/docker/builder_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "context" 6 "os" 7 "path/filepath" 8 "testing" 9 10 "github.com/docker/cli/cli/command" 11 "github.com/docker/cli/cli/context/store" 12 "github.com/docker/cli/cli/flags" 13 "github.com/docker/cli/internal/test/output" 14 "github.com/docker/docker/api/types" 15 "github.com/docker/docker/client" 16 "gotest.tools/v3/assert" 17 "gotest.tools/v3/fs" 18 ) 19 20 var pluginFilename = "docker-buildx" 21 22 func TestBuildWithBuilder(t *testing.T) { 23 testcases := []struct { 24 name string 25 context string 26 builder string 27 alias bool 28 expectedEnvs []string 29 }{ 30 { 31 name: "default", 32 context: "default", 33 alias: false, 34 expectedEnvs: []string{"BUILDX_BUILDER=default"}, 35 }, 36 { 37 name: "custom context", 38 context: "foo", 39 alias: false, 40 expectedEnvs: []string{"BUILDX_BUILDER=foo"}, 41 }, 42 { 43 name: "custom builder name", 44 builder: "mybuilder", 45 alias: false, 46 expectedEnvs: nil, 47 }, 48 { 49 name: "buildx install", 50 alias: true, 51 expectedEnvs: nil, 52 }, 53 } 54 55 dir := fs.NewDir(t, t.Name(), 56 fs.WithFile(pluginFilename, `#!/bin/sh 57 echo '{"SchemaVersion":"0.1.0","Vendor":"Docker Inc.","Version":"v0.6.3","ShortDescription":"Build with BuildKit"}'`, fs.WithMode(0o777)), 58 ) 59 defer dir.Remove() 60 61 for _, tt := range testcases { 62 tt := tt 63 t.Run(tt.name, func(t *testing.T) { 64 if tt.builder != "" { 65 t.Setenv("BUILDX_BUILDER", tt.builder) 66 } 67 68 var b bytes.Buffer 69 dockerCli, err := command.NewDockerCli( 70 command.WithAPIClient(&fakeClient{}), 71 command.WithInputStream(discard), 72 command.WithCombinedStreams(&b), 73 ) 74 assert.NilError(t, err) 75 assert.NilError(t, dockerCli.Initialize(flags.NewClientOptions())) 76 77 if tt.context != "" { 78 if tt.context != command.DefaultContextName { 79 assert.NilError(t, dockerCli.ContextStore().CreateOrUpdate(store.Metadata{ 80 Name: tt.context, 81 Endpoints: map[string]interface{}{ 82 "docker": map[string]interface{}{ 83 "host": "unix://" + filepath.Join(t.TempDir(), "docker.sock"), 84 }, 85 }, 86 })) 87 } 88 opts := flags.NewClientOptions() 89 opts.Context = tt.context 90 assert.NilError(t, dockerCli.Initialize(opts)) 91 } 92 93 dockerCli.ConfigFile().CLIPluginsExtraDirs = []string{dir.Path()} 94 if tt.alias { 95 dockerCli.ConfigFile().Aliases = map[string]string{"builder": "buildx"} 96 } 97 98 tcmd := newDockerCommand(dockerCli) 99 tcmd.SetArgs([]string{"build", "."}) 100 101 cmd, args, err := tcmd.HandleGlobalFlags() 102 assert.NilError(t, err) 103 104 var envs []string 105 args, os.Args, envs, err = processBuilder(dockerCli, cmd, args, os.Args) 106 assert.NilError(t, err) 107 assert.DeepEqual(t, []string{builderDefaultPlugin, "build", "."}, args) 108 if tt.expectedEnvs != nil { 109 assert.DeepEqual(t, tt.expectedEnvs, envs) 110 } else { 111 assert.Check(t, len(envs) == 0) 112 } 113 }) 114 } 115 } 116 117 type fakeClient struct { 118 client.Client 119 } 120 121 func (c *fakeClient) Ping(_ context.Context) (types.Ping, error) { 122 return types.Ping{OSType: "linux"}, nil 123 } 124 125 func TestBuildkitDisabled(t *testing.T) { 126 t.Setenv("DOCKER_BUILDKIT", "0") 127 128 dir := fs.NewDir(t, t.Name(), 129 fs.WithFile(pluginFilename, `#!/bin/sh exit 1`, fs.WithMode(0o777)), 130 ) 131 defer dir.Remove() 132 133 b := bytes.NewBuffer(nil) 134 135 dockerCli, err := command.NewDockerCli( 136 command.WithAPIClient(&fakeClient{}), 137 command.WithInputStream(discard), 138 command.WithCombinedStreams(b), 139 ) 140 assert.NilError(t, err) 141 assert.NilError(t, dockerCli.Initialize(flags.NewClientOptions())) 142 dockerCli.ConfigFile().CLIPluginsExtraDirs = []string{dir.Path()} 143 144 tcmd := newDockerCommand(dockerCli) 145 tcmd.SetArgs([]string{"build", "."}) 146 147 cmd, args, err := tcmd.HandleGlobalFlags() 148 assert.NilError(t, err) 149 150 var envs []string 151 args, os.Args, envs, err = processBuilder(dockerCli, cmd, args, os.Args) 152 assert.NilError(t, err) 153 assert.DeepEqual(t, []string{"build", "."}, args) 154 assert.Check(t, len(envs) == 0) 155 156 output.Assert(t, b.String(), map[int]func(string) error{ 157 0: output.Suffix("DEPRECATED: The legacy builder is deprecated and will be removed in a future release."), 158 1: output.Suffix("BuildKit is currently disabled; enable it by removing the DOCKER_BUILDKIT=0"), 159 }) 160 } 161 162 func TestBuilderBroken(t *testing.T) { 163 dir := fs.NewDir(t, t.Name(), 164 fs.WithFile(pluginFilename, `#!/bin/sh exit 1`, fs.WithMode(0o777)), 165 ) 166 defer dir.Remove() 167 168 b := bytes.NewBuffer(nil) 169 170 dockerCli, err := command.NewDockerCli( 171 command.WithAPIClient(&fakeClient{}), 172 command.WithInputStream(discard), 173 command.WithCombinedStreams(b), 174 ) 175 assert.NilError(t, err) 176 assert.NilError(t, dockerCli.Initialize(flags.NewClientOptions())) 177 dockerCli.ConfigFile().CLIPluginsExtraDirs = []string{dir.Path()} 178 179 tcmd := newDockerCommand(dockerCli) 180 tcmd.SetArgs([]string{"build", "."}) 181 182 cmd, args, err := tcmd.HandleGlobalFlags() 183 assert.NilError(t, err) 184 185 var envs []string 186 args, os.Args, envs, err = processBuilder(dockerCli, cmd, args, os.Args) 187 assert.NilError(t, err) 188 assert.DeepEqual(t, []string{"build", "."}, args) 189 assert.Check(t, len(envs) == 0) 190 191 output.Assert(t, b.String(), map[int]func(string) error{ 192 0: output.Prefix("failed to fetch metadata:"), 193 2: output.Suffix("DEPRECATED: The legacy builder is deprecated and will be removed in a future release."), 194 }) 195 } 196 197 func TestBuilderBrokenEnforced(t *testing.T) { 198 t.Setenv("DOCKER_BUILDKIT", "1") 199 200 dir := fs.NewDir(t, t.Name(), 201 fs.WithFile(pluginFilename, `#!/bin/sh exit 1`, fs.WithMode(0o777)), 202 ) 203 defer dir.Remove() 204 205 b := bytes.NewBuffer(nil) 206 207 dockerCli, err := command.NewDockerCli( 208 command.WithAPIClient(&fakeClient{}), 209 command.WithInputStream(discard), 210 command.WithCombinedStreams(b), 211 ) 212 assert.NilError(t, err) 213 assert.NilError(t, dockerCli.Initialize(flags.NewClientOptions())) 214 dockerCli.ConfigFile().CLIPluginsExtraDirs = []string{dir.Path()} 215 216 tcmd := newDockerCommand(dockerCli) 217 tcmd.SetArgs([]string{"build", "."}) 218 219 cmd, args, err := tcmd.HandleGlobalFlags() 220 assert.NilError(t, err) 221 222 var envs []string 223 args, os.Args, envs, err = processBuilder(dockerCli, cmd, args, os.Args) 224 assert.DeepEqual(t, []string{"build", "."}, args) 225 assert.Check(t, len(envs) == 0) 226 227 output.Assert(t, err.Error(), map[int]func(string) error{ 228 0: output.Prefix("failed to fetch metadata:"), 229 2: output.Suffix("ERROR: BuildKit is enabled but the buildx component is missing or broken."), 230 }) 231 } 232 233 func TestHasBuilderName(t *testing.T) { 234 cases := []struct { 235 name string 236 args []string 237 envs []string 238 expected bool 239 }{ 240 { 241 name: "no args", 242 args: []string{"docker", "build", "."}, 243 envs: []string{"FOO=bar"}, 244 expected: false, 245 }, 246 { 247 name: "env var", 248 args: []string{"docker", "build", "."}, 249 envs: []string{"BUILDX_BUILDER=foo"}, 250 expected: true, 251 }, 252 { 253 name: "empty env var", 254 args: []string{"docker", "build", "."}, 255 envs: []string{"BUILDX_BUILDER="}, 256 expected: false, 257 }, 258 { 259 name: "flag", 260 args: []string{"docker", "build", "--builder", "foo", "."}, 261 envs: []string{"FOO=bar"}, 262 expected: true, 263 }, 264 { 265 name: "both", 266 args: []string{"docker", "build", "--builder", "foo", "."}, 267 envs: []string{"BUILDX_BUILDER=foo"}, 268 expected: true, 269 }, 270 } 271 for _, tt := range cases { 272 tt := tt 273 t.Run(tt.name, func(t *testing.T) { 274 assert.Equal(t, tt.expected, hasBuilderName(tt.args, tt.envs)) 275 }) 276 } 277 }