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