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