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  }