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