github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/actor/sharedaction/resource_unix_test.go (about)

     1  //go:build !windows
     2  // +build !windows
     3  
     4  package sharedaction_test
     5  
     6  import (
     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  		actor      *Actor
    22  		fakeConfig *sharedactionfakes.FakeConfig
    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("", "v2-resource-actions")
    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"), 0644)
    44  		Expect(err).ToNot(HaveOccurred())
    45  
    46  		err = ioutil.WriteFile(filepath.Join(srcDir, "tmpFile2"), []byte("Hello, Binky"), 0751)
    47  		Expect(err).ToNot(HaveOccurred())
    48  
    49  		err = ioutil.WriteFile(filepath.Join(srcDir, "tmpFile3"), []byte("Bananarama"), 0655)
    50  		Expect(err).ToNot(HaveOccurred())
    51  	})
    52  
    53  	AfterEach(func() {
    54  		Expect(os.RemoveAll(srcDir)).ToNot(HaveOccurred())
    55  	})
    56  
    57  	Describe("GatherArchiveResources", func() {
    58  		When("the archive exists", func() {
    59  			var (
    60  				archive string
    61  
    62  				resources  []Resource
    63  				executeErr error
    64  			)
    65  
    66  			BeforeEach(func() {
    67  				tmpfile, err := ioutil.TempFile("", "example")
    68  				Expect(err).ToNot(HaveOccurred())
    69  				archive = tmpfile.Name()
    70  				Expect(tmpfile.Close()).ToNot(HaveOccurred())
    71  			})
    72  
    73  			JustBeforeEach(func() {
    74  				err := zipit(srcDir, archive, "")
    75  				Expect(err).ToNot(HaveOccurred())
    76  
    77  				resources, executeErr = actor.GatherArchiveResources(archive)
    78  			})
    79  
    80  			AfterEach(func() {
    81  				Expect(os.RemoveAll(archive)).ToNot(HaveOccurred())
    82  			})
    83  
    84  			When("archive is empty", func() {
    85  				BeforeEach(func() {
    86  					var err error
    87  					srcDir, err = ioutil.TempDir("", "v2-resource-actions-empty")
    88  					Expect(err).ToNot(HaveOccurred())
    89  				})
    90  
    91  				AfterEach(func() {
    92  					Expect(os.RemoveAll(srcDir)).ToNot(HaveOccurred())
    93  				})
    94  
    95  				It("returns an EmptyArchiveError", func() {
    96  					_, err := actor.GatherArchiveResources(archive)
    97  					Expect(err).To(MatchError(actionerror.EmptyArchiveError{Path: archive}))
    98  				})
    99  			})
   100  
   101  			When("the file is a symlink to an archive", func() {
   102  				var symlinkToArchive string
   103  
   104  				BeforeEach(func() {
   105  					tempFile, err := ioutil.TempFile("", "symlink-to-archive")
   106  					Expect(err).ToNot(HaveOccurred())
   107  					Expect(tempFile.Close()).To(Succeed())
   108  					symlinkToArchive = tempFile.Name()
   109  					Expect(os.Remove(symlinkToArchive)).To(Succeed())
   110  
   111  					Expect(os.Symlink(archive, symlinkToArchive)).To(Succeed())
   112  				})
   113  
   114  				JustBeforeEach(func() {
   115  					resources, executeErr = actor.GatherArchiveResources(symlinkToArchive)
   116  				})
   117  
   118  				AfterEach(func() {
   119  					Expect(os.Remove(symlinkToArchive)).To(Succeed())
   120  				})
   121  
   122  				It("gathers a list of all files in a source archive", func() {
   123  					Expect(executeErr).ToNot(HaveOccurred())
   124  
   125  					Expect(resources).To(Equal(
   126  						[]Resource{
   127  							{Filename: "/", Mode: DefaultFolderPermissions},
   128  							{Filename: "/level1/", Mode: DefaultFolderPermissions},
   129  							{Filename: "/level1/level2/", Mode: DefaultFolderPermissions},
   130  							{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: DefaultArchiveFilePermissions},
   131  							{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: DefaultArchiveFilePermissions},
   132  							{Filename: "/tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: DefaultArchiveFilePermissions},
   133  						}))
   134  				})
   135  			})
   136  
   137  			When("a .cfignore file exists in the archive", func() {
   138  				BeforeEach(func() {
   139  					err := ioutil.WriteFile(filepath.Join(srcDir, ".cfignore"), []byte("level2"), 0655)
   140  					Expect(err).ToNot(HaveOccurred())
   141  				})
   142  
   143  				It("excludes all patterns of files mentioned in .cfignore", func() {
   144  					Expect(executeErr).ToNot(HaveOccurred())
   145  
   146  					Expect(resources).To(Equal(
   147  						[]Resource{
   148  							{Filename: "/", Mode: DefaultFolderPermissions},
   149  							{Filename: "/level1/", Mode: DefaultFolderPermissions},
   150  							{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: DefaultArchiveFilePermissions},
   151  							{Filename: "/tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: DefaultArchiveFilePermissions},
   152  						}))
   153  				})
   154  			})
   155  
   156  			When("default ignored files exist in the archive", func() {
   157  				BeforeEach(func() {
   158  					for _, filename := range DefaultIgnoreLines {
   159  						if filename != ".cfignore" {
   160  							err := ioutil.WriteFile(filepath.Join(srcDir, filename), nil, 0655)
   161  							Expect(err).ToNot(HaveOccurred())
   162  							err = ioutil.WriteFile(filepath.Join(srcDir, "level1", filename), nil, 0655)
   163  							Expect(err).ToNot(HaveOccurred())
   164  						}
   165  					}
   166  				})
   167  
   168  				It("excludes all default files", func() {
   169  					Expect(executeErr).ToNot(HaveOccurred())
   170  
   171  					Expect(resources).To(Equal(
   172  						[]Resource{
   173  							{Filename: "/", Mode: DefaultFolderPermissions},
   174  							{Filename: "/level1/", Mode: DefaultFolderPermissions},
   175  							{Filename: "/level1/level2/", Mode: DefaultFolderPermissions},
   176  							{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: DefaultArchiveFilePermissions},
   177  							{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: DefaultArchiveFilePermissions},
   178  							{Filename: "/tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: DefaultArchiveFilePermissions},
   179  						}))
   180  				})
   181  			})
   182  		})
   183  
   184  		When("the archive does not exist", func() {
   185  			It("returns an error if the file is problematic", func() {
   186  				_, err := actor.GatherArchiveResources("/does/not/exist")
   187  				Expect(os.IsNotExist(err)).To(BeTrue())
   188  			})
   189  		})
   190  	})
   191  
   192  	Describe("GatherDirectoryResources", func() {
   193  		When("files exist in the directory", func() {
   194  			var (
   195  				gatheredResources []Resource
   196  				executeErr        error
   197  			)
   198  
   199  			JustBeforeEach(func() {
   200  				gatheredResources, executeErr = actor.GatherDirectoryResources(srcDir)
   201  			})
   202  
   203  			When("the provided path is a symlink to the directory", func() {
   204  				var tmpDir string
   205  
   206  				BeforeEach(func() {
   207  					tmpDir = srcDir
   208  
   209  					tmpFile, err := ioutil.TempFile("", "symlink-file-")
   210  					Expect(err).ToNot(HaveOccurred())
   211  					Expect(tmpFile.Close()).To(Succeed())
   212  
   213  					srcDir = tmpFile.Name()
   214  					Expect(os.Remove(srcDir)).To(Succeed())
   215  					Expect(os.Symlink(tmpDir, srcDir)).To(Succeed())
   216  				})
   217  
   218  				AfterEach(func() {
   219  					Expect(os.RemoveAll(tmpDir)).To(Succeed())
   220  				})
   221  
   222  				It("gathers a list of all directories files in a source directory", func() {
   223  					Expect(executeErr).ToNot(HaveOccurred())
   224  
   225  					Expect(gatheredResources).To(Equal(
   226  						[]Resource{
   227  							{Filename: "level1", Mode: DefaultFolderPermissions},
   228  							{Filename: "level1/level2", Mode: DefaultFolderPermissions},
   229  							{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0644},
   230  							{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0751},
   231  							{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0655},
   232  						}))
   233  				})
   234  			})
   235  
   236  			When("a .cfignore file exists in the sourceDir", func() {
   237  				Context("with relative paths", func() {
   238  					BeforeEach(func() {
   239  						err := ioutil.WriteFile(filepath.Join(srcDir, ".cfignore"), []byte("level2"), 0655)
   240  						Expect(err).ToNot(HaveOccurred())
   241  					})
   242  
   243  					It("excludes all patterns of files mentioned in .cfignore", func() {
   244  						Expect(executeErr).ToNot(HaveOccurred())
   245  
   246  						Expect(gatheredResources).To(Equal(
   247  							[]Resource{
   248  								{Filename: "level1", Mode: DefaultFolderPermissions},
   249  								{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0751},
   250  								{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0655},
   251  							}))
   252  					})
   253  				})
   254  
   255  				Context("with absolute paths - where '/' == sourceDir", func() {
   256  					BeforeEach(func() {
   257  						err := ioutil.WriteFile(filepath.Join(srcDir, ".cfignore"), []byte("/level1/level2"), 0655)
   258  						Expect(err).ToNot(HaveOccurred())
   259  					})
   260  
   261  					It("excludes all patterns of files mentioned in .cfignore", func() {
   262  						Expect(executeErr).ToNot(HaveOccurred())
   263  
   264  						Expect(gatheredResources).To(Equal(
   265  							[]Resource{
   266  								{Filename: "level1", Mode: DefaultFolderPermissions},
   267  								{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0751},
   268  								{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0655},
   269  							}))
   270  					})
   271  				})
   272  			})
   273  
   274  			When("default ignored files exist in the app dir", func() {
   275  				BeforeEach(func() {
   276  					for _, filename := range DefaultIgnoreLines {
   277  						if filename != ".cfignore" {
   278  							err := ioutil.WriteFile(filepath.Join(srcDir, filename), nil, 0655)
   279  							Expect(err).ToNot(HaveOccurred())
   280  							err = ioutil.WriteFile(filepath.Join(srcDir, "level1", filename), nil, 0655)
   281  							Expect(err).ToNot(HaveOccurred())
   282  						}
   283  					}
   284  				})
   285  
   286  				It("excludes all default files", func() {
   287  					Expect(executeErr).ToNot(HaveOccurred())
   288  
   289  					Expect(gatheredResources).To(Equal(
   290  						[]Resource{
   291  							{Filename: "level1", Mode: DefaultFolderPermissions},
   292  							{Filename: "level1/level2", Mode: DefaultFolderPermissions},
   293  							{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0644},
   294  							{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0751},
   295  							{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0655},
   296  						}))
   297  				})
   298  			})
   299  
   300  			When("trace files are in the source directory", func() {
   301  				BeforeEach(func() {
   302  					traceFilePath := filepath.Join(srcDir, "i-am-trace.txt")
   303  					err := ioutil.WriteFile(traceFilePath, nil, 0655)
   304  					Expect(err).ToNot(HaveOccurred())
   305  
   306  					fakeConfig.VerboseReturns(false, []string{traceFilePath, "/some-other-path"})
   307  				})
   308  
   309  				It("excludes all of the trace files", func() {
   310  					Expect(executeErr).ToNot(HaveOccurred())
   311  
   312  					Expect(gatheredResources).To(Equal(
   313  						[]Resource{
   314  							{Filename: "level1", Mode: DefaultFolderPermissions},
   315  							{Filename: "level1/level2", Mode: DefaultFolderPermissions},
   316  							{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0644},
   317  							{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0751},
   318  							{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0655},
   319  						}))
   320  				})
   321  			})
   322  		})
   323  
   324  		When("the directory is empty", func() {
   325  			var emptyDir string
   326  
   327  			BeforeEach(func() {
   328  				var err error
   329  				emptyDir, err = ioutil.TempDir("", "v2-resource-actions-empty")
   330  				Expect(err).ToNot(HaveOccurred())
   331  			})
   332  
   333  			AfterEach(func() {
   334  				Expect(os.RemoveAll(emptyDir)).ToNot(HaveOccurred())
   335  			})
   336  
   337  			It("returns an EmptyDirectoryError", func() {
   338  				_, err := actor.GatherDirectoryResources(emptyDir)
   339  				Expect(err).To(MatchError(actionerror.EmptyDirectoryError{Path: emptyDir}))
   340  			})
   341  		})
   342  	})
   343  
   344  	Describe("ZipDirectoryResources", func() {
   345  		var (
   346  			resultZip  string
   347  			resources  []Resource
   348  			executeErr error
   349  		)
   350  
   351  		BeforeEach(func() {
   352  			resources = []Resource{
   353  				{Filename: "level1"},
   354  				{Filename: "level1/level2"},
   355  				{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4", Size: 9, Mode: 0644},
   356  				{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95", Size: 12, Mode: 0751},
   357  				{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879", Size: 10, Mode: 0655},
   358  			}
   359  		})
   360  
   361  		JustBeforeEach(func() {
   362  			resultZip, executeErr = actor.ZipDirectoryResources(srcDir, resources)
   363  		})
   364  
   365  		AfterEach(func() {
   366  			err := os.RemoveAll(resultZip)
   367  			Expect(err).ToNot(HaveOccurred())
   368  		})
   369  
   370  		When("zipping on UNIX", func() {
   371  			It("zips the directory and keeps the file permissions", func() {
   372  				Expect(executeErr).ToNot(HaveOccurred())
   373  
   374  				Expect(resultZip).ToNot(BeEmpty())
   375  				zipFile, err := os.Open(resultZip)
   376  				Expect(err).ToNot(HaveOccurred())
   377  				defer zipFile.Close()
   378  
   379  				zipInfo, err := zipFile.Stat()
   380  				Expect(err).ToNot(HaveOccurred())
   381  
   382  				reader, err := ykk.NewReader(zipFile, zipInfo.Size())
   383  				Expect(err).ToNot(HaveOccurred())
   384  
   385  				Expect(reader.File).To(HaveLen(5))
   386  				Expect(reader.File[2].Mode()).To(Equal(os.FileMode(0644)))
   387  				Expect(reader.File[3].Mode()).To(Equal(os.FileMode(0751)))
   388  				Expect(reader.File[4].Mode()).To(Equal(os.FileMode(0655)))
   389  			})
   390  		})
   391  	})
   392  })