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