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