github.com/justincormack/cli@v0.0.0-20201215022714-831ebeae9675/cli/command/container/list_test.go (about)

     1  package container
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"testing"
     7  
     8  	"github.com/docker/cli/cli/config/configfile"
     9  	"github.com/docker/cli/internal/test"
    10  	. "github.com/docker/cli/internal/test/builders" // Import builders to get the builder function as package function
    11  	"github.com/docker/cli/opts"
    12  	"github.com/docker/docker/api/types"
    13  	"gotest.tools/v3/assert"
    14  	is "gotest.tools/v3/assert/cmp"
    15  	"gotest.tools/v3/golden"
    16  )
    17  
    18  func TestContainerListBuildContainerListOptions(t *testing.T) {
    19  	filters := opts.NewFilterOpt()
    20  	assert.NilError(t, filters.Set("foo=bar"))
    21  	assert.NilError(t, filters.Set("baz=foo"))
    22  
    23  	contexts := []struct {
    24  		psOpts          *psOptions
    25  		expectedAll     bool
    26  		expectedSize    bool
    27  		expectedLimit   int
    28  		expectedFilters map[string]string
    29  	}{
    30  		{
    31  			psOpts: &psOptions{
    32  				all:    true,
    33  				size:   true,
    34  				last:   5,
    35  				filter: filters,
    36  			},
    37  			expectedAll:   true,
    38  			expectedSize:  true,
    39  			expectedLimit: 5,
    40  			expectedFilters: map[string]string{
    41  				"foo": "bar",
    42  				"baz": "foo",
    43  			},
    44  		},
    45  		{
    46  			psOpts: &psOptions{
    47  				all:     true,
    48  				size:    true,
    49  				last:    -1,
    50  				nLatest: true,
    51  			},
    52  			expectedAll:     true,
    53  			expectedSize:    true,
    54  			expectedLimit:   1,
    55  			expectedFilters: make(map[string]string),
    56  		},
    57  		{
    58  			psOpts: &psOptions{
    59  				all:    true,
    60  				size:   false,
    61  				last:   5,
    62  				filter: filters,
    63  				// With .Size, size should be true
    64  				format: "{{.Size}}",
    65  			},
    66  			expectedAll:   true,
    67  			expectedSize:  true,
    68  			expectedLimit: 5,
    69  			expectedFilters: map[string]string{
    70  				"foo": "bar",
    71  				"baz": "foo",
    72  			},
    73  		},
    74  		{
    75  			psOpts: &psOptions{
    76  				all:    true,
    77  				size:   false,
    78  				last:   5,
    79  				filter: filters,
    80  				// With .Size, size should be true
    81  				format: "{{.Size}} {{.CreatedAt}} {{upper .Networks}}",
    82  			},
    83  			expectedAll:   true,
    84  			expectedSize:  true,
    85  			expectedLimit: 5,
    86  			expectedFilters: map[string]string{
    87  				"foo": "bar",
    88  				"baz": "foo",
    89  			},
    90  		},
    91  		{
    92  			psOpts: &psOptions{
    93  				all:    true,
    94  				size:   false,
    95  				last:   5,
    96  				filter: filters,
    97  				// Without .Size, size should be false
    98  				format: "{{.CreatedAt}} {{.Networks}}",
    99  			},
   100  			expectedAll:   true,
   101  			expectedSize:  false,
   102  			expectedLimit: 5,
   103  			expectedFilters: map[string]string{
   104  				"foo": "bar",
   105  				"baz": "foo",
   106  			},
   107  		},
   108  	}
   109  
   110  	for _, c := range contexts {
   111  		options, err := buildContainerListOptions(c.psOpts)
   112  		assert.NilError(t, err)
   113  
   114  		assert.Check(t, is.Equal(c.expectedAll, options.All))
   115  		assert.Check(t, is.Equal(c.expectedSize, options.Size))
   116  		assert.Check(t, is.Equal(c.expectedLimit, options.Limit))
   117  		assert.Check(t, is.Equal(len(c.expectedFilters), options.Filters.Len()))
   118  
   119  		for k, v := range c.expectedFilters {
   120  			f := options.Filters
   121  			if !f.ExactMatch(k, v) {
   122  				t.Fatalf("Expected filter with key %s to be %s but got %s", k, v, f.Get(k))
   123  			}
   124  		}
   125  	}
   126  }
   127  
   128  func TestContainerListErrors(t *testing.T) {
   129  	testCases := []struct {
   130  		args              []string
   131  		flags             map[string]string
   132  		containerListFunc func(types.ContainerListOptions) ([]types.Container, error)
   133  		expectedError     string
   134  	}{
   135  		{
   136  			flags: map[string]string{
   137  				"format": "{{invalid}}",
   138  			},
   139  			expectedError: `function "invalid" not defined`,
   140  		},
   141  		{
   142  			flags: map[string]string{
   143  				"format": "{{join}}",
   144  			},
   145  			expectedError: `wrong number of args for join`,
   146  		},
   147  		{
   148  			containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
   149  				return nil, fmt.Errorf("error listing containers")
   150  			},
   151  			expectedError: "error listing containers",
   152  		},
   153  	}
   154  	for _, tc := range testCases {
   155  		cmd := newListCommand(
   156  			test.NewFakeCli(&fakeClient{
   157  				containerListFunc: tc.containerListFunc,
   158  			}),
   159  		)
   160  		cmd.SetArgs(tc.args)
   161  		for key, value := range tc.flags {
   162  			cmd.Flags().Set(key, value)
   163  		}
   164  		cmd.SetOut(ioutil.Discard)
   165  		assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
   166  	}
   167  }
   168  
   169  func TestContainerListWithoutFormat(t *testing.T) {
   170  	cli := test.NewFakeCli(&fakeClient{
   171  		containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
   172  			return []types.Container{
   173  				*Container("c1"),
   174  				*Container("c2", WithName("foo")),
   175  				*Container("c3", WithPort(80, 80, TCP), WithPort(81, 81, TCP), WithPort(82, 82, TCP)),
   176  				*Container("c4", WithPort(81, 81, UDP)),
   177  				*Container("c5", WithPort(82, 82, IP("8.8.8.8"), TCP)),
   178  			}, nil
   179  		},
   180  	})
   181  	cmd := newListCommand(cli)
   182  	assert.NilError(t, cmd.Execute())
   183  	golden.Assert(t, cli.OutBuffer().String(), "container-list-without-format.golden")
   184  }
   185  
   186  func TestContainerListNoTrunc(t *testing.T) {
   187  	cli := test.NewFakeCli(&fakeClient{
   188  		containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
   189  			return []types.Container{
   190  				*Container("c1"),
   191  				*Container("c2", WithName("foo/bar")),
   192  			}, nil
   193  		},
   194  	})
   195  	cmd := newListCommand(cli)
   196  	cmd.Flags().Set("no-trunc", "true")
   197  	assert.NilError(t, cmd.Execute())
   198  	golden.Assert(t, cli.OutBuffer().String(), "container-list-without-format-no-trunc.golden")
   199  }
   200  
   201  // Test for GitHub issue docker/docker#21772
   202  func TestContainerListNamesMultipleTime(t *testing.T) {
   203  	cli := test.NewFakeCli(&fakeClient{
   204  		containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
   205  			return []types.Container{
   206  				*Container("c1"),
   207  				*Container("c2", WithName("foo/bar")),
   208  			}, nil
   209  		},
   210  	})
   211  	cmd := newListCommand(cli)
   212  	cmd.Flags().Set("format", "{{.Names}} {{.Names}}")
   213  	assert.NilError(t, cmd.Execute())
   214  	golden.Assert(t, cli.OutBuffer().String(), "container-list-format-name-name.golden")
   215  }
   216  
   217  // Test for GitHub issue docker/docker#30291
   218  func TestContainerListFormatTemplateWithArg(t *testing.T) {
   219  	cli := test.NewFakeCli(&fakeClient{
   220  		containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
   221  			return []types.Container{
   222  				*Container("c1", WithLabel("some.label", "value")),
   223  				*Container("c2", WithName("foo/bar"), WithLabel("foo", "bar")),
   224  			}, nil
   225  		},
   226  	})
   227  	cmd := newListCommand(cli)
   228  	cmd.Flags().Set("format", `{{.Names}} {{.Label "some.label"}}`)
   229  	assert.NilError(t, cmd.Execute())
   230  	golden.Assert(t, cli.OutBuffer().String(), "container-list-format-with-arg.golden")
   231  }
   232  
   233  func TestContainerListFormatSizeSetsOption(t *testing.T) {
   234  	cli := test.NewFakeCli(&fakeClient{
   235  		containerListFunc: func(options types.ContainerListOptions) ([]types.Container, error) {
   236  			assert.Check(t, options.Size)
   237  			return []types.Container{}, nil
   238  		},
   239  	})
   240  	cmd := newListCommand(cli)
   241  	cmd.Flags().Set("format", `{{.Size}}`)
   242  	assert.NilError(t, cmd.Execute())
   243  }
   244  
   245  func TestContainerListWithConfigFormat(t *testing.T) {
   246  	cli := test.NewFakeCli(&fakeClient{
   247  		containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
   248  			return []types.Container{
   249  				*Container("c1", WithLabel("some.label", "value")),
   250  				*Container("c2", WithName("foo/bar"), WithLabel("foo", "bar")),
   251  			}, nil
   252  		},
   253  	})
   254  	cli.SetConfigFile(&configfile.ConfigFile{
   255  		PsFormat: "{{ .Names }} {{ .Image }} {{ .Labels }}",
   256  	})
   257  	cmd := newListCommand(cli)
   258  	assert.NilError(t, cmd.Execute())
   259  	golden.Assert(t, cli.OutBuffer().String(), "container-list-with-config-format.golden")
   260  }
   261  
   262  func TestContainerListWithFormat(t *testing.T) {
   263  	cli := test.NewFakeCli(&fakeClient{
   264  		containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
   265  			return []types.Container{
   266  				*Container("c1", WithLabel("some.label", "value")),
   267  				*Container("c2", WithName("foo/bar"), WithLabel("foo", "bar")),
   268  			}, nil
   269  		},
   270  	})
   271  	cmd := newListCommand(cli)
   272  	cmd.Flags().Set("format", "{{ .Names }} {{ .Image }} {{ .Labels }}")
   273  	assert.NilError(t, cmd.Execute())
   274  	golden.Assert(t, cli.OutBuffer().String(), "container-list-with-format.golden")
   275  }