gopkg.in/docker/docker.v20@v20.10.27/integration-cli/docker_cli_images_test.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "reflect" 8 "sort" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/docker/docker/integration-cli/cli/build" 14 "github.com/docker/docker/pkg/stringid" 15 "gotest.tools/v3/assert" 16 is "gotest.tools/v3/assert/cmp" 17 "gotest.tools/v3/icmd" 18 ) 19 20 func (s *DockerSuite) TestImagesEnsureImageIsListed(c *testing.T) { 21 imagesOut, _ := dockerCmd(c, "images") 22 assert.Assert(c, strings.Contains(imagesOut, "busybox")) 23 } 24 25 func (s *DockerSuite) TestImagesEnsureImageWithTagIsListed(c *testing.T) { 26 name := "imagewithtag" 27 dockerCmd(c, "tag", "busybox", name+":v1") 28 dockerCmd(c, "tag", "busybox", name+":v1v1") 29 dockerCmd(c, "tag", "busybox", name+":v2") 30 31 imagesOut, _ := dockerCmd(c, "images", name+":v1") 32 assert.Assert(c, strings.Contains(imagesOut, name)) 33 assert.Assert(c, strings.Contains(imagesOut, "v1")) 34 assert.Assert(c, !strings.Contains(imagesOut, "v2")) 35 assert.Assert(c, !strings.Contains(imagesOut, "v1v1")) 36 imagesOut, _ = dockerCmd(c, "images", name) 37 assert.Assert(c, strings.Contains(imagesOut, name)) 38 assert.Assert(c, strings.Contains(imagesOut, "v1")) 39 assert.Assert(c, strings.Contains(imagesOut, "v1v1")) 40 assert.Assert(c, strings.Contains(imagesOut, "v2")) 41 } 42 43 func (s *DockerSuite) TestImagesEnsureImageWithBadTagIsNotListed(c *testing.T) { 44 imagesOut, _ := dockerCmd(c, "images", "busybox:nonexistent") 45 assert.Assert(c, !strings.Contains(imagesOut, "busybox")) 46 } 47 48 func (s *DockerSuite) TestImagesOrderedByCreationDate(c *testing.T) { 49 buildImageSuccessfully(c, "order:test_a", build.WithDockerfile(`FROM busybox 50 MAINTAINER dockerio1`)) 51 id1 := getIDByName(c, "order:test_a") 52 time.Sleep(1 * time.Second) 53 buildImageSuccessfully(c, "order:test_c", build.WithDockerfile(`FROM busybox 54 MAINTAINER dockerio2`)) 55 id2 := getIDByName(c, "order:test_c") 56 time.Sleep(1 * time.Second) 57 buildImageSuccessfully(c, "order:test_b", build.WithDockerfile(`FROM busybox 58 MAINTAINER dockerio3`)) 59 id3 := getIDByName(c, "order:test_b") 60 61 out, _ := dockerCmd(c, "images", "-q", "--no-trunc") 62 imgs := strings.Split(out, "\n") 63 assert.Equal(c, imgs[0], id3, fmt.Sprintf("First image must be %s, got %s", id3, imgs[0])) 64 assert.Equal(c, imgs[1], id2, fmt.Sprintf("First image must be %s, got %s", id2, imgs[1])) 65 assert.Equal(c, imgs[2], id1, fmt.Sprintf("First image must be %s, got %s", id1, imgs[2])) 66 } 67 68 func (s *DockerSuite) TestImagesErrorWithInvalidFilterNameTest(c *testing.T) { 69 out, _, err := dockerCmdWithError("images", "-f", "FOO=123") 70 assert.ErrorContains(c, err, "") 71 assert.Assert(c, strings.Contains(out, "Invalid filter")) 72 } 73 74 func (s *DockerSuite) TestImagesFilterLabelMatch(c *testing.T) { 75 imageName1 := "images_filter_test1" 76 imageName2 := "images_filter_test2" 77 imageName3 := "images_filter_test3" 78 buildImageSuccessfully(c, imageName1, build.WithDockerfile(`FROM busybox 79 LABEL match me`)) 80 image1ID := getIDByName(c, imageName1) 81 82 buildImageSuccessfully(c, imageName2, build.WithDockerfile(`FROM busybox 83 LABEL match="me too"`)) 84 image2ID := getIDByName(c, imageName2) 85 86 buildImageSuccessfully(c, imageName3, build.WithDockerfile(`FROM busybox 87 LABEL nomatch me`)) 88 image3ID := getIDByName(c, imageName3) 89 90 out, _ := dockerCmd(c, "images", "--no-trunc", "-q", "-f", "label=match") 91 out = strings.TrimSpace(out) 92 assert.Assert(c, is.Regexp(fmt.Sprintf("^[\\s\\w:]*%s[\\s\\w:]*$", image1ID), out)) 93 94 assert.Assert(c, is.Regexp(fmt.Sprintf("^[\\s\\w:]*%s[\\s\\w:]*$", image2ID), out)) 95 96 assert.Assert(c, !is.Regexp(fmt.Sprintf("^[\\s\\w:]*%s[\\s\\w:]*$", image3ID), out)().Success()) 97 98 out, _ = dockerCmd(c, "images", "--no-trunc", "-q", "-f", "label=match=me too") 99 out = strings.TrimSpace(out) 100 assert.Equal(c, out, image2ID) 101 } 102 103 // Regression : #15659 104 func (s *DockerSuite) TestCommitWithFilterLabel(c *testing.T) { 105 // Create a container 106 dockerCmd(c, "run", "--name", "bar", "busybox", "/bin/sh") 107 // Commit with labels "using changes" 108 out, _ := dockerCmd(c, "commit", "-c", "LABEL foo.version=1.0.0-1", "-c", "LABEL foo.name=bar", "-c", "LABEL foo.author=starlord", "bar", "bar:1.0.0-1") 109 imageID := strings.TrimSpace(out) 110 111 out, _ = dockerCmd(c, "images", "--no-trunc", "-q", "-f", "label=foo.version=1.0.0-1") 112 out = strings.TrimSpace(out) 113 assert.Equal(c, out, imageID) 114 } 115 116 func (s *DockerSuite) TestImagesFilterSinceAndBefore(c *testing.T) { 117 buildImageSuccessfully(c, "image:1", build.WithDockerfile(`FROM `+minimalBaseImage()+` 118 LABEL number=1`)) 119 imageID1 := getIDByName(c, "image:1") 120 buildImageSuccessfully(c, "image:2", build.WithDockerfile(`FROM `+minimalBaseImage()+` 121 LABEL number=2`)) 122 imageID2 := getIDByName(c, "image:2") 123 buildImageSuccessfully(c, "image:3", build.WithDockerfile(`FROM `+minimalBaseImage()+` 124 LABEL number=3`)) 125 imageID3 := getIDByName(c, "image:3") 126 127 expected := []string{imageID3, imageID2} 128 129 out, _ := dockerCmd(c, "images", "-f", "since=image:1", "image") 130 assert.Equal(c, assertImageList(out, expected), true, fmt.Sprintf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out)) 131 132 out, _ = dockerCmd(c, "images", "-f", "since="+imageID1, "image") 133 assert.Equal(c, assertImageList(out, expected), true, fmt.Sprintf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out)) 134 135 expected = []string{imageID3} 136 137 out, _ = dockerCmd(c, "images", "-f", "since=image:2", "image") 138 assert.Equal(c, assertImageList(out, expected), true, fmt.Sprintf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out)) 139 140 out, _ = dockerCmd(c, "images", "-f", "since="+imageID2, "image") 141 assert.Equal(c, assertImageList(out, expected), true, fmt.Sprintf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out)) 142 143 expected = []string{imageID2, imageID1} 144 145 out, _ = dockerCmd(c, "images", "-f", "before=image:3", "image") 146 assert.Equal(c, assertImageList(out, expected), true, fmt.Sprintf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out)) 147 148 out, _ = dockerCmd(c, "images", "-f", "before="+imageID3, "image") 149 assert.Equal(c, assertImageList(out, expected), true, fmt.Sprintf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out)) 150 151 expected = []string{imageID1} 152 153 out, _ = dockerCmd(c, "images", "-f", "before=image:2", "image") 154 assert.Equal(c, assertImageList(out, expected), true, fmt.Sprintf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out)) 155 156 out, _ = dockerCmd(c, "images", "-f", "before="+imageID2, "image") 157 assert.Equal(c, assertImageList(out, expected), true, fmt.Sprintf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out)) 158 } 159 160 func assertImageList(out string, expected []string) bool { 161 lines := strings.Split(strings.Trim(out, "\n "), "\n") 162 163 if len(lines)-1 != len(expected) { 164 return false 165 } 166 167 imageIDIndex := strings.Index(lines[0], "IMAGE ID") 168 for i := 0; i < len(expected); i++ { 169 imageID := lines[i+1][imageIDIndex : imageIDIndex+12] 170 found := false 171 for _, e := range expected { 172 if imageID == e[7:19] { 173 found = true 174 break 175 } 176 } 177 if !found { 178 return false 179 } 180 } 181 182 return true 183 } 184 185 // FIXME(vdemeester) should be a unit test on `docker image ls` 186 func (s *DockerSuite) TestImagesFilterSpaceTrimCase(c *testing.T) { 187 imageName := "images_filter_test" 188 // Build a image and fail to build so that we have dangling images ? 189 buildImage(imageName, build.WithDockerfile(`FROM busybox 190 RUN touch /test/foo 191 RUN touch /test/bar 192 RUN touch /test/baz`)).Assert(c, icmd.Expected{ 193 ExitCode: 1, 194 }) 195 196 filters := []string{ 197 "dangling=true", 198 "Dangling=true", 199 " dangling=true", 200 "dangling=true ", 201 "dangling = true", 202 } 203 204 imageListings := make([][]string, 5) 205 for idx, filter := range filters { 206 out, _ := dockerCmd(c, "images", "-q", "-f", filter) 207 listing := strings.Split(out, "\n") 208 sort.Strings(listing) 209 imageListings[idx] = listing 210 } 211 212 for idx, listing := range imageListings { 213 if idx < 4 && !reflect.DeepEqual(listing, imageListings[idx+1]) { 214 for idx, errListing := range imageListings { 215 fmt.Printf("out %d\n", idx) 216 for _, image := range errListing { 217 fmt.Print(image) 218 } 219 fmt.Print("") 220 } 221 c.Fatalf("All output must be the same") 222 } 223 } 224 } 225 226 func (s *DockerSuite) TestImagesEnsureDanglingImageOnlyListedOnce(c *testing.T) { 227 testRequires(c, DaemonIsLinux) 228 // create container 1 229 out, _ := dockerCmd(c, "run", "-d", "busybox", "true") 230 containerID1 := strings.TrimSpace(out) 231 232 // tag as foobox 233 out, _ = dockerCmd(c, "commit", containerID1, "foobox") 234 imageID := stringid.TruncateID(strings.TrimSpace(out)) 235 236 // overwrite the tag, making the previous image dangling 237 dockerCmd(c, "tag", "busybox", "foobox") 238 239 out, _ = dockerCmd(c, "images", "-q", "-f", "dangling=true") 240 // Expect one dangling image 241 assert.Equal(c, strings.Count(out, imageID), 1) 242 243 out, _ = dockerCmd(c, "images", "-q", "-f", "dangling=false") 244 // dangling=false would not include dangling images 245 assert.Assert(c, !strings.Contains(out, imageID)) 246 out, _ = dockerCmd(c, "images") 247 // docker images still include dangling images 248 assert.Assert(c, strings.Contains(out, imageID)) 249 } 250 251 // FIXME(vdemeester) should be a unit test for `docker image ls` 252 func (s *DockerSuite) TestImagesWithIncorrectFilter(c *testing.T) { 253 out, _, err := dockerCmdWithError("images", "-f", "dangling=invalid") 254 assert.ErrorContains(c, err, "") 255 assert.Assert(c, strings.Contains(out, "Invalid filter")) 256 } 257 258 func (s *DockerSuite) TestImagesEnsureOnlyHeadsImagesShown(c *testing.T) { 259 dockerfile := ` 260 FROM busybox 261 MAINTAINER docker 262 ENV foo bar` 263 name := "scratch-image" 264 result := buildImage(name, build.WithDockerfile(dockerfile)) 265 result.Assert(c, icmd.Success) 266 id := getIDByName(c, name) 267 268 // this is just the output of docker build 269 // we're interested in getting the image id of the MAINTAINER instruction 270 // and that's located at output, line 5, from 7 to end 271 split := strings.Split(result.Combined(), "\n") 272 intermediate := strings.TrimSpace(split[5][7:]) 273 274 out, _ := dockerCmd(c, "images") 275 // images shouldn't show non-heads images 276 assert.Assert(c, !strings.Contains(out, intermediate)) 277 // images should contain final built images 278 assert.Assert(c, strings.Contains(out, stringid.TruncateID(id))) 279 } 280 281 func (s *DockerSuite) TestImagesEnsureImagesFromScratchShown(c *testing.T) { 282 testRequires(c, DaemonIsLinux) // Windows does not support FROM scratch 283 dockerfile := ` 284 FROM scratch 285 MAINTAINER docker` 286 287 name := "scratch-image" 288 buildImageSuccessfully(c, name, build.WithDockerfile(dockerfile)) 289 id := getIDByName(c, name) 290 291 out, _ := dockerCmd(c, "images") 292 // images should contain images built from scratch 293 assert.Assert(c, strings.Contains(out, stringid.TruncateID(id))) 294 } 295 296 // For W2W - equivalent to TestImagesEnsureImagesFromScratchShown but Windows 297 // doesn't support from scratch 298 func (s *DockerSuite) TestImagesEnsureImagesFromBusyboxShown(c *testing.T) { 299 dockerfile := ` 300 FROM busybox 301 MAINTAINER docker` 302 name := "busybox-image" 303 304 buildImageSuccessfully(c, name, build.WithDockerfile(dockerfile)) 305 id := getIDByName(c, name) 306 307 out, _ := dockerCmd(c, "images") 308 // images should contain images built from busybox 309 assert.Assert(c, strings.Contains(out, stringid.TruncateID(id))) 310 } 311 312 // #18181 313 func (s *DockerSuite) TestImagesFilterNameWithPort(c *testing.T) { 314 tag := "a.b.c.d:5000/hello" 315 dockerCmd(c, "tag", "busybox", tag) 316 out, _ := dockerCmd(c, "images", tag) 317 assert.Assert(c, strings.Contains(out, tag)) 318 out, _ = dockerCmd(c, "images", tag+":latest") 319 assert.Assert(c, strings.Contains(out, tag)) 320 out, _ = dockerCmd(c, "images", tag+":no-such-tag") 321 assert.Assert(c, !strings.Contains(out, tag)) 322 } 323 324 func (s *DockerSuite) TestImagesFormat(c *testing.T) { 325 // testRequires(c, DaemonIsLinux) 326 tag := "myimage" 327 dockerCmd(c, "tag", "busybox", tag+":v1") 328 dockerCmd(c, "tag", "busybox", tag+":v2") 329 330 out, _ := dockerCmd(c, "images", "--format", "{{.Repository}}", tag) 331 lines := strings.Split(strings.TrimSpace(out), "\n") 332 333 expected := []string{"myimage", "myimage"} 334 var names []string 335 names = append(names, lines...) 336 assert.Assert(c, is.DeepEqual(names, expected), "Expected array with truncated names: %v, got: %v", expected, names) 337 } 338 339 // ImagesDefaultFormatAndQuiet 340 func (s *DockerSuite) TestImagesFormatDefaultFormat(c *testing.T) { 341 testRequires(c, DaemonIsLinux) 342 343 // create container 1 344 out, _ := dockerCmd(c, "run", "-d", "busybox", "true") 345 containerID1 := strings.TrimSpace(out) 346 347 // tag as foobox 348 out, _ = dockerCmd(c, "commit", containerID1, "myimage") 349 imageID := stringid.TruncateID(strings.TrimSpace(out)) 350 351 config := `{ 352 "imagesFormat": "{{ .ID }} default" 353 }` 354 d, err := os.MkdirTemp("", "integration-cli-") 355 assert.NilError(c, err) 356 defer os.RemoveAll(d) 357 358 err = os.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644) 359 assert.NilError(c, err) 360 361 out, _ = dockerCmd(c, "--config", d, "images", "-q", "myimage") 362 assert.Equal(c, out, imageID+"\n", "Expected to print only the image id, got %v\n", out) 363 }