github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/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/libpod/pkg/bindings" 10 "github.com/containers/libpod/pkg/bindings/containers" 11 "github.com/containers/libpod/pkg/bindings/images" 12 "github.com/containers/libpod/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 _, err = images.Remove(bt.conn, "foobar5000", &bindings.PFalse) 88 Expect(err).ToNot(BeNil()) 89 code, _ := bindings.CheckResponseCode(err) 90 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 91 92 // Remove an image by name, validate image is removed and error is nil 93 inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil) 94 Expect(err).To(BeNil()) 95 response, err := images.Remove(bt.conn, busybox.shortName, nil) 96 Expect(err).To(BeNil()) 97 Expect(inspectData.ID).To(Equal(response[0]["Deleted"])) 98 inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) 99 code, _ = bindings.CheckResponseCode(err) 100 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 101 102 // Start a container with alpine image 103 var top string = "top" 104 _, err = bt.RunTopContainer(&top, &bindings.PFalse, nil) 105 Expect(err).To(BeNil()) 106 // we should now have a container called "top" running 107 containerResponse, err := containers.Inspect(bt.conn, "top", &bindings.PFalse) 108 Expect(err).To(BeNil()) 109 Expect(containerResponse.Name).To(Equal("top")) 110 111 // try to remove the image "alpine". This should fail since we are not force 112 // deleting hence image cannot be deleted until the container is deleted. 113 response, err = images.Remove(bt.conn, alpine.shortName, &bindings.PFalse) 114 code, _ = bindings.CheckResponseCode(err) 115 Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) 116 117 // Removing the image "alpine" where force = true 118 response, err = images.Remove(bt.conn, alpine.shortName, &bindings.PTrue) 119 Expect(err).To(BeNil()) 120 121 // Checking if both the images are gone as well as the container is deleted 122 inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) 123 code, _ = bindings.CheckResponseCode(err) 124 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 125 126 inspectData, err = images.GetImage(bt.conn, alpine.shortName, nil) 127 code, _ = bindings.CheckResponseCode(err) 128 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 129 130 _, err = containers.Inspect(bt.conn, "top", &bindings.PFalse) 131 code, _ = bindings.CheckResponseCode(err) 132 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 133 }) 134 135 // Tests to validate the image tag command. 136 It("tag image", func() { 137 // Validates if invalid image name is given a bad response is encountered. 138 err = images.Tag(bt.conn, "dummy", "demo", alpine.shortName) 139 Expect(err).ToNot(BeNil()) 140 code, _ := bindings.CheckResponseCode(err) 141 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 142 143 // Validates if the image is tagged successfully. 144 err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName) 145 Expect(err).To(BeNil()) 146 147 // Validates if name updates when the image is retagged. 148 _, err := images.GetImage(bt.conn, "alpine:demo", nil) 149 Expect(err).To(BeNil()) 150 151 }) 152 153 // Test to validate the List images command. 154 It("List image", func() { 155 // Array to hold the list of images returned 156 imageSummary, err := images.List(bt.conn, nil, nil) 157 // There Should be no errors in the response. 158 Expect(err).To(BeNil()) 159 // Since in the begin context two images are created the 160 // list context should have only 2 images 161 Expect(len(imageSummary)).To(Equal(2)) 162 163 // Adding one more image. There Should be no errors in the response. 164 // And the count should be three now. 165 bt.Pull("busybox:glibc") 166 imageSummary, err = images.List(bt.conn, nil, nil) 167 Expect(err).To(BeNil()) 168 Expect(len(imageSummary)).To(Equal(3)) 169 170 // Validate the image names. 171 var names []string 172 for _, i := range imageSummary { 173 names = append(names, i.RepoTags...) 174 } 175 Expect(StringInSlice(alpine.name, names)).To(BeTrue()) 176 Expect(StringInSlice(busybox.name, names)).To(BeTrue()) 177 178 // List images with a filter 179 filters := make(map[string][]string) 180 filters["reference"] = []string{alpine.name} 181 filteredImages, err := images.List(bt.conn, &bindings.PFalse, filters) 182 Expect(err).To(BeNil()) 183 Expect(len(filteredImages)).To(BeNumerically("==", 1)) 184 185 // List images with a bad filter 186 filters["name"] = []string{alpine.name} 187 _, err = images.List(bt.conn, &bindings.PFalse, filters) 188 Expect(err).ToNot(BeNil()) 189 code, _ := bindings.CheckResponseCode(err) 190 Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) 191 }) 192 193 It("Image Exists", func() { 194 // exists on bogus image should be false, with no error 195 exists, err := images.Exists(bt.conn, "foobar") 196 Expect(err).To(BeNil()) 197 Expect(exists).To(BeFalse()) 198 199 // exists with shortname should be true 200 exists, err = images.Exists(bt.conn, alpine.shortName) 201 Expect(err).To(BeNil()) 202 Expect(exists).To(BeTrue()) 203 204 // exists with fqname should be true 205 exists, err = images.Exists(bt.conn, alpine.name) 206 Expect(err).To(BeNil()) 207 Expect(exists).To(BeTrue()) 208 }) 209 210 It("Load|Import Image", func() { 211 // load an image 212 _, err := images.Remove(bt.conn, alpine.name, nil) 213 Expect(err).To(BeNil()) 214 exists, err := images.Exists(bt.conn, alpine.name) 215 Expect(err).To(BeNil()) 216 Expect(exists).To(BeFalse()) 217 f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 218 defer f.Close() 219 Expect(err).To(BeNil()) 220 names, err := images.Load(bt.conn, f, nil) 221 Expect(err).To(BeNil()) 222 Expect(names.Name).To(Equal(alpine.name)) 223 exists, err = images.Exists(bt.conn, alpine.name) 224 Expect(err).To(BeNil()) 225 Expect(exists).To(BeTrue()) 226 227 // load with a repo name 228 f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 229 Expect(err).To(BeNil()) 230 _, err = images.Remove(bt.conn, alpine.name, nil) 231 Expect(err).To(BeNil()) 232 exists, err = images.Exists(bt.conn, alpine.name) 233 Expect(err).To(BeNil()) 234 Expect(exists).To(BeFalse()) 235 newName := "quay.io/newname:fizzle" 236 names, err = images.Load(bt.conn, f, &newName) 237 Expect(err).To(BeNil()) 238 Expect(names.Name).To(Equal(alpine.name)) 239 exists, err = images.Exists(bt.conn, newName) 240 Expect(err).To(BeNil()) 241 Expect(exists).To(BeTrue()) 242 243 // load with a bad repo name should trigger a 500 244 f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 245 Expect(err).To(BeNil()) 246 _, err = images.Remove(bt.conn, alpine.name, nil) 247 Expect(err).To(BeNil()) 248 exists, err = images.Exists(bt.conn, alpine.name) 249 Expect(err).To(BeNil()) 250 Expect(exists).To(BeFalse()) 251 badName := "quay.io/newName:fizzle" 252 _, err = images.Load(bt.conn, f, &badName) 253 Expect(err).ToNot(BeNil()) 254 code, _ := bindings.CheckResponseCode(err) 255 Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) 256 }) 257 258 It("Export Image", func() { 259 // Export an image 260 exportPath := filepath.Join(bt.tempDirPath, alpine.tarballName) 261 w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName)) 262 defer w.Close() 263 Expect(err).To(BeNil()) 264 err = images.Export(bt.conn, alpine.name, w, nil, nil) 265 Expect(err).To(BeNil()) 266 _, err = os.Stat(exportPath) 267 Expect(err).To(BeNil()) 268 269 // TODO how do we verify that a format change worked? 270 }) 271 272 It("Import Image", func() { 273 // load an image 274 _, err = images.Remove(bt.conn, alpine.name, nil) 275 Expect(err).To(BeNil()) 276 exists, err := images.Exists(bt.conn, alpine.name) 277 Expect(err).To(BeNil()) 278 Expect(exists).To(BeFalse()) 279 f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) 280 defer f.Close() 281 Expect(err).To(BeNil()) 282 changes := []string{"CMD /bin/foobar"} 283 testMessage := "test_import" 284 _, err = images.Import(bt.conn, changes, &testMessage, &alpine.name, nil, f) 285 Expect(err).To(BeNil()) 286 exists, err = images.Exists(bt.conn, alpine.name) 287 Expect(err).To(BeNil()) 288 Expect(exists).To(BeTrue()) 289 data, err := images.GetImage(bt.conn, alpine.name, nil) 290 Expect(err).To(BeNil()) 291 Expect(data.Comment).To(Equal(testMessage)) 292 293 }) 294 295 It("History Image", func() { 296 // a bogus name should return a 404 297 _, err := images.History(bt.conn, "foobar") 298 Expect(err).To(Not(BeNil())) 299 code, _ := bindings.CheckResponseCode(err) 300 Expect(code).To(BeNumerically("==", http.StatusNotFound)) 301 302 var foundID bool 303 data, err := images.GetImage(bt.conn, alpine.name, nil) 304 Expect(err).To(BeNil()) 305 history, err := images.History(bt.conn, alpine.name) 306 Expect(err).To(BeNil()) 307 for _, i := range history { 308 if i.ID == data.ID { 309 foundID = true 310 break 311 } 312 } 313 Expect(foundID).To(BeTrue()) 314 }) 315 316 It("Search for an image", func() { 317 reports, err := images.Search(bt.conn, "alpine", entities.ImageSearchOptions{}) 318 Expect(err).To(BeNil()) 319 Expect(len(reports)).To(BeNumerically(">", 1)) 320 var foundAlpine bool 321 for _, i := range reports { 322 if i.Name == "docker.io/library/alpine" { 323 foundAlpine = true 324 break 325 } 326 } 327 Expect(foundAlpine).To(BeTrue()) 328 329 // Search for alpine with a limit of 10 330 reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Limit: 10}) 331 Expect(err).To(BeNil()) 332 Expect(len(reports)).To(BeNumerically("<=", 10)) 333 334 // Search for alpine with stars greater than 100 335 reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Filters: []string{"stars=100"}}) 336 Expect(err).To(BeNil()) 337 for _, i := range reports { 338 Expect(i.Stars).To(BeNumerically(">=", 100)) 339 } 340 341 // Search with a fqdn 342 reports, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", entities.ImageSearchOptions{}) 343 Expect(len(reports)).To(BeNumerically(">=", 1)) 344 }) 345 346 It("Prune images", func() { 347 trueBoxed := true 348 results, err := images.Prune(bt.conn, &trueBoxed, nil) 349 Expect(err).NotTo(HaveOccurred()) 350 Expect(len(results)).To(BeNumerically(">", 0)) 351 Expect(results).To(ContainElement("docker.io/library/alpine:latest")) 352 }) 353 354 // TODO: we really need to extent to pull tests once we have a more sophisticated CI. 355 It("Image Pull", func() { 356 rawImage := "docker.io/library/busybox:latest" 357 358 pulledImages, err := images.Pull(bt.conn, rawImage, entities.ImagePullOptions{}) 359 Expect(err).To(BeNil()) 360 Expect(len(pulledImages)).To(Equal(1)) 361 362 exists, err := images.Exists(bt.conn, rawImage) 363 Expect(err).To(BeNil()) 364 Expect(exists).To(BeTrue()) 365 366 // Make sure the normalization AND the full-transport reference works. 367 _, err = images.Pull(bt.conn, "docker://"+rawImage, entities.ImagePullOptions{}) 368 Expect(err).To(BeNil()) 369 370 // The v2 endpoint only supports the docker transport. Let's see if that's really true. 371 _, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", entities.ImagePullOptions{}) 372 Expect(err).To(Not(BeNil())) 373 }) 374 })