github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/pkg/archive/archive_test.go (about) 1 package archive // import "github.com/docker/docker/pkg/archive" 2 3 import ( 4 "archive/tar" 5 "bytes" 6 "compress/gzip" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "reflect" 14 "runtime" 15 "strings" 16 "testing" 17 "time" 18 19 "github.com/docker/docker/pkg/idtools" 20 "github.com/docker/docker/pkg/ioutils" 21 "gotest.tools/assert" 22 is "gotest.tools/assert/cmp" 23 "gotest.tools/skip" 24 ) 25 26 var tmp string 27 28 func init() { 29 tmp = "/tmp/" 30 if runtime.GOOS == "windows" { 31 tmp = os.Getenv("TEMP") + `\` 32 } 33 } 34 35 var defaultArchiver = NewDefaultArchiver() 36 37 func defaultTarUntar(src, dst string) error { 38 return defaultArchiver.TarUntar(src, dst) 39 } 40 41 func defaultUntarPath(src, dst string) error { 42 return defaultArchiver.UntarPath(src, dst) 43 } 44 45 func defaultCopyFileWithTar(src, dst string) (err error) { 46 return defaultArchiver.CopyFileWithTar(src, dst) 47 } 48 49 func defaultCopyWithTar(src, dst string) error { 50 return defaultArchiver.CopyWithTar(src, dst) 51 } 52 53 func TestIsArchivePathDir(t *testing.T) { 54 cmd := exec.Command("sh", "-c", "mkdir -p /tmp/archivedir") 55 output, err := cmd.CombinedOutput() 56 if err != nil { 57 t.Fatalf("Fail to create an archive file for test : %s.", output) 58 } 59 if IsArchivePath(tmp + "archivedir") { 60 t.Fatalf("Incorrectly recognised directory as an archive") 61 } 62 } 63 64 func TestIsArchivePathInvalidFile(t *testing.T) { 65 cmd := exec.Command("sh", "-c", "dd if=/dev/zero bs=1024 count=1 of=/tmp/archive && gzip --stdout /tmp/archive > /tmp/archive.gz") 66 output, err := cmd.CombinedOutput() 67 if err != nil { 68 t.Fatalf("Fail to create an archive file for test : %s.", output) 69 } 70 if IsArchivePath(tmp + "archive") { 71 t.Fatalf("Incorrectly recognised invalid tar path as archive") 72 } 73 if IsArchivePath(tmp + "archive.gz") { 74 t.Fatalf("Incorrectly recognised invalid compressed tar path as archive") 75 } 76 } 77 78 func TestIsArchivePathTar(t *testing.T) { 79 whichTar := "tar" 80 cmdStr := fmt.Sprintf("touch /tmp/archivedata && %s -cf /tmp/archive /tmp/archivedata && gzip --stdout /tmp/archive > /tmp/archive.gz", whichTar) 81 cmd := exec.Command("sh", "-c", cmdStr) 82 output, err := cmd.CombinedOutput() 83 if err != nil { 84 t.Fatalf("Fail to create an archive file for test : %s.", output) 85 } 86 if !IsArchivePath(tmp + "/archive") { 87 t.Fatalf("Did not recognise valid tar path as archive") 88 } 89 if !IsArchivePath(tmp + "archive.gz") { 90 t.Fatalf("Did not recognise valid compressed tar path as archive") 91 } 92 } 93 94 func testDecompressStream(t *testing.T, ext, compressCommand string) io.Reader { 95 cmd := exec.Command("sh", "-c", 96 fmt.Sprintf("touch /tmp/archive && %s /tmp/archive", compressCommand)) 97 output, err := cmd.CombinedOutput() 98 if err != nil { 99 t.Fatalf("Failed to create an archive file for test : %s.", output) 100 } 101 filename := "archive." + ext 102 archive, err := os.Open(tmp + filename) 103 if err != nil { 104 t.Fatalf("Failed to open file %s: %v", filename, err) 105 } 106 defer archive.Close() 107 108 r, err := DecompressStream(archive) 109 if err != nil { 110 t.Fatalf("Failed to decompress %s: %v", filename, err) 111 } 112 if _, err = ioutil.ReadAll(r); err != nil { 113 t.Fatalf("Failed to read the decompressed stream: %v ", err) 114 } 115 if err = r.Close(); err != nil { 116 t.Fatalf("Failed to close the decompressed stream: %v ", err) 117 } 118 119 return r 120 } 121 122 func TestDecompressStreamGzip(t *testing.T) { 123 testDecompressStream(t, "gz", "gzip -f") 124 } 125 126 func TestDecompressStreamBzip2(t *testing.T) { 127 testDecompressStream(t, "bz2", "bzip2 -f") 128 } 129 130 func TestDecompressStreamXz(t *testing.T) { 131 if runtime.GOOS == "windows" { 132 t.Skip("Xz not present in msys2") 133 } 134 testDecompressStream(t, "xz", "xz -f") 135 } 136 137 func TestCompressStreamXzUnsupported(t *testing.T) { 138 dest, err := os.Create(tmp + "dest") 139 if err != nil { 140 t.Fatalf("Fail to create the destination file") 141 } 142 defer dest.Close() 143 144 _, err = CompressStream(dest, Xz) 145 if err == nil { 146 t.Fatalf("Should fail as xz is unsupported for compression format.") 147 } 148 } 149 150 func TestCompressStreamBzip2Unsupported(t *testing.T) { 151 dest, err := os.Create(tmp + "dest") 152 if err != nil { 153 t.Fatalf("Fail to create the destination file") 154 } 155 defer dest.Close() 156 157 _, err = CompressStream(dest, Bzip2) 158 if err == nil { 159 t.Fatalf("Should fail as bzip2 is unsupported for compression format.") 160 } 161 } 162 163 func TestCompressStreamInvalid(t *testing.T) { 164 dest, err := os.Create(tmp + "dest") 165 if err != nil { 166 t.Fatalf("Fail to create the destination file") 167 } 168 defer dest.Close() 169 170 _, err = CompressStream(dest, -1) 171 if err == nil { 172 t.Fatalf("Should fail as xz is unsupported for compression format.") 173 } 174 } 175 176 func TestExtensionInvalid(t *testing.T) { 177 compression := Compression(-1) 178 output := compression.Extension() 179 if output != "" { 180 t.Fatalf("The extension of an invalid compression should be an empty string.") 181 } 182 } 183 184 func TestExtensionUncompressed(t *testing.T) { 185 compression := Uncompressed 186 output := compression.Extension() 187 if output != "tar" { 188 t.Fatalf("The extension of an uncompressed archive should be 'tar'.") 189 } 190 } 191 func TestExtensionBzip2(t *testing.T) { 192 compression := Bzip2 193 output := compression.Extension() 194 if output != "tar.bz2" { 195 t.Fatalf("The extension of a bzip2 archive should be 'tar.bz2'") 196 } 197 } 198 func TestExtensionGzip(t *testing.T) { 199 compression := Gzip 200 output := compression.Extension() 201 if output != "tar.gz" { 202 t.Fatalf("The extension of a gzip archive should be 'tar.gz'") 203 } 204 } 205 func TestExtensionXz(t *testing.T) { 206 compression := Xz 207 output := compression.Extension() 208 if output != "tar.xz" { 209 t.Fatalf("The extension of a xz archive should be 'tar.xz'") 210 } 211 } 212 213 func TestCmdStreamLargeStderr(t *testing.T) { 214 cmd := exec.Command("sh", "-c", "dd if=/dev/zero bs=1k count=1000 of=/dev/stderr; echo hello") 215 out, err := cmdStream(cmd, nil) 216 if err != nil { 217 t.Fatalf("Failed to start command: %s", err) 218 } 219 errCh := make(chan error) 220 go func() { 221 _, err := io.Copy(ioutil.Discard, out) 222 errCh <- err 223 }() 224 select { 225 case err := <-errCh: 226 if err != nil { 227 t.Fatalf("Command should not have failed (err=%.100s...)", err) 228 } 229 case <-time.After(5 * time.Second): 230 t.Fatalf("Command did not complete in 5 seconds; probable deadlock") 231 } 232 } 233 234 func TestCmdStreamBad(t *testing.T) { 235 // TODO Windows: Figure out why this is failing in CI but not locally 236 if runtime.GOOS == "windows" { 237 t.Skip("Failing on Windows CI machines") 238 } 239 badCmd := exec.Command("sh", "-c", "echo hello; echo >&2 error couldn\\'t reverse the phase pulser; exit 1") 240 out, err := cmdStream(badCmd, nil) 241 if err != nil { 242 t.Fatalf("Failed to start command: %s", err) 243 } 244 if output, err := ioutil.ReadAll(out); err == nil { 245 t.Fatalf("Command should have failed") 246 } else if err.Error() != "exit status 1: error couldn't reverse the phase pulser\n" { 247 t.Fatalf("Wrong error value (%s)", err) 248 } else if s := string(output); s != "hello\n" { 249 t.Fatalf("Command output should be '%s', not '%s'", "hello\\n", output) 250 } 251 } 252 253 func TestCmdStreamGood(t *testing.T) { 254 cmd := exec.Command("sh", "-c", "echo hello; exit 0") 255 out, err := cmdStream(cmd, nil) 256 if err != nil { 257 t.Fatal(err) 258 } 259 if output, err := ioutil.ReadAll(out); err != nil { 260 t.Fatalf("Command should not have failed (err=%s)", err) 261 } else if s := string(output); s != "hello\n" { 262 t.Fatalf("Command output should be '%s', not '%s'", "hello\\n", output) 263 } 264 } 265 266 func TestUntarPathWithInvalidDest(t *testing.T) { 267 tempFolder, err := ioutil.TempDir("", "docker-archive-test") 268 assert.NilError(t, err) 269 defer os.RemoveAll(tempFolder) 270 invalidDestFolder := filepath.Join(tempFolder, "invalidDest") 271 // Create a src file 272 srcFile := filepath.Join(tempFolder, "src") 273 tarFile := filepath.Join(tempFolder, "src.tar") 274 os.Create(srcFile) 275 os.Create(invalidDestFolder) // being a file (not dir) should cause an error 276 277 // Translate back to Unix semantics as next exec.Command is run under sh 278 srcFileU := srcFile 279 tarFileU := tarFile 280 if runtime.GOOS == "windows" { 281 tarFileU = "/tmp/" + filepath.Base(filepath.Dir(tarFile)) + "/src.tar" 282 srcFileU = "/tmp/" + filepath.Base(filepath.Dir(srcFile)) + "/src" 283 } 284 285 cmd := exec.Command("sh", "-c", "tar cf "+tarFileU+" "+srcFileU) 286 _, err = cmd.CombinedOutput() 287 assert.NilError(t, err) 288 289 err = defaultUntarPath(tarFile, invalidDestFolder) 290 if err == nil { 291 t.Fatalf("UntarPath with invalid destination path should throw an error.") 292 } 293 } 294 295 func TestUntarPathWithInvalidSrc(t *testing.T) { 296 dest, err := ioutil.TempDir("", "docker-archive-test") 297 if err != nil { 298 t.Fatalf("Fail to create the destination file") 299 } 300 defer os.RemoveAll(dest) 301 err = defaultUntarPath("/invalid/path", dest) 302 if err == nil { 303 t.Fatalf("UntarPath with invalid src path should throw an error.") 304 } 305 } 306 307 func TestUntarPath(t *testing.T) { 308 skip.If(t, os.Getuid() != 0, "skipping test that requires root") 309 tmpFolder, err := ioutil.TempDir("", "docker-archive-test") 310 assert.NilError(t, err) 311 defer os.RemoveAll(tmpFolder) 312 srcFile := filepath.Join(tmpFolder, "src") 313 tarFile := filepath.Join(tmpFolder, "src.tar") 314 os.Create(filepath.Join(tmpFolder, "src")) 315 316 destFolder := filepath.Join(tmpFolder, "dest") 317 err = os.MkdirAll(destFolder, 0740) 318 if err != nil { 319 t.Fatalf("Fail to create the destination file") 320 } 321 322 // Translate back to Unix semantics as next exec.Command is run under sh 323 srcFileU := srcFile 324 tarFileU := tarFile 325 if runtime.GOOS == "windows" { 326 tarFileU = "/tmp/" + filepath.Base(filepath.Dir(tarFile)) + "/src.tar" 327 srcFileU = "/tmp/" + filepath.Base(filepath.Dir(srcFile)) + "/src" 328 } 329 cmd := exec.Command("sh", "-c", "tar cf "+tarFileU+" "+srcFileU) 330 _, err = cmd.CombinedOutput() 331 assert.NilError(t, err) 332 333 err = defaultUntarPath(tarFile, destFolder) 334 if err != nil { 335 t.Fatalf("UntarPath shouldn't throw an error, %s.", err) 336 } 337 expectedFile := filepath.Join(destFolder, srcFileU) 338 _, err = os.Stat(expectedFile) 339 if err != nil { 340 t.Fatalf("Destination folder should contain the source file but did not.") 341 } 342 } 343 344 // Do the same test as above but with the destination as file, it should fail 345 func TestUntarPathWithDestinationFile(t *testing.T) { 346 tmpFolder, err := ioutil.TempDir("", "docker-archive-test") 347 if err != nil { 348 t.Fatal(err) 349 } 350 defer os.RemoveAll(tmpFolder) 351 srcFile := filepath.Join(tmpFolder, "src") 352 tarFile := filepath.Join(tmpFolder, "src.tar") 353 os.Create(filepath.Join(tmpFolder, "src")) 354 355 // Translate back to Unix semantics as next exec.Command is run under sh 356 srcFileU := srcFile 357 tarFileU := tarFile 358 if runtime.GOOS == "windows" { 359 tarFileU = "/tmp/" + filepath.Base(filepath.Dir(tarFile)) + "/src.tar" 360 srcFileU = "/tmp/" + filepath.Base(filepath.Dir(srcFile)) + "/src" 361 } 362 cmd := exec.Command("sh", "-c", "tar cf "+tarFileU+" "+srcFileU) 363 _, err = cmd.CombinedOutput() 364 if err != nil { 365 t.Fatal(err) 366 } 367 destFile := filepath.Join(tmpFolder, "dest") 368 _, err = os.Create(destFile) 369 if err != nil { 370 t.Fatalf("Fail to create the destination file") 371 } 372 err = defaultUntarPath(tarFile, destFile) 373 if err == nil { 374 t.Fatalf("UntarPath should throw an error if the destination if a file") 375 } 376 } 377 378 // Do the same test as above but with the destination folder already exists 379 // and the destination file is a directory 380 // It's working, see https://github.com/docker/docker/issues/10040 381 func TestUntarPathWithDestinationSrcFileAsFolder(t *testing.T) { 382 tmpFolder, err := ioutil.TempDir("", "docker-archive-test") 383 if err != nil { 384 t.Fatal(err) 385 } 386 defer os.RemoveAll(tmpFolder) 387 srcFile := filepath.Join(tmpFolder, "src") 388 tarFile := filepath.Join(tmpFolder, "src.tar") 389 os.Create(srcFile) 390 391 // Translate back to Unix semantics as next exec.Command is run under sh 392 srcFileU := srcFile 393 tarFileU := tarFile 394 if runtime.GOOS == "windows" { 395 tarFileU = "/tmp/" + filepath.Base(filepath.Dir(tarFile)) + "/src.tar" 396 srcFileU = "/tmp/" + filepath.Base(filepath.Dir(srcFile)) + "/src" 397 } 398 399 cmd := exec.Command("sh", "-c", "tar cf "+tarFileU+" "+srcFileU) 400 _, err = cmd.CombinedOutput() 401 if err != nil { 402 t.Fatal(err) 403 } 404 destFolder := filepath.Join(tmpFolder, "dest") 405 err = os.MkdirAll(destFolder, 0740) 406 if err != nil { 407 t.Fatalf("Fail to create the destination folder") 408 } 409 // Let's create a folder that will has the same path as the extracted file (from tar) 410 destSrcFileAsFolder := filepath.Join(destFolder, srcFileU) 411 err = os.MkdirAll(destSrcFileAsFolder, 0740) 412 if err != nil { 413 t.Fatal(err) 414 } 415 err = defaultUntarPath(tarFile, destFolder) 416 if err != nil { 417 t.Fatalf("UntarPath should throw not throw an error if the extracted file already exists and is a folder") 418 } 419 } 420 421 func TestCopyWithTarInvalidSrc(t *testing.T) { 422 tempFolder, err := ioutil.TempDir("", "docker-archive-test") 423 if err != nil { 424 t.Fatal(nil) 425 } 426 destFolder := filepath.Join(tempFolder, "dest") 427 invalidSrc := filepath.Join(tempFolder, "doesnotexists") 428 err = os.MkdirAll(destFolder, 0740) 429 if err != nil { 430 t.Fatal(err) 431 } 432 err = defaultCopyWithTar(invalidSrc, destFolder) 433 if err == nil { 434 t.Fatalf("archiver.CopyWithTar with invalid src path should throw an error.") 435 } 436 } 437 438 func TestCopyWithTarInexistentDestWillCreateIt(t *testing.T) { 439 skip.If(t, os.Getuid() != 0, "skipping test that requires root") 440 tempFolder, err := ioutil.TempDir("", "docker-archive-test") 441 if err != nil { 442 t.Fatal(nil) 443 } 444 srcFolder := filepath.Join(tempFolder, "src") 445 inexistentDestFolder := filepath.Join(tempFolder, "doesnotexists") 446 err = os.MkdirAll(srcFolder, 0740) 447 if err != nil { 448 t.Fatal(err) 449 } 450 err = defaultCopyWithTar(srcFolder, inexistentDestFolder) 451 if err != nil { 452 t.Fatalf("CopyWithTar with an inexistent folder shouldn't fail.") 453 } 454 _, err = os.Stat(inexistentDestFolder) 455 if err != nil { 456 t.Fatalf("CopyWithTar with an inexistent folder should create it.") 457 } 458 } 459 460 // Test CopyWithTar with a file as src 461 func TestCopyWithTarSrcFile(t *testing.T) { 462 folder, err := ioutil.TempDir("", "docker-archive-test") 463 if err != nil { 464 t.Fatal(err) 465 } 466 defer os.RemoveAll(folder) 467 dest := filepath.Join(folder, "dest") 468 srcFolder := filepath.Join(folder, "src") 469 src := filepath.Join(folder, filepath.Join("src", "src")) 470 err = os.MkdirAll(srcFolder, 0740) 471 if err != nil { 472 t.Fatal(err) 473 } 474 err = os.MkdirAll(dest, 0740) 475 if err != nil { 476 t.Fatal(err) 477 } 478 ioutil.WriteFile(src, []byte("content"), 0777) 479 err = defaultCopyWithTar(src, dest) 480 if err != nil { 481 t.Fatalf("archiver.CopyWithTar shouldn't throw an error, %s.", err) 482 } 483 _, err = os.Stat(dest) 484 // FIXME Check the content 485 if err != nil { 486 t.Fatalf("Destination file should be the same as the source.") 487 } 488 } 489 490 // Test CopyWithTar with a folder as src 491 func TestCopyWithTarSrcFolder(t *testing.T) { 492 folder, err := ioutil.TempDir("", "docker-archive-test") 493 if err != nil { 494 t.Fatal(err) 495 } 496 defer os.RemoveAll(folder) 497 dest := filepath.Join(folder, "dest") 498 src := filepath.Join(folder, filepath.Join("src", "folder")) 499 err = os.MkdirAll(src, 0740) 500 if err != nil { 501 t.Fatal(err) 502 } 503 err = os.MkdirAll(dest, 0740) 504 if err != nil { 505 t.Fatal(err) 506 } 507 ioutil.WriteFile(filepath.Join(src, "file"), []byte("content"), 0777) 508 err = defaultCopyWithTar(src, dest) 509 if err != nil { 510 t.Fatalf("archiver.CopyWithTar shouldn't throw an error, %s.", err) 511 } 512 _, err = os.Stat(dest) 513 // FIXME Check the content (the file inside) 514 if err != nil { 515 t.Fatalf("Destination folder should contain the source file but did not.") 516 } 517 } 518 519 func TestCopyFileWithTarInvalidSrc(t *testing.T) { 520 tempFolder, err := ioutil.TempDir("", "docker-archive-test") 521 if err != nil { 522 t.Fatal(err) 523 } 524 defer os.RemoveAll(tempFolder) 525 destFolder := filepath.Join(tempFolder, "dest") 526 err = os.MkdirAll(destFolder, 0740) 527 if err != nil { 528 t.Fatal(err) 529 } 530 invalidFile := filepath.Join(tempFolder, "doesnotexists") 531 err = defaultCopyFileWithTar(invalidFile, destFolder) 532 if err == nil { 533 t.Fatalf("archiver.CopyWithTar with invalid src path should throw an error.") 534 } 535 } 536 537 func TestCopyFileWithTarInexistentDestWillCreateIt(t *testing.T) { 538 tempFolder, err := ioutil.TempDir("", "docker-archive-test") 539 if err != nil { 540 t.Fatal(nil) 541 } 542 defer os.RemoveAll(tempFolder) 543 srcFile := filepath.Join(tempFolder, "src") 544 inexistentDestFolder := filepath.Join(tempFolder, "doesnotexists") 545 _, err = os.Create(srcFile) 546 if err != nil { 547 t.Fatal(err) 548 } 549 err = defaultCopyFileWithTar(srcFile, inexistentDestFolder) 550 if err != nil { 551 t.Fatalf("CopyWithTar with an inexistent folder shouldn't fail.") 552 } 553 _, err = os.Stat(inexistentDestFolder) 554 if err != nil { 555 t.Fatalf("CopyWithTar with an inexistent folder should create it.") 556 } 557 // FIXME Test the src file and content 558 } 559 560 func TestCopyFileWithTarSrcFolder(t *testing.T) { 561 folder, err := ioutil.TempDir("", "docker-archive-copyfilewithtar-test") 562 if err != nil { 563 t.Fatal(err) 564 } 565 defer os.RemoveAll(folder) 566 dest := filepath.Join(folder, "dest") 567 src := filepath.Join(folder, "srcfolder") 568 err = os.MkdirAll(src, 0740) 569 if err != nil { 570 t.Fatal(err) 571 } 572 err = os.MkdirAll(dest, 0740) 573 if err != nil { 574 t.Fatal(err) 575 } 576 err = defaultCopyFileWithTar(src, dest) 577 if err == nil { 578 t.Fatalf("CopyFileWithTar should throw an error with a folder.") 579 } 580 } 581 582 func TestCopyFileWithTarSrcFile(t *testing.T) { 583 folder, err := ioutil.TempDir("", "docker-archive-test") 584 if err != nil { 585 t.Fatal(err) 586 } 587 defer os.RemoveAll(folder) 588 dest := filepath.Join(folder, "dest") 589 srcFolder := filepath.Join(folder, "src") 590 src := filepath.Join(folder, filepath.Join("src", "src")) 591 err = os.MkdirAll(srcFolder, 0740) 592 if err != nil { 593 t.Fatal(err) 594 } 595 err = os.MkdirAll(dest, 0740) 596 if err != nil { 597 t.Fatal(err) 598 } 599 ioutil.WriteFile(src, []byte("content"), 0777) 600 err = defaultCopyWithTar(src, dest+"/") 601 if err != nil { 602 t.Fatalf("archiver.CopyFileWithTar shouldn't throw an error, %s.", err) 603 } 604 _, err = os.Stat(dest) 605 if err != nil { 606 t.Fatalf("Destination folder should contain the source file but did not.") 607 } 608 } 609 610 func TestTarFiles(t *testing.T) { 611 // TODO Windows: Figure out how to port this test. 612 if runtime.GOOS == "windows" { 613 t.Skip("Failing on Windows") 614 } 615 // try without hardlinks 616 if err := checkNoChanges(1000, false); err != nil { 617 t.Fatal(err) 618 } 619 // try with hardlinks 620 if err := checkNoChanges(1000, true); err != nil { 621 t.Fatal(err) 622 } 623 } 624 625 func checkNoChanges(fileNum int, hardlinks bool) error { 626 srcDir, err := ioutil.TempDir("", "docker-test-srcDir") 627 if err != nil { 628 return err 629 } 630 defer os.RemoveAll(srcDir) 631 632 destDir, err := ioutil.TempDir("", "docker-test-destDir") 633 if err != nil { 634 return err 635 } 636 defer os.RemoveAll(destDir) 637 638 _, err = prepareUntarSourceDirectory(fileNum, srcDir, hardlinks) 639 if err != nil { 640 return err 641 } 642 643 err = defaultTarUntar(srcDir, destDir) 644 if err != nil { 645 return err 646 } 647 648 changes, err := ChangesDirs(destDir, srcDir) 649 if err != nil { 650 return err 651 } 652 if len(changes) > 0 { 653 return fmt.Errorf("with %d files and %v hardlinks: expected 0 changes, got %d", fileNum, hardlinks, len(changes)) 654 } 655 return nil 656 } 657 658 func tarUntar(t *testing.T, origin string, options *TarOptions) ([]Change, error) { 659 archive, err := TarWithOptions(origin, options) 660 if err != nil { 661 t.Fatal(err) 662 } 663 defer archive.Close() 664 665 buf := make([]byte, 10) 666 if _, err := archive.Read(buf); err != nil { 667 return nil, err 668 } 669 wrap := io.MultiReader(bytes.NewReader(buf), archive) 670 671 detectedCompression := DetectCompression(buf) 672 compression := options.Compression 673 if detectedCompression.Extension() != compression.Extension() { 674 return nil, fmt.Errorf("Wrong compression detected. Actual compression: %s, found %s", compression.Extension(), detectedCompression.Extension()) 675 } 676 677 tmp, err := ioutil.TempDir("", "docker-test-untar") 678 if err != nil { 679 return nil, err 680 } 681 defer os.RemoveAll(tmp) 682 if err := Untar(wrap, tmp, nil); err != nil { 683 return nil, err 684 } 685 if _, err := os.Stat(tmp); err != nil { 686 return nil, err 687 } 688 689 return ChangesDirs(origin, tmp) 690 } 691 692 func TestTarUntar(t *testing.T) { 693 // TODO Windows: Figure out how to fix this test. 694 if runtime.GOOS == "windows" { 695 t.Skip("Failing on Windows") 696 } 697 origin, err := ioutil.TempDir("", "docker-test-untar-origin") 698 if err != nil { 699 t.Fatal(err) 700 } 701 defer os.RemoveAll(origin) 702 if err := ioutil.WriteFile(filepath.Join(origin, "1"), []byte("hello world"), 0700); err != nil { 703 t.Fatal(err) 704 } 705 if err := ioutil.WriteFile(filepath.Join(origin, "2"), []byte("welcome!"), 0700); err != nil { 706 t.Fatal(err) 707 } 708 if err := ioutil.WriteFile(filepath.Join(origin, "3"), []byte("will be ignored"), 0700); err != nil { 709 t.Fatal(err) 710 } 711 712 for _, c := range []Compression{ 713 Uncompressed, 714 Gzip, 715 } { 716 changes, err := tarUntar(t, origin, &TarOptions{ 717 Compression: c, 718 ExcludePatterns: []string{"3"}, 719 }) 720 721 if err != nil { 722 t.Fatalf("Error tar/untar for compression %s: %s", c.Extension(), err) 723 } 724 725 if len(changes) != 1 || changes[0].Path != "/3" { 726 t.Fatalf("Unexpected differences after tarUntar: %v", changes) 727 } 728 } 729 } 730 731 func TestTarWithOptionsChownOptsAlwaysOverridesIdPair(t *testing.T) { 732 origin, err := ioutil.TempDir("", "docker-test-tar-chown-opt") 733 assert.NilError(t, err) 734 735 defer os.RemoveAll(origin) 736 filePath := filepath.Join(origin, "1") 737 err = ioutil.WriteFile(filePath, []byte("hello world"), 0700) 738 assert.NilError(t, err) 739 740 idMaps := []idtools.IDMap{ 741 0: { 742 ContainerID: 0, 743 HostID: 0, 744 Size: 65536, 745 }, 746 1: { 747 ContainerID: 0, 748 HostID: 100000, 749 Size: 65536, 750 }, 751 } 752 753 cases := []struct { 754 opts *TarOptions 755 expectedUID int 756 expectedGID int 757 }{ 758 {&TarOptions{ChownOpts: &idtools.Identity{UID: 1337, GID: 42}}, 1337, 42}, 759 {&TarOptions{ChownOpts: &idtools.Identity{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001}, 760 {&TarOptions{ChownOpts: &idtools.Identity{UID: 0, GID: 0}, NoLchown: false}, 0, 0}, 761 {&TarOptions{ChownOpts: &idtools.Identity{UID: 1, GID: 1}, NoLchown: true}, 1, 1}, 762 {&TarOptions{ChownOpts: &idtools.Identity{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000}, 763 } 764 for _, testCase := range cases { 765 reader, err := TarWithOptions(filePath, testCase.opts) 766 assert.NilError(t, err) 767 tr := tar.NewReader(reader) 768 defer reader.Close() 769 for { 770 hdr, err := tr.Next() 771 if err == io.EOF { 772 // end of tar archive 773 break 774 } 775 assert.NilError(t, err) 776 assert.Check(t, is.Equal(hdr.Uid, testCase.expectedUID), "Uid equals expected value") 777 assert.Check(t, is.Equal(hdr.Gid, testCase.expectedGID), "Gid equals expected value") 778 } 779 } 780 } 781 782 func TestTarWithOptions(t *testing.T) { 783 // TODO Windows: Figure out how to fix this test. 784 if runtime.GOOS == "windows" { 785 t.Skip("Failing on Windows") 786 } 787 origin, err := ioutil.TempDir("", "docker-test-untar-origin") 788 if err != nil { 789 t.Fatal(err) 790 } 791 if _, err := ioutil.TempDir(origin, "folder"); err != nil { 792 t.Fatal(err) 793 } 794 defer os.RemoveAll(origin) 795 if err := ioutil.WriteFile(filepath.Join(origin, "1"), []byte("hello world"), 0700); err != nil { 796 t.Fatal(err) 797 } 798 if err := ioutil.WriteFile(filepath.Join(origin, "2"), []byte("welcome!"), 0700); err != nil { 799 t.Fatal(err) 800 } 801 802 cases := []struct { 803 opts *TarOptions 804 numChanges int 805 }{ 806 {&TarOptions{IncludeFiles: []string{"1"}}, 2}, 807 {&TarOptions{ExcludePatterns: []string{"2"}}, 1}, 808 {&TarOptions{ExcludePatterns: []string{"1", "folder*"}}, 2}, 809 {&TarOptions{IncludeFiles: []string{"1", "1"}}, 2}, 810 {&TarOptions{IncludeFiles: []string{"1"}, RebaseNames: map[string]string{"1": "test"}}, 4}, 811 } 812 for _, testCase := range cases { 813 changes, err := tarUntar(t, origin, testCase.opts) 814 if err != nil { 815 t.Fatalf("Error tar/untar when testing inclusion/exclusion: %s", err) 816 } 817 if len(changes) != testCase.numChanges { 818 t.Errorf("Expected %d changes, got %d for %+v:", 819 testCase.numChanges, len(changes), testCase.opts) 820 } 821 } 822 } 823 824 // Some tar archives such as http://haproxy.1wt.eu/download/1.5/src/devel/haproxy-1.5-dev21.tar.gz 825 // use PAX Global Extended Headers. 826 // Failing prevents the archives from being uncompressed during ADD 827 func TestTypeXGlobalHeaderDoesNotFail(t *testing.T) { 828 hdr := tar.Header{Typeflag: tar.TypeXGlobalHeader} 829 tmpDir, err := ioutil.TempDir("", "docker-test-archive-pax-test") 830 if err != nil { 831 t.Fatal(err) 832 } 833 defer os.RemoveAll(tmpDir) 834 err = createTarFile(filepath.Join(tmpDir, "pax_global_header"), tmpDir, &hdr, nil, true, nil, false) 835 if err != nil { 836 t.Fatal(err) 837 } 838 } 839 840 // Some tar have both GNU specific (huge uid) and Ustar specific (long name) things. 841 // Not supposed to happen (should use PAX instead of Ustar for long name) but it does and it should still work. 842 func TestUntarUstarGnuConflict(t *testing.T) { 843 f, err := os.Open("testdata/broken.tar") 844 if err != nil { 845 t.Fatal(err) 846 } 847 defer f.Close() 848 849 found := false 850 tr := tar.NewReader(f) 851 // Iterate through the files in the archive. 852 for { 853 hdr, err := tr.Next() 854 if err == io.EOF { 855 // end of tar archive 856 break 857 } 858 if err != nil { 859 t.Fatal(err) 860 } 861 if hdr.Name == "root/.cpanm/work/1395823785.24209/Plack-1.0030/blib/man3/Plack::Middleware::LighttpdScriptNameFix.3pm" { 862 found = true 863 break 864 } 865 } 866 if !found { 867 t.Fatalf("%s not found in the archive", "root/.cpanm/work/1395823785.24209/Plack-1.0030/blib/man3/Plack::Middleware::LighttpdScriptNameFix.3pm") 868 } 869 } 870 871 func prepareUntarSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) { 872 fileData := []byte("fooo") 873 for n := 0; n < numberOfFiles; n++ { 874 fileName := fmt.Sprintf("file-%d", n) 875 if err := ioutil.WriteFile(filepath.Join(targetPath, fileName), fileData, 0700); err != nil { 876 return 0, err 877 } 878 if makeLinks { 879 if err := os.Link(filepath.Join(targetPath, fileName), filepath.Join(targetPath, fileName+"-link")); err != nil { 880 return 0, err 881 } 882 } 883 } 884 totalSize := numberOfFiles * len(fileData) 885 return totalSize, nil 886 } 887 888 func BenchmarkTarUntar(b *testing.B) { 889 origin, err := ioutil.TempDir("", "docker-test-untar-origin") 890 if err != nil { 891 b.Fatal(err) 892 } 893 tempDir, err := ioutil.TempDir("", "docker-test-untar-destination") 894 if err != nil { 895 b.Fatal(err) 896 } 897 target := filepath.Join(tempDir, "dest") 898 n, err := prepareUntarSourceDirectory(100, origin, false) 899 if err != nil { 900 b.Fatal(err) 901 } 902 defer os.RemoveAll(origin) 903 defer os.RemoveAll(tempDir) 904 905 b.ResetTimer() 906 b.SetBytes(int64(n)) 907 for n := 0; n < b.N; n++ { 908 err := defaultTarUntar(origin, target) 909 if err != nil { 910 b.Fatal(err) 911 } 912 os.RemoveAll(target) 913 } 914 } 915 916 func BenchmarkTarUntarWithLinks(b *testing.B) { 917 origin, err := ioutil.TempDir("", "docker-test-untar-origin") 918 if err != nil { 919 b.Fatal(err) 920 } 921 tempDir, err := ioutil.TempDir("", "docker-test-untar-destination") 922 if err != nil { 923 b.Fatal(err) 924 } 925 target := filepath.Join(tempDir, "dest") 926 n, err := prepareUntarSourceDirectory(100, origin, true) 927 if err != nil { 928 b.Fatal(err) 929 } 930 defer os.RemoveAll(origin) 931 defer os.RemoveAll(tempDir) 932 933 b.ResetTimer() 934 b.SetBytes(int64(n)) 935 for n := 0; n < b.N; n++ { 936 err := defaultTarUntar(origin, target) 937 if err != nil { 938 b.Fatal(err) 939 } 940 os.RemoveAll(target) 941 } 942 } 943 944 func TestUntarInvalidFilenames(t *testing.T) { 945 // TODO Windows: Figure out how to fix this test. 946 if runtime.GOOS == "windows" { 947 t.Skip("Passes but hits breakoutError: platform and architecture is not supported") 948 } 949 for i, headers := range [][]*tar.Header{ 950 { 951 { 952 Name: "../victim/dotdot", 953 Typeflag: tar.TypeReg, 954 Mode: 0644, 955 }, 956 }, 957 { 958 { 959 // Note the leading slash 960 Name: "/../victim/slash-dotdot", 961 Typeflag: tar.TypeReg, 962 Mode: 0644, 963 }, 964 }, 965 } { 966 if err := testBreakout("untar", "docker-TestUntarInvalidFilenames", headers); err != nil { 967 t.Fatalf("i=%d. %v", i, err) 968 } 969 } 970 } 971 972 func TestUntarHardlinkToSymlink(t *testing.T) { 973 // TODO Windows. There may be a way of running this, but turning off for now 974 skip.If(t, runtime.GOOS == "windows", "hardlinks on Windows") 975 skip.If(t, os.Getuid() != 0, "skipping test that requires root") 976 for i, headers := range [][]*tar.Header{ 977 { 978 { 979 Name: "symlink1", 980 Typeflag: tar.TypeSymlink, 981 Linkname: "regfile", 982 Mode: 0644, 983 }, 984 { 985 Name: "symlink2", 986 Typeflag: tar.TypeLink, 987 Linkname: "symlink1", 988 Mode: 0644, 989 }, 990 { 991 Name: "regfile", 992 Typeflag: tar.TypeReg, 993 Mode: 0644, 994 }, 995 }, 996 } { 997 if err := testBreakout("untar", "docker-TestUntarHardlinkToSymlink", headers); err != nil { 998 t.Fatalf("i=%d. %v", i, err) 999 } 1000 } 1001 } 1002 1003 func TestUntarInvalidHardlink(t *testing.T) { 1004 // TODO Windows. There may be a way of running this, but turning off for now 1005 if runtime.GOOS == "windows" { 1006 t.Skip("hardlinks on Windows") 1007 } 1008 for i, headers := range [][]*tar.Header{ 1009 { // try reading victim/hello (../) 1010 { 1011 Name: "dotdot", 1012 Typeflag: tar.TypeLink, 1013 Linkname: "../victim/hello", 1014 Mode: 0644, 1015 }, 1016 }, 1017 { // try reading victim/hello (/../) 1018 { 1019 Name: "slash-dotdot", 1020 Typeflag: tar.TypeLink, 1021 // Note the leading slash 1022 Linkname: "/../victim/hello", 1023 Mode: 0644, 1024 }, 1025 }, 1026 { // try writing victim/file 1027 { 1028 Name: "loophole-victim", 1029 Typeflag: tar.TypeLink, 1030 Linkname: "../victim", 1031 Mode: 0755, 1032 }, 1033 { 1034 Name: "loophole-victim/file", 1035 Typeflag: tar.TypeReg, 1036 Mode: 0644, 1037 }, 1038 }, 1039 { // try reading victim/hello (hardlink, symlink) 1040 { 1041 Name: "loophole-victim", 1042 Typeflag: tar.TypeLink, 1043 Linkname: "../victim", 1044 Mode: 0755, 1045 }, 1046 { 1047 Name: "symlink", 1048 Typeflag: tar.TypeSymlink, 1049 Linkname: "loophole-victim/hello", 1050 Mode: 0644, 1051 }, 1052 }, 1053 { // Try reading victim/hello (hardlink, hardlink) 1054 { 1055 Name: "loophole-victim", 1056 Typeflag: tar.TypeLink, 1057 Linkname: "../victim", 1058 Mode: 0755, 1059 }, 1060 { 1061 Name: "hardlink", 1062 Typeflag: tar.TypeLink, 1063 Linkname: "loophole-victim/hello", 1064 Mode: 0644, 1065 }, 1066 }, 1067 { // Try removing victim directory (hardlink) 1068 { 1069 Name: "loophole-victim", 1070 Typeflag: tar.TypeLink, 1071 Linkname: "../victim", 1072 Mode: 0755, 1073 }, 1074 { 1075 Name: "loophole-victim", 1076 Typeflag: tar.TypeReg, 1077 Mode: 0644, 1078 }, 1079 }, 1080 } { 1081 if err := testBreakout("untar", "docker-TestUntarInvalidHardlink", headers); err != nil { 1082 t.Fatalf("i=%d. %v", i, err) 1083 } 1084 } 1085 } 1086 1087 func TestUntarInvalidSymlink(t *testing.T) { 1088 // TODO Windows. There may be a way of running this, but turning off for now 1089 if runtime.GOOS == "windows" { 1090 t.Skip("hardlinks on Windows") 1091 } 1092 for i, headers := range [][]*tar.Header{ 1093 { // try reading victim/hello (../) 1094 { 1095 Name: "dotdot", 1096 Typeflag: tar.TypeSymlink, 1097 Linkname: "../victim/hello", 1098 Mode: 0644, 1099 }, 1100 }, 1101 { // try reading victim/hello (/../) 1102 { 1103 Name: "slash-dotdot", 1104 Typeflag: tar.TypeSymlink, 1105 // Note the leading slash 1106 Linkname: "/../victim/hello", 1107 Mode: 0644, 1108 }, 1109 }, 1110 { // try writing victim/file 1111 { 1112 Name: "loophole-victim", 1113 Typeflag: tar.TypeSymlink, 1114 Linkname: "../victim", 1115 Mode: 0755, 1116 }, 1117 { 1118 Name: "loophole-victim/file", 1119 Typeflag: tar.TypeReg, 1120 Mode: 0644, 1121 }, 1122 }, 1123 { // try reading victim/hello (symlink, symlink) 1124 { 1125 Name: "loophole-victim", 1126 Typeflag: tar.TypeSymlink, 1127 Linkname: "../victim", 1128 Mode: 0755, 1129 }, 1130 { 1131 Name: "symlink", 1132 Typeflag: tar.TypeSymlink, 1133 Linkname: "loophole-victim/hello", 1134 Mode: 0644, 1135 }, 1136 }, 1137 { // try reading victim/hello (symlink, hardlink) 1138 { 1139 Name: "loophole-victim", 1140 Typeflag: tar.TypeSymlink, 1141 Linkname: "../victim", 1142 Mode: 0755, 1143 }, 1144 { 1145 Name: "hardlink", 1146 Typeflag: tar.TypeLink, 1147 Linkname: "loophole-victim/hello", 1148 Mode: 0644, 1149 }, 1150 }, 1151 { // try removing victim directory (symlink) 1152 { 1153 Name: "loophole-victim", 1154 Typeflag: tar.TypeSymlink, 1155 Linkname: "../victim", 1156 Mode: 0755, 1157 }, 1158 { 1159 Name: "loophole-victim", 1160 Typeflag: tar.TypeReg, 1161 Mode: 0644, 1162 }, 1163 }, 1164 { // try writing to victim/newdir/newfile with a symlink in the path 1165 { 1166 // this header needs to be before the next one, or else there is an error 1167 Name: "dir/loophole", 1168 Typeflag: tar.TypeSymlink, 1169 Linkname: "../../victim", 1170 Mode: 0755, 1171 }, 1172 { 1173 Name: "dir/loophole/newdir/newfile", 1174 Typeflag: tar.TypeReg, 1175 Mode: 0644, 1176 }, 1177 }, 1178 } { 1179 if err := testBreakout("untar", "docker-TestUntarInvalidSymlink", headers); err != nil { 1180 t.Fatalf("i=%d. %v", i, err) 1181 } 1182 } 1183 } 1184 1185 func TestTempArchiveCloseMultipleTimes(t *testing.T) { 1186 reader := ioutil.NopCloser(strings.NewReader("hello")) 1187 tempArchive, err := NewTempArchive(reader, "") 1188 assert.NilError(t, err) 1189 buf := make([]byte, 10) 1190 n, err := tempArchive.Read(buf) 1191 assert.NilError(t, err) 1192 if n != 5 { 1193 t.Fatalf("Expected to read 5 bytes. Read %d instead", n) 1194 } 1195 for i := 0; i < 3; i++ { 1196 if err = tempArchive.Close(); err != nil { 1197 t.Fatalf("i=%d. Unexpected error closing temp archive: %v", i, err) 1198 } 1199 } 1200 } 1201 1202 func TestReplaceFileTarWrapper(t *testing.T) { 1203 filesInArchive := 20 1204 testcases := []struct { 1205 doc string 1206 filename string 1207 modifier TarModifierFunc 1208 expected string 1209 fileCount int 1210 }{ 1211 { 1212 doc: "Modifier creates a new file", 1213 filename: "newfile", 1214 modifier: createModifier(t), 1215 expected: "the new content", 1216 fileCount: filesInArchive + 1, 1217 }, 1218 { 1219 doc: "Modifier replaces a file", 1220 filename: "file-2", 1221 modifier: createOrReplaceModifier, 1222 expected: "the new content", 1223 fileCount: filesInArchive, 1224 }, 1225 { 1226 doc: "Modifier replaces the last file", 1227 filename: fmt.Sprintf("file-%d", filesInArchive-1), 1228 modifier: createOrReplaceModifier, 1229 expected: "the new content", 1230 fileCount: filesInArchive, 1231 }, 1232 { 1233 doc: "Modifier appends to a file", 1234 filename: "file-3", 1235 modifier: appendModifier, 1236 expected: "fooo\nnext line", 1237 fileCount: filesInArchive, 1238 }, 1239 } 1240 1241 for _, testcase := range testcases { 1242 sourceArchive, cleanup := buildSourceArchive(t, filesInArchive) 1243 defer cleanup() 1244 1245 resultArchive := ReplaceFileTarWrapper( 1246 sourceArchive, 1247 map[string]TarModifierFunc{testcase.filename: testcase.modifier}) 1248 1249 actual := readFileFromArchive(t, resultArchive, testcase.filename, testcase.fileCount, testcase.doc) 1250 assert.Check(t, is.Equal(testcase.expected, actual), testcase.doc) 1251 } 1252 } 1253 1254 // TestPrefixHeaderReadable tests that files that could be created with the 1255 // version of this package that was built with <=go17 are still readable. 1256 func TestPrefixHeaderReadable(t *testing.T) { 1257 skip.If(t, os.Getuid() != 0, "skipping test that requires root") 1258 // https://gist.github.com/stevvooe/e2a790ad4e97425896206c0816e1a882#file-out-go 1259 var testFile = []byte("\x1f\x8b\x08\x08\x44\x21\x68\x59\x00\x03\x74\x2e\x74\x61\x72\x00\x4b\xcb\xcf\x67\xa0\x35\x30\x80\x00\x86\x06\x10\x47\x01\xc1\x37\x40\x00\x54\xb6\xb1\xa1\xa9\x99\x09\x48\x25\x1d\x40\x69\x71\x49\x62\x91\x02\xe5\x76\xa1\x79\x84\x21\x91\xd6\x80\x72\xaf\x8f\x82\x51\x30\x0a\x46\x36\x00\x00\xf0\x1c\x1e\x95\x00\x06\x00\x00") 1260 1261 tmpDir, err := ioutil.TempDir("", "prefix-test") 1262 assert.NilError(t, err) 1263 defer os.RemoveAll(tmpDir) 1264 err = Untar(bytes.NewReader(testFile), tmpDir, nil) 1265 assert.NilError(t, err) 1266 1267 baseName := "foo" 1268 pth := strings.Repeat("a", 100-len(baseName)) + "/" + baseName 1269 1270 _, err = os.Lstat(filepath.Join(tmpDir, pth)) 1271 assert.NilError(t, err) 1272 } 1273 1274 func buildSourceArchive(t *testing.T, numberOfFiles int) (io.ReadCloser, func()) { 1275 srcDir, err := ioutil.TempDir("", "docker-test-srcDir") 1276 assert.NilError(t, err) 1277 1278 _, err = prepareUntarSourceDirectory(numberOfFiles, srcDir, false) 1279 assert.NilError(t, err) 1280 1281 sourceArchive, err := TarWithOptions(srcDir, &TarOptions{}) 1282 assert.NilError(t, err) 1283 return sourceArchive, func() { 1284 os.RemoveAll(srcDir) 1285 sourceArchive.Close() 1286 } 1287 } 1288 1289 func createOrReplaceModifier(path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) { 1290 return &tar.Header{ 1291 Mode: 0600, 1292 Typeflag: tar.TypeReg, 1293 }, []byte("the new content"), nil 1294 } 1295 1296 func createModifier(t *testing.T) TarModifierFunc { 1297 return func(path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) { 1298 assert.Check(t, is.Nil(content)) 1299 return createOrReplaceModifier(path, header, content) 1300 } 1301 } 1302 1303 func appendModifier(path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) { 1304 buffer := bytes.Buffer{} 1305 if content != nil { 1306 if _, err := buffer.ReadFrom(content); err != nil { 1307 return nil, nil, err 1308 } 1309 } 1310 buffer.WriteString("\nnext line") 1311 return &tar.Header{Mode: 0600, Typeflag: tar.TypeReg}, buffer.Bytes(), nil 1312 } 1313 1314 func readFileFromArchive(t *testing.T, archive io.ReadCloser, name string, expectedCount int, doc string) string { 1315 skip.If(t, os.Getuid() != 0, "skipping test that requires root") 1316 destDir, err := ioutil.TempDir("", "docker-test-destDir") 1317 assert.NilError(t, err) 1318 defer os.RemoveAll(destDir) 1319 1320 err = Untar(archive, destDir, nil) 1321 assert.NilError(t, err) 1322 1323 files, _ := ioutil.ReadDir(destDir) 1324 assert.Check(t, is.Len(files, expectedCount), doc) 1325 1326 content, err := ioutil.ReadFile(filepath.Join(destDir, name)) 1327 assert.Check(t, err) 1328 return string(content) 1329 } 1330 1331 func TestDisablePigz(t *testing.T) { 1332 _, err := exec.LookPath("unpigz") 1333 if err != nil { 1334 t.Log("Test will not check full path when Pigz not installed") 1335 } 1336 1337 os.Setenv("MOBY_DISABLE_PIGZ", "true") 1338 defer os.Unsetenv("MOBY_DISABLE_PIGZ") 1339 1340 r := testDecompressStream(t, "gz", "gzip -f") 1341 // For the bufio pool 1342 outsideReaderCloserWrapper := r.(*ioutils.ReadCloserWrapper) 1343 // For the context canceller 1344 contextReaderCloserWrapper := outsideReaderCloserWrapper.Reader.(*ioutils.ReadCloserWrapper) 1345 1346 assert.Equal(t, reflect.TypeOf(contextReaderCloserWrapper.Reader), reflect.TypeOf(&gzip.Reader{})) 1347 } 1348 1349 func TestPigz(t *testing.T) { 1350 r := testDecompressStream(t, "gz", "gzip -f") 1351 // For the bufio pool 1352 outsideReaderCloserWrapper := r.(*ioutils.ReadCloserWrapper) 1353 // For the context canceller 1354 contextReaderCloserWrapper := outsideReaderCloserWrapper.Reader.(*ioutils.ReadCloserWrapper) 1355 1356 _, err := exec.LookPath("unpigz") 1357 if err == nil { 1358 t.Log("Tested whether Pigz is used, as it installed") 1359 assert.Equal(t, reflect.TypeOf(contextReaderCloserWrapper.Reader), reflect.TypeOf(&io.PipeReader{})) 1360 } else { 1361 t.Log("Tested whether Pigz is not used, as it not installed") 1362 assert.Equal(t, reflect.TypeOf(contextReaderCloserWrapper.Reader), reflect.TypeOf(&gzip.Reader{})) 1363 } 1364 }