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  })