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 }