github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+incompatible/actor/sharedaction/resource_unix_test.go (about)

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