github.com/cloudfoundry-community/cloudfoundry-cli@v6.44.1-0.20240130060226-cda5ed8e89a5+incompatible/actor/sharedaction/resource_test.go (about)

     1  package sharedaction_test
     2  
     3  import (
     4  	"archive/zip"
     5  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"code.cloudfoundry.org/cli/actor/actionerror"
    12  	. "code.cloudfoundry.org/cli/actor/sharedaction"
    13  	"code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes"
    14  	"code.cloudfoundry.org/ykk"
    15  	. "github.com/onsi/ginkgo"
    16  	. "github.com/onsi/gomega"
    17  )
    18  
    19  var _ = Describe("Resource Actions", func() {
    20  	var (
    21  		fakeConfig *sharedactionfakes.FakeConfig
    22  		actor      *Actor
    23  		srcDir     string
    24  	)
    25  
    26  	BeforeEach(func() {
    27  		fakeConfig = new(sharedactionfakes.FakeConfig)
    28  		actor = NewActor(fakeConfig)
    29  
    30  		// Creates the following directory structure:
    31  		// level1/level2/tmpFile1
    32  		// tmpfile2
    33  		// tmpfile3
    34  
    35  		var err error
    36  		srcDir, err = ioutil.TempDir("", "resource-actions-test")
    37  		Expect(err).ToNot(HaveOccurred())
    38  
    39  		subDir := filepath.Join(srcDir, "level1", "level2")
    40  		err = os.MkdirAll(subDir, 0777)
    41  		Expect(err).ToNot(HaveOccurred())
    42  
    43  		err = ioutil.WriteFile(filepath.Join(subDir, "tmpFile1"), []byte("why hello"), 0600)
    44  		Expect(err).ToNot(HaveOccurred())
    45  
    46  		err = ioutil.WriteFile(filepath.Join(srcDir, "tmpFile2"), []byte("Hello, Binky"), 0600)
    47  		Expect(err).ToNot(HaveOccurred())
    48  
    49  		err = ioutil.WriteFile(filepath.Join(srcDir, "tmpFile3"), []byte("Bananarama"), 0600)
    50  		Expect(err).ToNot(HaveOccurred())
    51  
    52  		relativePath, err := filepath.Rel(srcDir, subDir)
    53  		Expect(err).ToNot(HaveOccurred())
    54  
    55  		// ./symlink -> ./level1/level2/tmpfile1
    56  		err = os.Symlink(filepath.Join(relativePath, "tmpFile1"), filepath.Join(srcDir, "symlink1"))
    57  		Expect(err).ToNot(HaveOccurred())
    58  
    59  		// ./level1/level2/symlink2 -> ../../tmpfile2
    60  		err = os.Symlink("../../tmpfile2", filepath.Join(subDir, "symlink2"))
    61  		Expect(err).ToNot(HaveOccurred())
    62  	})
    63  
    64  	AfterEach(func() {
    65  		Expect(os.RemoveAll(srcDir)).ToNot(HaveOccurred())
    66  	})
    67  
    68  	Describe("SharedToV3Resource", func() {
    69  
    70  		var returnedV3Resource V3Resource
    71  		var sharedResource = Resource{Filename: "file1", SHA1: "a43rknl", Mode: os.FileMode(644), Size: 100000}
    72  
    73  		JustBeforeEach(func() {
    74  			returnedV3Resource = sharedResource.ToV3Resource()
    75  		})
    76  
    77  		It("returns a ccv3 Resource", func() {
    78  			Expect(returnedV3Resource).To(Equal(V3Resource{
    79  				FilePath: "file1",
    80  				Checksum: ccv3.Checksum{
    81  					Value: "a43rknl",
    82  				},
    83  				SizeInBytes: 100000,
    84  				Mode:        os.FileMode(644),
    85  			}))
    86  		})
    87  
    88  	})
    89  
    90  	Describe("ToSharedResource", func() {
    91  
    92  		var returnedSharedResource Resource
    93  		var v3Resource = V3Resource{
    94  			FilePath: "file1",
    95  			Checksum: ccv3.Checksum{
    96  				Value: "a43rknl",
    97  			},
    98  			SizeInBytes: 100000,
    99  			Mode:        os.FileMode(644),
   100  		}
   101  
   102  		JustBeforeEach(func() {
   103  			returnedSharedResource = v3Resource.ToV2Resource()
   104  		})
   105  
   106  		It("returns a ccv3 Resource", func() {
   107  			Expect(returnedSharedResource).To(Equal(Resource{Filename: "file1", SHA1: "a43rknl", Mode: os.FileMode(644), Size: 100000}))
   108  
   109  		})
   110  	})
   111  
   112  	Describe("GatherArchiveResources", func() {
   113  		// tests are under resource_unix_test.go and resource_windows_test.go
   114  	})
   115  
   116  	Describe("GatherDirectoryResources", func() {
   117  		// tests are under resource_unix_test.go and resource_windows_test.go
   118  	})
   119  
   120  	Describe("ReadArchive", func() {
   121  		var (
   122  			archivePath string
   123  			executeErr  error
   124  
   125  			readCloser io.ReadCloser
   126  			fileSize   int64
   127  		)
   128  
   129  		JustBeforeEach(func() {
   130  			readCloser, fileSize, executeErr = actor.ReadArchive(archivePath)
   131  		})
   132  
   133  		AfterEach(func() {
   134  			Expect(os.RemoveAll(archivePath)).ToNot(HaveOccurred())
   135  		})
   136  
   137  		When("the archive can be accessed properly", func() {
   138  			BeforeEach(func() {
   139  				tmpfile, err := ioutil.TempFile("", "fake-archive")
   140  				Expect(err).ToNot(HaveOccurred())
   141  				_, err = tmpfile.Write([]byte("123456"))
   142  				Expect(err).ToNot(HaveOccurred())
   143  				Expect(tmpfile.Close()).ToNot(HaveOccurred())
   144  
   145  				archivePath = tmpfile.Name()
   146  			})
   147  
   148  			It("returns zero errors", func() {
   149  				defer readCloser.Close()
   150  
   151  				Expect(executeErr).ToNot(HaveOccurred())
   152  				Expect(fileSize).To(BeNumerically("==", 6))
   153  
   154  				b := make([]byte, 100)
   155  				size, err := readCloser.Read(b)
   156  				Expect(err).ToNot(HaveOccurred())
   157  				Expect(b[:size]).To(Equal([]byte("123456")))
   158  			})
   159  		})
   160  
   161  		When("the archive returns any access errors", func() {
   162  			It("returns the error", func() {
   163  				_, ok := executeErr.(*os.PathError)
   164  				Expect(ok).To(BeTrue())
   165  			})
   166  		})
   167  	})
   168  
   169  	Describe("ZipArchiveResources", func() {
   170  		var (
   171  			archive    string
   172  			resultZip  string
   173  			resources  []Resource
   174  			executeErr error
   175  		)
   176  
   177  		BeforeEach(func() {
   178  			tmpfile, err := ioutil.TempFile("", "zip-archive-resources")
   179  			Expect(err).ToNot(HaveOccurred())
   180  			defer tmpfile.Close()
   181  			archive = tmpfile.Name()
   182  
   183  			err = zipit(srcDir, archive, "")
   184  			Expect(err).ToNot(HaveOccurred())
   185  		})
   186  
   187  		JustBeforeEach(func() {
   188  			resultZip, executeErr = actor.ZipArchiveResources(archive, resources)
   189  		})
   190  
   191  		AfterEach(func() {
   192  			Expect(os.RemoveAll(archive)).ToNot(HaveOccurred())
   193  			Expect(os.RemoveAll(resultZip)).ToNot(HaveOccurred())
   194  		})
   195  
   196  		When("the files have not been changed since scanning them", func() {
   197  			When("there are no symlinks", func() {
   198  				BeforeEach(func() {
   199  					resources = []Resource{
   200  						{Filename: "/"},
   201  						{Filename: "/level1/"},
   202  						{Filename: "/level1/level2/"},
   203  						{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   204  						{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95"},
   205  						// Explicitly skipping /tmpFile3
   206  					}
   207  				})
   208  
   209  				It("zips the file and returns a populated resources list", func() {
   210  					Expect(executeErr).ToNot(HaveOccurred())
   211  
   212  					Expect(resultZip).ToNot(BeEmpty())
   213  					zipFile, err := os.Open(resultZip)
   214  					Expect(err).ToNot(HaveOccurred())
   215  					defer zipFile.Close()
   216  
   217  					zipInfo, err := zipFile.Stat()
   218  					Expect(err).ToNot(HaveOccurred())
   219  
   220  					reader, err := ykk.NewReader(zipFile, zipInfo.Size())
   221  					Expect(err).ToNot(HaveOccurred())
   222  
   223  					Expect(reader.File).To(HaveLen(5))
   224  
   225  					Expect(reader.File[0].Name).To(Equal("/"))
   226  
   227  					Expect(reader.File[1].Name).To(Equal("/level1/"))
   228  
   229  					Expect(reader.File[2].Name).To(Equal("/level1/level2/"))
   230  
   231  					Expect(reader.File[3].Name).To(Equal("/level1/level2/tmpFile1"))
   232  					Expect(reader.File[3].Method).To(Equal(zip.Deflate))
   233  					expectFileContentsToEqual(reader.File[3], "why hello")
   234  
   235  					Expect(reader.File[4].Name).To(Equal("/tmpFile2"))
   236  					Expect(reader.File[4].Method).To(Equal(zip.Deflate))
   237  					expectFileContentsToEqual(reader.File[4], "Hello, Binky")
   238  				})
   239  			})
   240  
   241  			When("there are relative symlink files", func() {
   242  				BeforeEach(func() {
   243  					resources = []Resource{
   244  						{Filename: "/"},
   245  						{Filename: "/level1/"},
   246  						{Filename: "/level1/level2/"},
   247  						{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   248  						{Filename: "/symlink1", Mode: os.ModeSymlink | 0777},
   249  						{Filename: "/level1/level2/symlink2", Mode: os.ModeSymlink | 0777},
   250  					}
   251  				})
   252  
   253  				It("zips the file and returns a populated resources list", func() {
   254  					Expect(executeErr).ToNot(HaveOccurred())
   255  
   256  					Expect(resultZip).ToNot(BeEmpty())
   257  					zipFile, err := os.Open(resultZip)
   258  					Expect(err).ToNot(HaveOccurred())
   259  					defer zipFile.Close()
   260  
   261  					zipInfo, err := zipFile.Stat()
   262  					Expect(err).ToNot(HaveOccurred())
   263  
   264  					reader, err := ykk.NewReader(zipFile, zipInfo.Size())
   265  					Expect(err).ToNot(HaveOccurred())
   266  
   267  					Expect(reader.File).To(HaveLen(6))
   268  					Expect(reader.File[0].Name).To(Equal("/"))
   269  					Expect(reader.File[1].Name).To(Equal("/level1/"))
   270  					Expect(reader.File[2].Name).To(Equal("/level1/level2/"))
   271  					Expect(reader.File[3].Name).To(Equal("/level1/level2/symlink2"))
   272  					Expect(reader.File[4].Name).To(Equal("/level1/level2/tmpFile1"))
   273  					Expect(reader.File[5].Name).To(Equal("/symlink1"))
   274  
   275  					expectFileContentsToEqual(reader.File[4], "why hello")
   276  					Expect(reader.File[5].Mode() & os.ModeSymlink).To(Equal(os.ModeSymlink))
   277  					expectFileContentsToEqual(reader.File[5], filepath.FromSlash("level1/level2/tmpFile1"))
   278  
   279  					Expect(reader.File[3].Mode() & os.ModeSymlink).To(Equal(os.ModeSymlink))
   280  					expectFileContentsToEqual(reader.File[3], filepath.FromSlash("../../tmpfile2"))
   281  				})
   282  			})
   283  		})
   284  
   285  		When("the files have changed since the scanning", func() {
   286  			BeforeEach(func() {
   287  				resources = []Resource{
   288  					{Filename: "/"},
   289  					{Filename: "/level1/"},
   290  					{Filename: "/level1/level2/"},
   291  					{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   292  					{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95"},
   293  					{Filename: "/tmpFile3", SHA1: "i dunno, 7?"},
   294  				}
   295  			})
   296  
   297  			It("returns an FileChangedError", func() {
   298  				Expect(executeErr).To(Equal(actionerror.FileChangedError{Filename: "/tmpFile3"}))
   299  			})
   300  		})
   301  	})
   302  
   303  	Describe("ZipDirectoryResources", func() {
   304  		var (
   305  			resultZip  string
   306  			resources  []Resource
   307  			executeErr error
   308  		)
   309  
   310  		JustBeforeEach(func() {
   311  			resultZip, executeErr = actor.ZipDirectoryResources(srcDir, resources)
   312  		})
   313  
   314  		AfterEach(func() {
   315  			Expect(os.RemoveAll(resultZip)).ToNot(HaveOccurred())
   316  		})
   317  
   318  		When("the files have not been changed since scanning them", func() {
   319  			When("there are no symlinks", func() {
   320  				BeforeEach(func() {
   321  					resources = []Resource{
   322  						{Filename: "level1"},
   323  						{Filename: "level1/level2"},
   324  						{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   325  						{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95"},
   326  						{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879"},
   327  					}
   328  				})
   329  
   330  				It("zips the file and returns a populated resources list", func() {
   331  					Expect(executeErr).ToNot(HaveOccurred())
   332  
   333  					Expect(resultZip).ToNot(BeEmpty())
   334  					zipFile, err := os.Open(resultZip)
   335  					Expect(err).ToNot(HaveOccurred())
   336  					defer zipFile.Close()
   337  
   338  					zipInfo, err := zipFile.Stat()
   339  					Expect(err).ToNot(HaveOccurred())
   340  
   341  					reader, err := ykk.NewReader(zipFile, zipInfo.Size())
   342  					Expect(err).ToNot(HaveOccurred())
   343  
   344  					Expect(reader.File).To(HaveLen(5))
   345  					Expect(reader.File[0].Name).To(Equal("level1/"))
   346  
   347  					Expect(reader.File[1].Name).To(Equal("level1/level2/"))
   348  
   349  					Expect(reader.File[2].Name).To(Equal("level1/level2/tmpFile1"))
   350  					Expect(reader.File[2].Method).To(Equal(zip.Deflate))
   351  					expectFileContentsToEqual(reader.File[2], "why hello")
   352  
   353  					Expect(reader.File[3].Name).To(Equal("tmpFile2"))
   354  					Expect(reader.File[3].Method).To(Equal(zip.Deflate))
   355  					expectFileContentsToEqual(reader.File[3], "Hello, Binky")
   356  
   357  					Expect(reader.File[4].Name).To(Equal("tmpFile3"))
   358  					Expect(reader.File[4].Method).To(Equal(zip.Deflate))
   359  					expectFileContentsToEqual(reader.File[4], "Bananarama")
   360  				})
   361  			})
   362  
   363  			When("there are relative symlink files", func() {
   364  				BeforeEach(func() {
   365  					resources = []Resource{
   366  						{Filename: "level1"},
   367  						{Filename: "level1/level2"},
   368  						{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   369  						{Filename: "symlink1", Mode: os.ModeSymlink},
   370  						{Filename: "level1/level2/symlink2", Mode: os.ModeSymlink},
   371  					}
   372  				})
   373  
   374  				It("zips the file and returns a populated resources list", func() {
   375  					Expect(executeErr).ToNot(HaveOccurred())
   376  
   377  					Expect(resultZip).ToNot(BeEmpty())
   378  					zipFile, err := os.Open(resultZip)
   379  					Expect(err).ToNot(HaveOccurred())
   380  					defer zipFile.Close()
   381  
   382  					zipInfo, err := zipFile.Stat()
   383  					Expect(err).ToNot(HaveOccurred())
   384  
   385  					reader, err := ykk.NewReader(zipFile, zipInfo.Size())
   386  					Expect(err).ToNot(HaveOccurred())
   387  
   388  					Expect(reader.File).To(HaveLen(5))
   389  
   390  					Expect(reader.File[0].Name).To(Equal("level1/"))
   391  
   392  					Expect(reader.File[1].Name).To(Equal("level1/level2/"))
   393  
   394  					Expect(reader.File[2].Name).To(Equal("level1/level2/tmpFile1"))
   395  					expectFileContentsToEqual(reader.File[2], "why hello")
   396  
   397  					Expect(reader.File[3].Name).To(Equal("symlink1"))
   398  					Expect(reader.File[3].Mode() & os.ModeSymlink).To(Equal(os.ModeSymlink))
   399  					expectFileContentsToEqual(reader.File[3], filepath.FromSlash("level1/level2/tmpFile1"))
   400  
   401  					Expect(reader.File[4].Name).To(Equal("level1/level2/symlink2"))
   402  					Expect(reader.File[4].Mode() & os.ModeSymlink).To(Equal(os.ModeSymlink))
   403  					expectFileContentsToEqual(reader.File[4], filepath.FromSlash("../../tmpfile2"))
   404  				})
   405  			})
   406  		})
   407  
   408  		When("the files have changed since the scanning", func() {
   409  			BeforeEach(func() {
   410  				resources = []Resource{
   411  					{Filename: "level1"},
   412  					{Filename: "level1/level2"},
   413  					{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   414  					{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95"},
   415  					{Filename: "tmpFile3", SHA1: "i dunno, 7?"},
   416  				}
   417  			})
   418  
   419  			It("returns an FileChangedError", func() {
   420  				Expect(executeErr).To(Equal(actionerror.FileChangedError{Filename: filepath.Join(srcDir, "tmpFile3")}))
   421  			})
   422  		})
   423  	})
   424  })
   425  
   426  func expectFileContentsToEqual(file *zip.File, expectedContents string) {
   427  	reader, err := file.Open()
   428  	Expect(err).ToNot(HaveOccurred())
   429  	defer reader.Close()
   430  
   431  	body, err := ioutil.ReadAll(reader)
   432  	Expect(err).ToNot(HaveOccurred())
   433  
   434  	Expect(string(body)).To(Equal(expectedContents))
   435  }