github.com/openshift/source-to-image@v1.4.1-0.20240516041539-bf52fc02204e/pkg/tar/tar_test.go (about) 1 package tar 2 3 import ( 4 "archive/tar" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "regexp" 11 "runtime" 12 "testing" 13 "time" 14 15 s2ierr "github.com/openshift/source-to-image/pkg/errors" 16 "github.com/openshift/source-to-image/pkg/util/fs" 17 ) 18 19 type dirDesc struct { 20 name string 21 modifiedDate time.Time 22 mode os.FileMode 23 } 24 25 type fileDesc struct { 26 name string 27 modifiedDate time.Time 28 mode os.FileMode 29 content string 30 shouldSkip bool 31 target string 32 } 33 34 type linkDesc struct { 35 linkName string 36 fileName string 37 } 38 39 func createTestFiles(baseDir string, dirs []dirDesc, files []fileDesc, links []linkDesc) error { 40 for _, dd := range dirs { 41 fileName := filepath.Join(baseDir, dd.name) 42 err := os.Mkdir(fileName, dd.mode) 43 if err != nil { 44 return err 45 } 46 os.Chmod(fileName, dd.mode) // umask 47 } 48 for _, fd := range files { 49 fileName := filepath.Join(baseDir, fd.name) 50 err := ioutil.WriteFile(fileName, []byte(fd.content), fd.mode) 51 if err != nil { 52 return err 53 } 54 os.Chmod(fileName, fd.mode) 55 os.Chtimes(fileName, fd.modifiedDate, fd.modifiedDate) 56 } 57 for _, ld := range links { 58 linkName := filepath.Join(baseDir, ld.linkName) 59 if err := os.MkdirAll(filepath.Dir(linkName), 0700); err != nil { 60 return err 61 } 62 if err := os.Symlink(ld.fileName, linkName); err != nil { 63 return err 64 } 65 } 66 for _, dd := range dirs { 67 fileName := filepath.Join(baseDir, dd.name) 68 os.Chtimes(fileName, dd.modifiedDate, dd.modifiedDate) 69 } 70 return nil 71 } 72 73 func verifyTarFile(t *testing.T, filename string, dirs []dirDesc, files []fileDesc, links []linkDesc) { 74 if runtime.GOOS == "windows" { 75 for i := range files { 76 if files[i].mode&0700 == 0400 { 77 files[i].mode = 0444 78 } else { 79 files[i].mode = 0666 80 } 81 } 82 for i := range dirs { 83 if dirs[i].mode&0700 == 0500 { 84 dirs[i].mode = 0555 85 } else { 86 dirs[i].mode = 0777 87 } 88 } 89 } 90 dirsToVerify := make(map[string]dirDesc) 91 for _, dd := range dirs { 92 dirsToVerify[dd.name] = dd 93 } 94 filesToVerify := make(map[string]fileDesc) 95 for _, fd := range files { 96 if !fd.shouldSkip { 97 filesToVerify[fd.name] = fd 98 } 99 } 100 linksToVerify := make(map[string]linkDesc) 101 for _, ld := range links { 102 linksToVerify[ld.linkName] = ld 103 } 104 105 file, err := os.Open(filename) 106 defer file.Close() 107 if err != nil { 108 t.Fatalf("Cannot open tar file %q: %v", filename, err) 109 } 110 tr := tar.NewReader(file) 111 for { 112 hdr, err := tr.Next() 113 if hdr == nil { 114 break 115 } 116 if err != nil { 117 t.Fatalf("Error reading tar %q: %v", filename, err) 118 } 119 finfo := hdr.FileInfo() 120 if dd, ok := dirsToVerify[hdr.Name]; ok { 121 delete(dirsToVerify, hdr.Name) 122 if finfo.Mode()&os.ModeDir == 0 { 123 t.Errorf("Incorrect dir %q", finfo.Name()) 124 } 125 if finfo.Mode().Perm() != dd.mode { 126 t.Errorf("Dir %q from tar %q does not match expected mode. Expected: %v, actual: %v", 127 hdr.Name, filename, dd.mode, finfo.Mode().Perm()) 128 } 129 if !dd.modifiedDate.IsZero() && finfo.ModTime().UTC() != dd.modifiedDate { 130 t.Errorf("Dir %q from tar %q does not match expected modified date. Expected: %v, actual: %v", 131 hdr.Name, filename, dd.modifiedDate, finfo.ModTime().UTC()) 132 } 133 } else if fd, ok := filesToVerify[hdr.Name]; ok { 134 delete(filesToVerify, hdr.Name) 135 if finfo.Mode().Perm() != fd.mode { 136 t.Errorf("File %q from tar %q does not match expected mode. Expected: %v, actual: %v", 137 hdr.Name, filename, fd.mode, finfo.Mode().Perm()) 138 } 139 if !fd.modifiedDate.IsZero() && finfo.ModTime().UTC() != fd.modifiedDate { 140 t.Errorf("File %q from tar %q does not match expected modified date. Expected: %v, actual: %v", 141 hdr.Name, filename, fd.modifiedDate, finfo.ModTime().UTC()) 142 } 143 fileBytes, err := ioutil.ReadAll(tr) 144 if err != nil { 145 t.Fatalf("Error reading tar %q: %v", filename, err) 146 } 147 fileContent := string(fileBytes) 148 if fileContent != fd.content { 149 t.Errorf("Content for file %q in tar %q doesn't match expected value. Expected: %q, Actual: %q", 150 finfo.Name(), filename, fd.content, fileContent) 151 } 152 } else if ld, ok := linksToVerify[hdr.Name]; ok { 153 delete(linksToVerify, hdr.Name) 154 if finfo.Mode()&os.ModeSymlink == 0 { 155 t.Errorf("Incorrect link %q", finfo.Name()) 156 } 157 if hdr.Linkname != ld.fileName { 158 t.Errorf("Incorrect link location. Expected: %q, Actual %q", ld.fileName, hdr.Linkname) 159 } 160 } else { 161 t.Errorf("Cannot find file %q from tar in files to verify.", hdr.Name) 162 } 163 } 164 165 if len(filesToVerify) > 0 || len(linksToVerify) > 0 { 166 t.Errorf("Did not find all expected files in tar: fileToVerify %v, linksToVerify %v", filesToVerify, linksToVerify) 167 } 168 } 169 170 func TestCreateTarStreamIncludeParentDir(t *testing.T) { 171 tempDir, err := ioutil.TempDir("", "testtar") 172 defer os.RemoveAll(tempDir) 173 if err != nil { 174 t.Fatalf("Cannot create temp directory for test: %v", err) 175 } 176 modificationDate := time.Date(2011, time.March, 5, 23, 30, 1, 0, time.UTC) 177 testDirs := []dirDesc{ 178 {"dir01", modificationDate, 0700}, 179 {"dir01/.git", modificationDate, 0755}, 180 {"dir01/dir02", modificationDate, 0755}, 181 {"dir01/dir03", modificationDate, 0775}, 182 } 183 testFiles := []fileDesc{ 184 {"dir01/dir02/test1.txt", modificationDate, 0700, "Test1 file content", false, ""}, 185 {"dir01/test2.git", modificationDate, 0660, "Test2 file content", false, ""}, 186 {"dir01/dir03/test3.txt", modificationDate, 0444, "Test3 file content", false, ""}, 187 {"dir01/.git/hello.txt", modificationDate, 0600, "Ignore file content", true, ""}, 188 } 189 if err = createTestFiles(tempDir, testDirs, testFiles, []linkDesc{}); err != nil { 190 t.Fatalf("Cannot create test files: %v", err) 191 } 192 th := New(fs.NewFileSystem()) 193 tarFile, err := ioutil.TempFile("", "testtarout") 194 if err != nil { 195 t.Fatalf("Unable to create temporary file %v", err) 196 } 197 defer os.Remove(tarFile.Name()) 198 err = th.CreateTarStream(tempDir, true, tarFile) 199 if err != nil { 200 t.Fatalf("Unable to create tar file %v", err) 201 } 202 tarFile.Close() 203 for i := range testDirs { 204 testDirs[i].name = filepath.ToSlash(filepath.Join(filepath.Base(tempDir), testDirs[i].name)) 205 } 206 for i := range testFiles { 207 testFiles[i].name = filepath.ToSlash(filepath.Join(filepath.Base(tempDir), testFiles[i].name)) 208 } 209 verifyTarFile(t, tarFile.Name(), testDirs, testFiles, []linkDesc{}) 210 } 211 212 func TestCreateTar(t *testing.T) { 213 th := New(fs.NewFileSystem()) 214 tempDir, err := ioutil.TempDir("", "testtar") 215 defer os.RemoveAll(tempDir) 216 if err != nil { 217 t.Fatalf("Cannot create temp directory for test: %v", err) 218 } 219 modificationDate := time.Date(2011, time.March, 5, 23, 30, 1, 0, time.UTC) 220 testDirs := []dirDesc{ 221 {"dir01", modificationDate, 0700}, 222 {"dir01/.git", modificationDate, 0755}, 223 {"dir01/dir02", modificationDate, 0755}, 224 {"dir01/dir03", modificationDate, 0775}, 225 {"link", modificationDate, 0775}, 226 } 227 testFiles := []fileDesc{ 228 {"dir01/dir02/test1.txt", modificationDate, 0700, "Test1 file content", false, ""}, 229 {"dir01/test2.git", modificationDate, 0660, "Test2 file content", false, ""}, 230 {"dir01/dir03/test3.txt", modificationDate, 0444, "Test3 file content", false, ""}, 231 {"dir01/.git/hello.txt", modificationDate, 0600, "Ignore file content", true, ""}, 232 {"dir01/dir03/tëst3.txt", modificationDate, 0444, "Test utf-8 file header content", false, ""}, 233 } 234 testLinks := []linkDesc{ 235 {"link/okfilelink", "../dir01/dir02/test1.txt"}, 236 {"link/errfilelink", "../dir01/missing.target"}, 237 {"link/okdirlink", "../dir01/dir02"}, 238 {"link/errdirlink", "../dir01/.git"}, 239 } 240 if err = createTestFiles(tempDir, testDirs, testFiles, testLinks); err != nil { 241 t.Fatalf("Cannot create test files: %v", err) 242 } 243 244 tarFile, err := th.CreateTarFile("", tempDir) 245 defer os.Remove(tarFile) 246 if err != nil { 247 t.Fatalf("Unable to create new tar upload file: %v", err) 248 } 249 verifyTarFile(t, tarFile, testDirs, testFiles, testLinks) 250 } 251 252 func TestCreateTarIncludeDotGit(t *testing.T) { 253 th := New(fs.NewFileSystem()) 254 th.SetExclusionPattern(regexp.MustCompile("test3.txt")) 255 tempDir, err := ioutil.TempDir("", "testtar") 256 defer os.RemoveAll(tempDir) 257 if err != nil { 258 t.Fatalf("Cannot create temp directory for test: %v", err) 259 } 260 modificationDate := time.Date(2011, time.March, 5, 23, 30, 1, 0, time.UTC) 261 testDirs := []dirDesc{ 262 {"dir01", modificationDate, 0700}, 263 {"dir01/.git", modificationDate, 0755}, 264 {"dir01/dir02", modificationDate, 0755}, 265 {"dir01/dir03", modificationDate, 0775}, 266 {"link", modificationDate, 0775}, 267 } 268 testFiles := []fileDesc{ 269 {"dir01/dir02/test1.txt", modificationDate, 0700, "Test1 file content", false, ""}, 270 {"dir01/test2.git", modificationDate, 0660, "Test2 file content", false, ""}, 271 {"dir01/dir03/test3.txt", modificationDate, 0444, "Test3 file content", true, ""}, 272 {"dir01/.git/hello.txt", modificationDate, 0600, "Allow .git content", false, ""}, 273 } 274 testLinks := []linkDesc{ 275 {"link/okfilelink", "../dir01/dir02/test1.txt"}, 276 {"link/errfilelink", "../dir01/missing.target"}, 277 {"link/okdirlink", "../dir01/dir02"}, 278 {"link/okdirlink2", "../dir01/.git"}, 279 } 280 if err = createTestFiles(tempDir, testDirs, testFiles, testLinks); err != nil { 281 t.Fatalf("Cannot create test files: %v", err) 282 } 283 284 tarFile, err := th.CreateTarFile("", tempDir) 285 defer os.Remove(tarFile) 286 if err != nil { 287 t.Fatalf("Unable to create new tar upload file: %v", err) 288 } 289 verifyTarFile(t, tarFile, testDirs, testFiles, testLinks) 290 } 291 292 func TestCreateTarEmptyRegexp(t *testing.T) { 293 th := New(fs.NewFileSystem()) 294 th.SetExclusionPattern(regexp.MustCompile("")) 295 tempDir, err := ioutil.TempDir("", "testtar") 296 defer os.RemoveAll(tempDir) 297 if err != nil { 298 t.Fatalf("Cannot create temp directory for test: %v", err) 299 } 300 modificationDate := time.Date(2011, time.March, 5, 23, 30, 1, 0, time.UTC) 301 testDirs := []dirDesc{ 302 {"dir01", modificationDate, 0700}, 303 {"dir01/.git", modificationDate, 0755}, 304 {"dir01/dir02", modificationDate, 0755}, 305 {"dir01/dir03", modificationDate, 0775}, 306 {"link", modificationDate, 0775}, 307 } 308 testFiles := []fileDesc{ 309 {"dir01/dir02/test1.txt", modificationDate, 0700, "Test1 file content", false, ""}, 310 {"dir01/test2.git", modificationDate, 0660, "Test2 file content", false, ""}, 311 {"dir01/dir03/test3.txt", modificationDate, 0444, "Test3 file content", false, ""}, 312 {"dir01/.git/hello.txt", modificationDate, 0600, "Allow .git content", false, ""}, 313 } 314 testLinks := []linkDesc{ 315 {"link/okfilelink", "../dir01/dir02/test1.txt"}, 316 {"link/errfilelink", "../dir01/missing.target"}, 317 {"link/okdirlink", "../dir01/dir02"}, 318 {"link/okdirlink2", "../dir01/.git"}, 319 } 320 if err = createTestFiles(tempDir, testDirs, testFiles, testLinks); err != nil { 321 t.Fatalf("Cannot create test files: %v", err) 322 } 323 324 tarFile, err := th.CreateTarFile("", tempDir) 325 defer os.Remove(tarFile) 326 if err != nil { 327 t.Fatalf("Unable to create new tar upload file: %v", err) 328 } 329 verifyTarFile(t, tarFile, testDirs, testFiles, testLinks) 330 } 331 332 func createTestTar(files []fileDesc, writer io.Writer) error { 333 tw := tar.NewWriter(writer) 334 defer tw.Close() 335 for _, fd := range files { 336 if isSymLink(fd.mode) { 337 if err := addSymLink(tw, &fd); err != nil { 338 msg := "unable to add symbolic link %q (points to %q) to archive: %v" 339 return fmt.Errorf(msg, fd.name, fd.target, err) 340 } 341 continue 342 } 343 if fd.mode.IsDir() { 344 if err := addDir(tw, &fd); err != nil { 345 msg := "unable to add dir %q to archive: %v" 346 return fmt.Errorf(msg, fd.name, err) 347 } 348 continue 349 } 350 if err := addRegularFile(tw, &fd); err != nil { 351 return fmt.Errorf("unable to add file %q to archive: %v", fd.name, err) 352 } 353 } 354 return nil 355 } 356 357 func addRegularFile(tw *tar.Writer, fd *fileDesc) error { 358 contentBytes := []byte(fd.content) 359 hdr := &tar.Header{ 360 Name: fd.name, 361 Mode: int64(fd.mode), 362 Size: int64(len(contentBytes)), 363 Typeflag: tar.TypeReg, 364 AccessTime: time.Now(), 365 ModTime: fd.modifiedDate, 366 ChangeTime: fd.modifiedDate, 367 } 368 if err := tw.WriteHeader(hdr); err != nil { 369 return err 370 } 371 _, err := tw.Write(contentBytes) 372 return err 373 } 374 375 func addDir(tw *tar.Writer, fd *fileDesc) error { 376 hdr := &tar.Header{ 377 Name: fd.name, 378 Mode: int64(fd.mode & 0777), 379 Typeflag: tar.TypeDir, 380 AccessTime: time.Now(), 381 ModTime: fd.modifiedDate, 382 ChangeTime: fd.modifiedDate, 383 } 384 return tw.WriteHeader(hdr) 385 } 386 387 func addSymLink(tw *tar.Writer, fd *fileDesc) error { 388 if len(fd.target) == 0 { 389 return fmt.Errorf("link %q must point to somewhere, but target wasn't defined", fd.name) 390 } 391 392 hdr := &tar.Header{ 393 Name: fd.name, 394 Linkname: fd.target, 395 Mode: int64(fd.mode & os.ModePerm), 396 Typeflag: tar.TypeSymlink, 397 ModTime: fd.modifiedDate, 398 } 399 400 return tw.WriteHeader(hdr) 401 } 402 403 func isSymLink(mode os.FileMode) bool { 404 return mode&os.ModeSymlink == os.ModeSymlink 405 } 406 407 func verifyDirectory(t *testing.T, dir string, dirs []dirDesc, files []fileDesc, links []linkDesc) { 408 if dirs == nil { 409 dirs = []dirDesc{} 410 } 411 if files == nil { 412 files = []fileDesc{} 413 } 414 if links == nil { 415 links = []linkDesc{} 416 } 417 if runtime.GOOS == "windows" { 418 for i := range files { 419 files[i].name = filepath.FromSlash(files[i].name) 420 if files[i].mode&0200 == 0200 { 421 // if the file is user writable make it writable for everyone 422 files[i].mode |= 0666 423 } else { 424 // if the file is only readable, make it readable for everyone 425 // first clear the r/w permission bits 426 files[i].mode &^= 0666 427 // then set r permission for all 428 files[i].mode |= 0444 429 } 430 if files[i].mode.IsDir() { 431 // if the file is a directory, make it executable for everyone 432 files[i].mode |= 0111 433 } else { 434 // if it's not a directory, clear the executable bits as they are 435 // irrelevant on windows. 436 files[i].mode &^= 0111 437 } 438 files[i].target = filepath.FromSlash(files[i].target) 439 } 440 for j := range dirs { 441 dirs[j].name = filepath.FromSlash(dirs[j].name) 442 if dirs[j].mode&0200 == 0200 { 443 // if the file is user writable make it writable for everyone 444 dirs[j].mode |= 0666 445 } else { 446 // if the file is only readable, make it readable for everyone 447 // first clear the r/w permission bits 448 dirs[j].mode &^= 0666 449 // then set r permission for all 450 dirs[j].mode |= 0444 451 } 452 if dirs[j].mode.IsDir() { 453 // if the file is a directory, make it executable for everyone 454 dirs[j].mode |= 0111 455 } else { 456 // if it's not a directory, clear the executable bits as they are 457 // irrelevant on windows. 458 dirs[j].mode &^= 0111 459 } 460 461 } 462 for k := range links { 463 links[k].fileName = filepath.FromSlash(links[k].fileName) 464 links[k].linkName = filepath.FromSlash(links[k].linkName) 465 } 466 } 467 dirsToVerify := make(map[string]dirDesc) 468 for _, dd := range dirs { 469 dirsToVerify[dd.name] = dd 470 } 471 pathsToVerify := make(map[string]fileDesc) 472 for _, fd := range files { 473 pathsToVerify[fd.name] = fd 474 } 475 linksToVerify := make(map[string]linkDesc) 476 for _, ld := range links { 477 linksToVerify[ld.linkName] = ld 478 } 479 err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 480 if path == dir { 481 return nil 482 } 483 relpath := path[len(dir)+1:] 484 if dd, ok := dirsToVerify[relpath]; ok { 485 if !info.IsDir() { 486 t.Errorf("Incorrect dir %q", info.Name()) 487 } 488 if info.Mode().Perm() != dd.mode { 489 t.Errorf("Dir %q does not match expected mode. Expected: %v, actual: %v", 490 info.Name(), dd.mode, info.Mode().Perm()) 491 } 492 // Do not test directories - mod time will be time directory was created on filesystem 493 } else if fd, ok := pathsToVerify[relpath]; ok { 494 if info.Mode() != fd.mode { 495 t.Errorf("File mode is not equal for %q. Expected: %v, Actual: %v", 496 relpath, fd.mode, info.Mode()) 497 } 498 // TODO: check modification time for symlinks when extractLink() will support it 499 if info.ModTime().UTC() != fd.modifiedDate && !isSymLink(fd.mode) && !fd.mode.IsDir() { 500 t.Errorf("File modified date is not equal for %q. Expected: %v, Actual: %v", 501 relpath, fd.modifiedDate, info.ModTime()) 502 } 503 if !info.IsDir() { 504 contentBytes, err := ioutil.ReadFile(path) 505 if err != nil { 506 t.Errorf("Error reading file %q: %v", path, err) 507 return err 508 } 509 content := string(contentBytes) 510 if content != fd.content { 511 t.Errorf("File content is not equal for %q. Expected: %q, Actual: %q", 512 relpath, fd.content, content) 513 } 514 } 515 if isSymLink(fd.mode) { 516 target, err := os.Readlink(path) 517 if err != nil { 518 t.Errorf("Error reading symlink %q: %v", path, err) 519 return err 520 } 521 if target != fd.target { 522 msg := "Symbolic link %q points to wrong path. Expected: %q, Actual: %q" 523 t.Errorf(msg, fd.name, fd.target, target) 524 } 525 } 526 } else if ld, ok := linksToVerify[relpath]; ok { 527 if isSymLink(info.Mode()) { 528 target, err := os.Readlink(path) 529 if err != nil { 530 t.Errorf("Error reading symlink %q: %v", path, err) 531 return err 532 } 533 if target != ld.fileName { 534 t.Errorf("Incorrect link location. Expected: %q, Actual %q", ld.fileName, target) 535 } 536 } else { 537 t.Errorf("Expected file %q to be a symlink", path) 538 } 539 } else { 540 t.Errorf("Unexpected file found: %q", relpath) 541 } 542 return nil 543 }) 544 if err != nil { 545 t.Fatalf("Error walking directory %q: %v", dir, err) 546 } 547 } 548 549 func TestExtractTarStream(t *testing.T) { 550 modificationDate := time.Date(2011, time.March, 5, 23, 30, 1, 0, time.UTC) 551 var symLinkMode os.FileMode = 0777 552 if runtime.GOOS == "darwin" { 553 // Symlinks show up as Lrwxr-xr-x on macOS 554 symLinkMode = 0755 555 } 556 testFiles := []fileDesc{ 557 {"dir01", modificationDate, 0700 | os.ModeDir, "", false, ""}, 558 {"dir01/.git", modificationDate, 0755 | os.ModeDir, "", false, ""}, 559 {"dir01/dir02", modificationDate, 0755 | os.ModeDir, "", false, ""}, 560 {"dir01/dir03", modificationDate, 0775 | os.ModeDir, "", false, ""}, 561 {"dir01/dir02/test1.txt", modificationDate, 0700, "Test1 file content", false, ""}, 562 {"dir01/test2.git", modificationDate, 0660, "Test2 file content", false, ""}, 563 {"dir01/dir03/test3.txt", modificationDate, 0444, "Test3 file content", false, ""}, 564 {"dir01/symlink", modificationDate, os.ModeSymlink | symLinkMode, "Test3 file content", false, "../dir01/dir03/test3.txt"}, 565 {"dir01/dir03/tëst3.txt", modificationDate, 0444, "utf-8 header file content", false, ""}, 566 } 567 reader, writer := io.Pipe() 568 destDir, err := ioutil.TempDir("", "testExtract") 569 if err != nil { 570 t.Fatalf("Cannot create temp directory: %v", err) 571 } 572 defer os.RemoveAll(destDir) 573 th := New(fs.NewFileSystem()) 574 575 go func() { 576 err := createTestTar(testFiles, writer) 577 if err != nil { 578 t.Fatalf("Error creating tar stream: %v", err) 579 } 580 writer.CloseWithError(err) 581 }() 582 th.ExtractTarStream(destDir, reader) 583 verifyDirectory(t, destDir, nil, testFiles, nil) 584 } 585 586 func TestExtractTarStreamTimeout(t *testing.T) { 587 reader, writer := io.Pipe() 588 destDir, err := ioutil.TempDir("", "testExtract") 589 if err != nil { 590 t.Fatalf("Cannot create temp directory: %v", err) 591 } 592 defer os.RemoveAll(destDir) 593 th := New(fs.NewFileSystem()) 594 th.(*stiTar).timeout = 5 * time.Millisecond 595 time.AfterFunc(30*time.Millisecond, func() { writer.Close() }) 596 err = th.ExtractTarStream(destDir, reader) 597 if e, ok := err.(s2ierr.Error); err == nil || (ok && e.ErrorCode != s2ierr.TarTimeoutError) { 598 t.Errorf("Did not get the expected timeout error. err = %v", err) 599 } 600 } 601 602 func TestRoundTripTar(t *testing.T) { 603 tarWriter := New(fs.NewFileSystem()) 604 tarReader := New(fs.NewFileSystem()) 605 tempDir, err := ioutil.TempDir("", "testtar") 606 defer os.RemoveAll(tempDir) 607 if err != nil { 608 t.Fatalf("Cannot create temp input directory for test: %v", err) 609 } 610 destDir, err := ioutil.TempDir("", "testExtract") 611 defer os.RemoveAll(destDir) 612 if err != nil { 613 t.Fatalf("Cannot create temp extract directory for test: %v", err) 614 } 615 modificationDate := time.Date(2011, time.March, 5, 23, 30, 1, 0, time.UTC) 616 testDirs := []dirDesc{ 617 {"dir01", modificationDate, 0700}, 618 {"dir01/.git", modificationDate, 0755}, 619 {"dir01/dir02", modificationDate, 0755}, 620 {"dir01/dir03", modificationDate, 0775}, 621 {"link", modificationDate, 0775}, 622 } 623 testFiles := []fileDesc{ 624 {"dir01/dir02/test1.txt", modificationDate, 0700, "Test1 file content", false, ""}, 625 {"dir01/test2.git", modificationDate, 0660, "Test2 file content", false, ""}, 626 {"dir01/dir03/test3.txt", modificationDate, 0444, "Test3 file content", false, ""}, 627 {"dir01/.git/hello.txt", modificationDate, 0600, "Ignore file content", true, ""}, 628 {"dir01/dir03/tëst3.txt", modificationDate, 0444, "Test utf-8 file header content", false, ""}, 629 } 630 testLinks := []linkDesc{ 631 {"link/okfilelink", "../dir01/dir02/test1.txt"}, 632 {"link/errfilelink", "../dir01/missing.target"}, 633 {"link/okdirlink", "../dir01/dir02"}, 634 {"link/okdirlink2", "../dir01/.git"}, 635 } 636 if err = createTestFiles(tempDir, testDirs, testFiles, testLinks); err != nil { 637 t.Fatalf("Cannot create test files: %v", err) 638 } 639 640 r, w := io.Pipe() 641 go func() { 642 writeErr := tarWriter.CreateTarStream(tempDir, false, w) 643 if writeErr != nil { 644 t.Errorf("Unable to create tar stream: %v", err) 645 } 646 w.CloseWithError(writeErr) 647 }() 648 649 err = tarReader.ExtractTarStream(destDir, r) 650 if err != nil { 651 t.Errorf("error extracting tar stream: %v", err) 652 } 653 verifyDirectory(t, destDir, testDirs, testFiles, testLinks) 654 }