github.com/willmadison/cli@v6.40.1-0.20181018160101-29d5937903ff+incompatible/actor/sharedaction/resource_test.go (about)

     1  package sharedaction_test
     2  
     3  import (
     4  	"archive/zip"
     5  	"io"
     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  		fakeConfig *sharedactionfakes.FakeConfig
    21  		actor      *Actor
    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("", "resource-actions-test")
    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"), 0600)
    43  		Expect(err).ToNot(HaveOccurred())
    44  
    45  		err = ioutil.WriteFile(filepath.Join(srcDir, "tmpFile2"), []byte("Hello, Binky"), 0600)
    46  		Expect(err).ToNot(HaveOccurred())
    47  
    48  		err = ioutil.WriteFile(filepath.Join(srcDir, "tmpFile3"), []byte("Bananarama"), 0600)
    49  		Expect(err).ToNot(HaveOccurred())
    50  
    51  		relativePath, err := filepath.Rel(srcDir, subDir)
    52  		Expect(err).ToNot(HaveOccurred())
    53  
    54  		// ./symlink -> ./level1/level2/tmpfile1
    55  		err = os.Symlink(filepath.Join(relativePath, "tmpFile1"), filepath.Join(srcDir, "symlink1"))
    56  		Expect(err).ToNot(HaveOccurred())
    57  
    58  		// ./level1/level2/symlink2 -> ../../tmpfile2
    59  		err = os.Symlink("../../tmpfile2", filepath.Join(subDir, "symlink2"))
    60  		Expect(err).ToNot(HaveOccurred())
    61  	})
    62  
    63  	AfterEach(func() {
    64  		Expect(os.RemoveAll(srcDir)).ToNot(HaveOccurred())
    65  	})
    66  
    67  	Describe("GatherArchiveResources", func() {
    68  		// tests are under resource_unix_test.go and resource_windows_test.go
    69  	})
    70  
    71  	Describe("GatherDirectoryResources", func() {
    72  		// tests are under resource_unix_test.go and resource_windows_test.go
    73  	})
    74  
    75  	Describe("ReadArchive", func() {
    76  		var (
    77  			archivePath string
    78  			executeErr  error
    79  
    80  			readCloser io.ReadCloser
    81  			fileSize   int64
    82  		)
    83  
    84  		JustBeforeEach(func() {
    85  			readCloser, fileSize, executeErr = actor.ReadArchive(archivePath)
    86  		})
    87  
    88  		AfterEach(func() {
    89  			Expect(os.RemoveAll(archivePath)).ToNot(HaveOccurred())
    90  		})
    91  
    92  		When("the archive can be accessed properly", func() {
    93  			BeforeEach(func() {
    94  				tmpfile, err := ioutil.TempFile("", "fake-archive")
    95  				Expect(err).ToNot(HaveOccurred())
    96  				_, err = tmpfile.Write([]byte("123456"))
    97  				Expect(err).ToNot(HaveOccurred())
    98  				Expect(tmpfile.Close()).ToNot(HaveOccurred())
    99  
   100  				archivePath = tmpfile.Name()
   101  			})
   102  
   103  			It("returns zero errors", func() {
   104  				defer readCloser.Close()
   105  
   106  				Expect(executeErr).ToNot(HaveOccurred())
   107  				Expect(fileSize).To(BeNumerically("==", 6))
   108  
   109  				b := make([]byte, 100)
   110  				size, err := readCloser.Read(b)
   111  				Expect(err).ToNot(HaveOccurred())
   112  				Expect(b[:size]).To(Equal([]byte("123456")))
   113  			})
   114  		})
   115  
   116  		When("the archive returns any access errors", func() {
   117  			It("returns the error", func() {
   118  				_, ok := executeErr.(*os.PathError)
   119  				Expect(ok).To(BeTrue())
   120  			})
   121  		})
   122  	})
   123  
   124  	Describe("ZipArchiveResources", func() {
   125  		var (
   126  			archive    string
   127  			resultZip  string
   128  			resources  []Resource
   129  			executeErr error
   130  		)
   131  
   132  		BeforeEach(func() {
   133  			tmpfile, err := ioutil.TempFile("", "zip-archive-resources")
   134  			Expect(err).ToNot(HaveOccurred())
   135  			defer tmpfile.Close()
   136  			archive = tmpfile.Name()
   137  
   138  			err = zipit(srcDir, archive, "")
   139  			Expect(err).ToNot(HaveOccurred())
   140  		})
   141  
   142  		JustBeforeEach(func() {
   143  			resultZip, executeErr = actor.ZipArchiveResources(archive, resources)
   144  		})
   145  
   146  		AfterEach(func() {
   147  			Expect(os.RemoveAll(archive)).ToNot(HaveOccurred())
   148  			Expect(os.RemoveAll(resultZip)).ToNot(HaveOccurred())
   149  		})
   150  
   151  		When("the files have not been changed since scanning them", func() {
   152  			When("there are no symlinks", func() {
   153  				BeforeEach(func() {
   154  					resources = []Resource{
   155  						{Filename: "/"},
   156  						{Filename: "/level1/"},
   157  						{Filename: "/level1/level2/"},
   158  						{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   159  						{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95"},
   160  						// Explicitly skipping /tmpFile3
   161  					}
   162  				})
   163  
   164  				It("zips the file and returns a populated resources list", func() {
   165  					Expect(executeErr).ToNot(HaveOccurred())
   166  
   167  					Expect(resultZip).ToNot(BeEmpty())
   168  					zipFile, err := os.Open(resultZip)
   169  					Expect(err).ToNot(HaveOccurred())
   170  					defer zipFile.Close()
   171  
   172  					zipInfo, err := zipFile.Stat()
   173  					Expect(err).ToNot(HaveOccurred())
   174  
   175  					reader, err := ykk.NewReader(zipFile, zipInfo.Size())
   176  					Expect(err).ToNot(HaveOccurred())
   177  
   178  					Expect(reader.File).To(HaveLen(5))
   179  					Expect(reader.File[0].Name).To(Equal("/"))
   180  					Expect(reader.File[1].Name).To(Equal("/level1/"))
   181  					Expect(reader.File[2].Name).To(Equal("/level1/level2/"))
   182  					Expect(reader.File[3].Name).To(Equal("/level1/level2/tmpFile1"))
   183  					Expect(reader.File[4].Name).To(Equal("/tmpFile2"))
   184  
   185  					expectFileContentsToEqual(reader.File[3], "why hello")
   186  					expectFileContentsToEqual(reader.File[4], "Hello, Binky")
   187  
   188  					for _, file := range reader.File {
   189  						Expect(file.Method).To(Equal(zip.Deflate))
   190  					}
   191  				})
   192  			})
   193  
   194  			When("there are relative symlink files", func() {
   195  				BeforeEach(func() {
   196  					resources = []Resource{
   197  						{Filename: "/"},
   198  						{Filename: "/level1/"},
   199  						{Filename: "/level1/level2/"},
   200  						{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   201  						{Filename: "/symlink1", Mode: os.ModeSymlink | 0777},
   202  						{Filename: "/level1/level2/symlink2", Mode: os.ModeSymlink | 0777},
   203  					}
   204  				})
   205  
   206  				It("zips the file and returns a populated resources list", func() {
   207  					Expect(executeErr).ToNot(HaveOccurred())
   208  
   209  					Expect(resultZip).ToNot(BeEmpty())
   210  					zipFile, err := os.Open(resultZip)
   211  					Expect(err).ToNot(HaveOccurred())
   212  					defer zipFile.Close()
   213  
   214  					zipInfo, err := zipFile.Stat()
   215  					Expect(err).ToNot(HaveOccurred())
   216  
   217  					reader, err := ykk.NewReader(zipFile, zipInfo.Size())
   218  					Expect(err).ToNot(HaveOccurred())
   219  
   220  					Expect(reader.File).To(HaveLen(6))
   221  					Expect(reader.File[0].Name).To(Equal("/"))
   222  					Expect(reader.File[1].Name).To(Equal("/level1/"))
   223  					Expect(reader.File[2].Name).To(Equal("/level1/level2/"))
   224  					Expect(reader.File[3].Name).To(Equal("/level1/level2/symlink2"))
   225  					Expect(reader.File[4].Name).To(Equal("/level1/level2/tmpFile1"))
   226  					Expect(reader.File[5].Name).To(Equal("/symlink1"))
   227  
   228  					expectFileContentsToEqual(reader.File[4], "why hello")
   229  					Expect(reader.File[5].Mode() & os.ModeSymlink).To(Equal(os.ModeSymlink))
   230  					expectFileContentsToEqual(reader.File[5], filepath.FromSlash("level1/level2/tmpFile1"))
   231  
   232  					Expect(reader.File[3].Mode() & os.ModeSymlink).To(Equal(os.ModeSymlink))
   233  					expectFileContentsToEqual(reader.File[3], filepath.FromSlash("../../tmpfile2"))
   234  				})
   235  			})
   236  		})
   237  
   238  		When("the files have changed since the scanning", func() {
   239  			BeforeEach(func() {
   240  				resources = []Resource{
   241  					{Filename: "/"},
   242  					{Filename: "/level1/"},
   243  					{Filename: "/level1/level2/"},
   244  					{Filename: "/level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   245  					{Filename: "/tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95"},
   246  					{Filename: "/tmpFile3", SHA1: "i dunno, 7?"},
   247  				}
   248  			})
   249  
   250  			It("returns an FileChangedError", func() {
   251  				Expect(executeErr).To(Equal(actionerror.FileChangedError{Filename: "/tmpFile3"}))
   252  			})
   253  		})
   254  	})
   255  
   256  	Describe("ZipDirectoryResources", func() {
   257  		var (
   258  			resultZip  string
   259  			resources  []Resource
   260  			executeErr error
   261  		)
   262  
   263  		JustBeforeEach(func() {
   264  			resultZip, executeErr = actor.ZipDirectoryResources(srcDir, resources)
   265  		})
   266  
   267  		AfterEach(func() {
   268  			Expect(os.RemoveAll(resultZip)).ToNot(HaveOccurred())
   269  		})
   270  
   271  		When("the files have not been changed since scanning them", func() {
   272  			When("there are no symlinks", func() {
   273  				BeforeEach(func() {
   274  					resources = []Resource{
   275  						{Filename: "level1"},
   276  						{Filename: "level1/level2"},
   277  						{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   278  						{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95"},
   279  						{Filename: "tmpFile3", SHA1: "f4c9ca85f3e084ffad3abbdabbd2a890c034c879"},
   280  					}
   281  				})
   282  
   283  				It("zips the file and returns a populated resources list", func() {
   284  					Expect(executeErr).ToNot(HaveOccurred())
   285  
   286  					Expect(resultZip).ToNot(BeEmpty())
   287  					zipFile, err := os.Open(resultZip)
   288  					Expect(err).ToNot(HaveOccurred())
   289  					defer zipFile.Close()
   290  
   291  					zipInfo, err := zipFile.Stat()
   292  					Expect(err).ToNot(HaveOccurred())
   293  
   294  					reader, err := ykk.NewReader(zipFile, zipInfo.Size())
   295  					Expect(err).ToNot(HaveOccurred())
   296  
   297  					Expect(reader.File).To(HaveLen(5))
   298  					Expect(reader.File[0].Name).To(Equal("level1/"))
   299  					Expect(reader.File[1].Name).To(Equal("level1/level2/"))
   300  					Expect(reader.File[2].Name).To(Equal("level1/level2/tmpFile1"))
   301  					Expect(reader.File[3].Name).To(Equal("tmpFile2"))
   302  					Expect(reader.File[4].Name).To(Equal("tmpFile3"))
   303  
   304  					expectFileContentsToEqual(reader.File[2], "why hello")
   305  					expectFileContentsToEqual(reader.File[3], "Hello, Binky")
   306  					expectFileContentsToEqual(reader.File[4], "Bananarama")
   307  
   308  					for _, file := range reader.File {
   309  						Expect(file.Method).To(Equal(zip.Deflate))
   310  					}
   311  				})
   312  			})
   313  
   314  			When("there are relative symlink files", func() {
   315  				BeforeEach(func() {
   316  					resources = []Resource{
   317  						{Filename: "level1"},
   318  						{Filename: "level1/level2"},
   319  						{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   320  						{Filename: "symlink1", Mode: os.ModeSymlink},
   321  						{Filename: "level1/level2/symlink2", Mode: os.ModeSymlink},
   322  					}
   323  				})
   324  
   325  				It("zips the file and returns a populated resources list", func() {
   326  					Expect(executeErr).ToNot(HaveOccurred())
   327  
   328  					Expect(resultZip).ToNot(BeEmpty())
   329  					zipFile, err := os.Open(resultZip)
   330  					Expect(err).ToNot(HaveOccurred())
   331  					defer zipFile.Close()
   332  
   333  					zipInfo, err := zipFile.Stat()
   334  					Expect(err).ToNot(HaveOccurred())
   335  
   336  					reader, err := ykk.NewReader(zipFile, zipInfo.Size())
   337  					Expect(err).ToNot(HaveOccurred())
   338  
   339  					Expect(reader.File).To(HaveLen(5))
   340  					Expect(reader.File[0].Name).To(Equal("level1/"))
   341  					Expect(reader.File[1].Name).To(Equal("level1/level2/"))
   342  					Expect(reader.File[2].Name).To(Equal("level1/level2/tmpFile1"))
   343  					Expect(reader.File[3].Name).To(Equal("symlink1"))
   344  					Expect(reader.File[4].Name).To(Equal("level1/level2/symlink2"))
   345  
   346  					expectFileContentsToEqual(reader.File[2], "why hello")
   347  					Expect(reader.File[3].Mode() & os.ModeSymlink).To(Equal(os.ModeSymlink))
   348  					expectFileContentsToEqual(reader.File[3], filepath.FromSlash("level1/level2/tmpFile1"))
   349  
   350  					Expect(reader.File[4].Mode() & os.ModeSymlink).To(Equal(os.ModeSymlink))
   351  					expectFileContentsToEqual(reader.File[4], filepath.FromSlash("../../tmpfile2"))
   352  				})
   353  			})
   354  		})
   355  
   356  		When("the files have changed since the scanning", func() {
   357  			BeforeEach(func() {
   358  				resources = []Resource{
   359  					{Filename: "level1"},
   360  					{Filename: "level1/level2"},
   361  					{Filename: "level1/level2/tmpFile1", SHA1: "9e36efec86d571de3a38389ea799a796fe4782f4"},
   362  					{Filename: "tmpFile2", SHA1: "e594bdc795bb293a0e55724137e53a36dc0d9e95"},
   363  					{Filename: "tmpFile3", SHA1: "i dunno, 7?"},
   364  				}
   365  			})
   366  
   367  			It("returns an FileChangedError", func() {
   368  				Expect(executeErr).To(Equal(actionerror.FileChangedError{Filename: filepath.Join(srcDir, "tmpFile3")}))
   369  			})
   370  		})
   371  	})
   372  })
   373  
   374  func expectFileContentsToEqual(file *zip.File, expectedContents string) {
   375  	reader, err := file.Open()
   376  	Expect(err).ToNot(HaveOccurred())
   377  	defer reader.Close()
   378  
   379  	body, err := ioutil.ReadAll(reader)
   380  	Expect(err).ToNot(HaveOccurred())
   381  
   382  	Expect(string(body)).To(Equal(expectedContents))
   383  }