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 }