github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/bindings/test/images_test.go (about) 1 package test_bindings 2 3 import ( 4 "net/http" 5 "os" 6 "path/filepath" 7 "time" 8 9 "github.com/containers/podman/v2/pkg/bindings" 10 "github.com/containers/podman/v2/pkg/bindings/containers" 11 "github.com/containers/podman/v2/pkg/bindings/images" 12 "github.com/containers/podman/v2/pkg/domain/entities" 13 . "github.com/onsi/ginkgo" 14 . "github.com/onsi/gomega" 15 "github.com/onsi/gomega/gexec" 16 ) 17 18 var _ = Describe("Podman images", func() { 19 var ( 20 // tempdir string 21 // err error 22 // podmanTest *PodmanTestIntegration 23 bt *bindingTest 24 s *gexec.Session 25 err error 26 ) 27 28 BeforeEach(func() { 29 // tempdir, err = CreateTempDirInTempDir() 30 // if err != nil { 31 // os.Exit(1) 32 // } 33 // podmanTest = PodmanTestCreate(tempdir) 34 // podmanTest.Setup() 35 // podmanTest.SeedImages() 36 bt = newBindingTest() 37 bt.RestoreImagesFromCache() 38 s = bt.startAPIService() 39 time.Sleep(1 * time.Second) 40 err := bt.NewConnection() 41 Expect(err).To(BeNil()) 42 }) 43 44 AfterEach(func() { 45 // podmanTest.Cleanup() 46 // f := CurrentGinkgoTestDescription() 47 // processTestResult(f) 48 s.Kill() 49 bt.cleanup() 50 }) 51 52 It("inspect image", func() { 53 // Inspect invalid image be 404 54 _, err = images.GetImage(bt.conn, "foobar5000", nil) 55 Expect(err).ToNot(BeNil()) 56 code, _ := bindings.CheckResponseCode(err) 57 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 58 59 // Inspect by short name 60 data, err := images.GetImage(bt.conn, alpine.shortName, nil) 61 Expect(err).To(BeNil()) 62 63 // Inspect with full ID 64 _, err = images.GetImage(bt.conn, data.ID, nil) 65 Expect(err).To(BeNil()) 66 67 // Inspect with partial ID 68 _, err = images.GetImage(bt.conn, data.ID[0:12], nil) 69 Expect(err).To(BeNil()) 70 71 // Inspect by long name 72 _, err = images.GetImage(bt.conn, alpine.name, nil) 73 Expect(err).To(BeNil()) 74 // TODO it looks like the images API alwaays returns size regardless 75 // of bool or not. What should we do ? 76 // Expect(data.Size).To(BeZero()) 77 78 // Enabling the size parameter should result in size being populated 79 data, err = images.GetImage(bt.conn, alpine.name, bindings.PTrue) 80 Expect(err).To(BeNil()) 81 Expect(data.Size).To(BeNumerically(">", 0)) 82 }) 83 84 // Test to validate the remove image api 85 It("remove image", func() { 86 // Remove invalid image should be a 404 87 response, err := images.Remove(bt.conn, "foobar5000", false) 88 Expect(err).ToNot(BeNil()) 89 Expect(response).To(BeNil()) 90 code, _ := bindings.CheckResponseCode(err) 91 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 92 93 // Remove an image by name, validate image is removed and error is nil 94 inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil) 95 Expect(err).To(BeNil()) 96 response, err = images.Remove(bt.conn, busybox.shortName, false) 97 Expect(err).To(BeNil()) 98 code, _ = bindings.CheckResponseCode(err) 99 100 Expect(inspectData.ID).To(Equal(response.Deleted[0])) 101 inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) 102 code, _ = bindings.CheckResponseCode(err) 103 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 104 105 // Start a container with alpine image 106 var top string = "top" 107 _, err = bt.RunTopContainer(&top, bindings.PFalse, nil) 108 Expect(err).To(BeNil()) 109 // we should now have a container called "top" running 110 containerResponse, err := containers.Inspect(bt.conn, "top", nil) 111 Expect(err).To(BeNil()) 112 Expect(containerResponse.Name).To(Equal("top")) 113 114 // try to remove the image "alpine". This should fail since we are not force 115 // deleting hence image cannot be deleted until the container is deleted. 116 response, err = images.Remove(bt.conn, alpine.shortName, false) 117 code, _ = bindings.CheckResponseCode(err) 118 Expect(code).To(BeNumerically("==", http.StatusConflict)) 119 120 // Removing the image "alpine" where force = true 121 response, err = images.Remove(bt.conn, alpine.shortName, true) 122 Expect(err).To(BeNil()) 123 // To be extra sure, check if the previously created container 124 // is gone as well. 125 _, err = containers.Inspect(bt.conn, "top", bindings.PFalse) 126 code, _ = bindings.CheckResponseCode(err) 127 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 128 129 // Now make sure both images are gone. 130 inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) 131 code, _ = bindings.CheckResponseCode(err) 132 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 133 134 inspectData, err = images.GetImage(bt.conn, alpine.shortName, nil) 135 code, _ = bindings.CheckResponseCode(err) 136 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 137 }) 138 139 // Tests to validate the image tag command. 140 It("tag image", func() { 141 // Validates if invalid image name is given a bad response is encountered. 142 err = images.Tag(bt.conn, "dummy", "demo", alpine.shortName) 143 Expect(err).ToNot(BeNil()) 144 code, _ := bindings.CheckResponseCode(err) 145 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 146 147 // Validates if the image is tagged successfully. 148 err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName) 149 Expect(err).To(BeNil()) 150 151 // Validates if name updates when the image is retagged. 152 _, err := images.GetImage(bt.conn, "alpine:demo", nil) 153 Expect(err).To(BeNil()) 154 155 }) 156 157 // Test to validate the List images command. 158 It("List image", func() { 159 // Array to hold the list of images returned 160 imageSummary, err := images.List(bt.conn, nil, nil) 161 // There Should be no errors in the response. 162 Expect(err).To(BeNil()) 163 // Since in the begin context two images are created the 164 // list context should have only 2 images 165 Expect(len(imageSummary)).To(Equal(2)) 166 167 // Adding one more image. There Should be no errors in the response. 168 // And the count should be three now. 169 bt.Pull("testimage:20200929") 170 imageSummary, err = images.List(bt.conn, nil, nil) 171 Expect(err).To(BeNil()) 172 Expect(len(imageSummary)).To(Equal(3)) 173 174 // Validate the image names. 175 var names []string 176 for _, i := range imageSummary { 177 names = append(names, i.RepoTags...) 178 } 179 Expect(StringInSlice(alpine.name, names)).To(BeTrue()) 180 Expect(StringInSlice(busybox.name, names)).To(BeTrue()) 181 182 // List images with a filter 183 filters := make(map[string][]string) 184 filters["reference"] = []string{alpine.name} 185 filteredImages, err := images.List(bt.conn, bindings.PFalse, filters) 186 Expect(err).To(BeNil()) 187 Expect(len(filteredImages)).To(BeNumerically("==", 1)) 188 189 // List images with a bad filter 190 filters["name"] = []string{alpine.name} 191 _, err = images.List(bt.conn, bindings.PFalse, filters) 192 Expect(err).ToNot(BeNil()) 193 code, _ := bindings.CheckResponseCode(err) 194 Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) 195 }) 196 197 It("Image Exists", func() { 198 // exists on bogus image should be false, with no error 199 exists, err := images.Exists(bt.conn, "foobar") 200 Expect(err).To(BeNil()) 201 Expect(exists).To(BeFalse()) 202 203 // exists with shortname should be true 204 exists, err = images.Exists(bt.conn, alpine.shortName) 205 Expect(err).To(BeNil()) 206 Expect(exists).To(BeTrue()) 207 208 // exists with fqname should be true 209 exists, err = images.Exists(bt.conn, alpine.name) 210 Expect(err).To(BeNil()) 211 Expect(exists).To(BeTrue()) 212 }) 213 214 It("Load|Import Image", func() { 215 // load an image 216 _, err := images.Remove(bt.conn, alpine.name, false) 217 Expect(err).To(BeNil()) 218 exists, err := images.Exists(bt.conn, alpine.name) 219 Expect(err).To(BeNil()) 220 Expect(exists).To(BeFalse()) 221 f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 222 defer f.Close() 223 Expect(err).To(BeNil()) 224 names, err := images.Load(bt.conn, f, nil) 225 Expect(err).To(BeNil()) 226 Expect(names.Names[0]).To(Equal(alpine.name)) 227 exists, err = images.Exists(bt.conn, alpine.name) 228 Expect(err).To(BeNil()) 229 Expect(exists).To(BeTrue()) 230 231 // load with a repo name 232 f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 233 Expect(err).To(BeNil()) 234 _, err = images.Remove(bt.conn, alpine.name, false) 235 Expect(err).To(BeNil()) 236 exists, err = images.Exists(bt.conn, alpine.name) 237 Expect(err).To(BeNil()) 238 Expect(exists).To(BeFalse()) 239 newName := "quay.io/newname:fizzle" 240 names, err = images.Load(bt.conn, f, &newName) 241 Expect(err).To(BeNil()) 242 Expect(names.Names[0]).To(Equal(alpine.name)) 243 exists, err = images.Exists(bt.conn, newName) 244 Expect(err).To(BeNil()) 245 Expect(exists).To(BeTrue()) 246 247 // load with a bad repo name should trigger a 500 248 f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 249 Expect(err).To(BeNil()) 250 _, err = images.Remove(bt.conn, alpine.name, false) 251 Expect(err).To(BeNil()) 252 exists, err = images.Exists(bt.conn, alpine.name) 253 Expect(err).To(BeNil()) 254 Expect(exists).To(BeFalse()) 255 badName := "quay.io/newName:fizzle" 256 _, err = images.Load(bt.conn, f, &badName) 257 Expect(err).ToNot(BeNil()) 258 code, _ := bindings.CheckResponseCode(err) 259 Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) 260 }) 261 262 It("Export Image", func() { 263 // Export an image 264 exportPath := filepath.Join(bt.tempDirPath, alpine.tarballName) 265 w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName)) 266 defer w.Close() 267 Expect(err).To(BeNil()) 268 err = images.Export(bt.conn, alpine.name, w, nil, nil) 269 Expect(err).To(BeNil()) 270 _, err = os.Stat(exportPath) 271 Expect(err).To(BeNil()) 272 273 // TODO how do we verify that a format change worked? 274 }) 275 276 It("Import Image", func() { 277 // load an image 278 _, err = images.Remove(bt.conn, alpine.name, false) 279 Expect(err).To(BeNil()) 280 exists, err := images.Exists(bt.conn, alpine.name) 281 Expect(err).To(BeNil()) 282 Expect(exists).To(BeFalse()) 283 f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 284 defer f.Close() 285 Expect(err).To(BeNil()) 286 changes := []string{"CMD /bin/foobar"} 287 testMessage := "test_import" 288 _, err = images.Import(bt.conn, changes, &testMessage, &alpine.name, nil, f) 289 Expect(err).To(BeNil()) 290 exists, err = images.Exists(bt.conn, alpine.name) 291 Expect(err).To(BeNil()) 292 Expect(exists).To(BeTrue()) 293 data, err := images.GetImage(bt.conn, alpine.name, nil) 294 Expect(err).To(BeNil()) 295 Expect(data.Comment).To(Equal(testMessage)) 296 297 }) 298 299 It("History Image", func() { 300 // a bogus name should return a 404 301 _, err := images.History(bt.conn, "foobar") 302 Expect(err).To(Not(BeNil())) 303 code, _ := bindings.CheckResponseCode(err) 304 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 305 306 var foundID bool 307 data, err := images.GetImage(bt.conn, alpine.name, nil) 308 Expect(err).To(BeNil()) 309 history, err := images.History(bt.conn, alpine.name) 310 Expect(err).To(BeNil()) 311 for _, i := range history { 312 if i.ID == data.ID { 313 foundID = true 314 break 315 } 316 } 317 Expect(foundID).To(BeTrue()) 318 }) 319 320 It("Search for an image", func() { 321 reports, err := images.Search(bt.conn, "alpine", entities.ImageSearchOptions{}) 322 Expect(err).To(BeNil()) 323 Expect(len(reports)).To(BeNumerically(">", 1)) 324 var foundAlpine bool 325 for _, i := range reports { 326 if i.Name == "docker.io/library/alpine" { 327 foundAlpine = true 328 break 329 } 330 } 331 Expect(foundAlpine).To(BeTrue()) 332 333 // Search for alpine with a limit of 10 334 reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Limit: 10}) 335 Expect(err).To(BeNil()) 336 Expect(len(reports)).To(BeNumerically("<=", 10)) 337 338 // Search for alpine with stars greater than 100 339 reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Filters: []string{"stars=100"}}) 340 Expect(err).To(BeNil()) 341 for _, i := range reports { 342 Expect(i.Stars).To(BeNumerically(">=", 100)) 343 } 344 345 // Search with a fqdn 346 reports, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", entities.ImageSearchOptions{}) 347 Expect(len(reports)).To(BeNumerically(">=", 1)) 348 }) 349 350 It("Prune images", func() { 351 trueBoxed := true 352 results, err := images.Prune(bt.conn, &trueBoxed, nil) 353 Expect(err).NotTo(HaveOccurred()) 354 Expect(len(results)).To(BeNumerically(">", 0)) 355 Expect(results).To(ContainElement("docker.io/library/alpine:latest")) 356 }) 357 358 // TODO: we really need to extent to pull tests once we have a more sophisticated CI. 359 It("Image Pull", func() { 360 rawImage := "docker.io/library/busybox:latest" 361 362 pulledImages, err := images.Pull(bt.conn, rawImage, entities.ImagePullOptions{}) 363 Expect(err).NotTo(HaveOccurred()) 364 Expect(len(pulledImages)).To(Equal(1)) 365 366 exists, err := images.Exists(bt.conn, rawImage) 367 Expect(err).NotTo(HaveOccurred()) 368 Expect(exists).To(BeTrue()) 369 370 // Make sure the normalization AND the full-transport reference works. 371 _, err = images.Pull(bt.conn, "docker://"+rawImage, entities.ImagePullOptions{}) 372 Expect(err).NotTo(HaveOccurred()) 373 374 // The v2 endpoint only supports the docker transport. Let's see if that's really true. 375 _, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", entities.ImagePullOptions{}) 376 Expect(err).To(HaveOccurred()) 377 }) 378 })