github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/os/os_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package os_test 6 7 import ( 8 "bytes" 9 "errors" 10 "flag" 11 "fmt" 12 "internal/testenv" 13 "io" 14 "io/ioutil" 15 . "os" 16 osexec "os/exec" 17 "path/filepath" 18 "reflect" 19 "runtime" 20 "runtime/debug" 21 "sort" 22 "strings" 23 "sync" 24 "syscall" 25 "testing" 26 "time" 27 ) 28 29 var dot = []string{ 30 "dir_unix.go", 31 "env.go", 32 "error.go", 33 "file.go", 34 "os_test.go", 35 "types.go", 36 "stat_darwin.go", 37 "stat_linux.go", 38 } 39 40 type sysDir struct { 41 name string 42 files []string 43 } 44 45 var sysdir = func() *sysDir { 46 switch runtime.GOOS { 47 case "android": 48 return &sysDir{ 49 "/system/lib", 50 []string{ 51 "libmedia.so", 52 "libpowermanager.so", 53 }, 54 } 55 case "darwin": 56 switch runtime.GOARCH { 57 case "arm", "arm64": 58 wd, err := syscall.Getwd() 59 if err != nil { 60 wd = err.Error() 61 } 62 return &sysDir{ 63 filepath.Join(wd, "..", ".."), 64 []string{ 65 "ResourceRules.plist", 66 "Info.plist", 67 }, 68 } 69 } 70 case "windows": 71 return &sysDir{ 72 Getenv("SystemRoot") + "\\system32\\drivers\\etc", 73 []string{ 74 "networks", 75 "protocol", 76 "services", 77 }, 78 } 79 case "plan9": 80 return &sysDir{ 81 "/lib/ndb", 82 []string{ 83 "common", 84 "local", 85 }, 86 } 87 } 88 return &sysDir{ 89 "/etc", 90 []string{ 91 "group", 92 "hosts", 93 "passwd", 94 }, 95 } 96 }() 97 98 func size(name string, t *testing.T) int64 { 99 file, err := Open(name) 100 if err != nil { 101 t.Fatal("open failed:", err) 102 } 103 defer file.Close() 104 var buf [100]byte 105 len := 0 106 for { 107 n, e := file.Read(buf[0:]) 108 len += n 109 if e == io.EOF { 110 break 111 } 112 if e != nil { 113 t.Fatal("read failed:", e) 114 } 115 } 116 return int64(len) 117 } 118 119 func equal(name1, name2 string) (r bool) { 120 switch runtime.GOOS { 121 case "windows": 122 r = strings.ToLower(name1) == strings.ToLower(name2) 123 default: 124 r = name1 == name2 125 } 126 return 127 } 128 129 // localTmp returns a local temporary directory not on NFS. 130 func localTmp() string { 131 switch runtime.GOOS { 132 case "android", "windows": 133 return TempDir() 134 case "darwin": 135 switch runtime.GOARCH { 136 case "arm", "arm64": 137 return TempDir() 138 } 139 } 140 return "/tmp" 141 } 142 143 func newFile(testName string, t *testing.T) (f *File) { 144 f, err := ioutil.TempFile(localTmp(), "_Go_"+testName) 145 if err != nil { 146 t.Fatalf("TempFile %s: %s", testName, err) 147 } 148 return 149 } 150 151 func newDir(testName string, t *testing.T) (name string) { 152 name, err := ioutil.TempDir(localTmp(), "_Go_"+testName) 153 if err != nil { 154 t.Fatalf("TempDir %s: %s", testName, err) 155 } 156 return 157 } 158 159 var sfdir = sysdir.name 160 var sfname = sysdir.files[0] 161 162 func TestStat(t *testing.T) { 163 path := sfdir + "/" + sfname 164 dir, err := Stat(path) 165 if err != nil { 166 t.Fatal("stat failed:", err) 167 } 168 if !equal(sfname, dir.Name()) { 169 t.Error("name should be ", sfname, "; is", dir.Name()) 170 } 171 filesize := size(path, t) 172 if dir.Size() != filesize { 173 t.Error("size should be", filesize, "; is", dir.Size()) 174 } 175 } 176 177 func TestStatError(t *testing.T) { 178 defer chtmpdir(t)() 179 180 path := "no-such-file" 181 Remove(path) // Just in case 182 183 fi, err := Stat(path) 184 if err == nil { 185 t.Fatal("got nil, want error") 186 } 187 if fi != nil { 188 t.Errorf("got %v, want nil", fi) 189 } 190 if perr, ok := err.(*PathError); !ok { 191 t.Errorf("got %T, want %T", err, perr) 192 } 193 194 testenv.MustHaveSymlink(t) 195 196 link := "symlink" 197 Remove(link) // Just in case 198 err = Symlink(path, link) 199 if err != nil { 200 t.Fatal(err) 201 } 202 defer Remove(link) 203 204 fi, err = Stat(link) 205 if err == nil { 206 t.Fatal("got nil, want error") 207 } 208 if fi != nil { 209 t.Errorf("got %v, want nil", fi) 210 } 211 if perr, ok := err.(*PathError); !ok { 212 t.Errorf("got %T, want %T", err, perr) 213 } 214 } 215 216 func TestFstat(t *testing.T) { 217 path := sfdir + "/" + sfname 218 file, err1 := Open(path) 219 if err1 != nil { 220 t.Fatal("open failed:", err1) 221 } 222 defer file.Close() 223 dir, err2 := file.Stat() 224 if err2 != nil { 225 t.Fatal("fstat failed:", err2) 226 } 227 if !equal(sfname, dir.Name()) { 228 t.Error("name should be ", sfname, "; is", dir.Name()) 229 } 230 filesize := size(path, t) 231 if dir.Size() != filesize { 232 t.Error("size should be", filesize, "; is", dir.Size()) 233 } 234 } 235 236 func TestLstat(t *testing.T) { 237 path := sfdir + "/" + sfname 238 dir, err := Lstat(path) 239 if err != nil { 240 t.Fatal("lstat failed:", err) 241 } 242 if !equal(sfname, dir.Name()) { 243 t.Error("name should be ", sfname, "; is", dir.Name()) 244 } 245 filesize := size(path, t) 246 if dir.Size() != filesize { 247 t.Error("size should be", filesize, "; is", dir.Size()) 248 } 249 } 250 251 // Read with length 0 should not return EOF. 252 func TestRead0(t *testing.T) { 253 path := sfdir + "/" + sfname 254 f, err := Open(path) 255 if err != nil { 256 t.Fatal("open failed:", err) 257 } 258 defer f.Close() 259 260 b := make([]byte, 0) 261 n, err := f.Read(b) 262 if n != 0 || err != nil { 263 t.Errorf("Read(0) = %d, %v, want 0, nil", n, err) 264 } 265 b = make([]byte, 100) 266 n, err = f.Read(b) 267 if n <= 0 || err != nil { 268 t.Errorf("Read(100) = %d, %v, want >0, nil", n, err) 269 } 270 } 271 272 // Reading a closed file should should return ErrClosed error 273 func TestReadClosed(t *testing.T) { 274 path := sfdir + "/" + sfname 275 file, err := Open(path) 276 if err != nil { 277 t.Fatal("open failed:", err) 278 } 279 file.Close() // close immediately 280 281 b := make([]byte, 100) 282 _, err = file.Read(b) 283 284 e, ok := err.(*PathError) 285 if !ok { 286 t.Fatalf("Read: %T(%v), want PathError", e, e) 287 } 288 289 if e.Err != ErrClosed { 290 t.Errorf("Read: %v, want PathError(ErrClosed)", e) 291 } 292 } 293 294 func testReaddirnames(dir string, contents []string, t *testing.T) { 295 file, err := Open(dir) 296 if err != nil { 297 t.Fatalf("open %q failed: %v", dir, err) 298 } 299 defer file.Close() 300 s, err2 := file.Readdirnames(-1) 301 if err2 != nil { 302 t.Fatalf("readdirnames %q failed: %v", dir, err2) 303 } 304 for _, m := range contents { 305 found := false 306 for _, n := range s { 307 if n == "." || n == ".." { 308 t.Errorf("got %s in directory", n) 309 } 310 if equal(m, n) { 311 if found { 312 t.Error("present twice:", m) 313 } 314 found = true 315 } 316 } 317 if !found { 318 t.Error("could not find", m) 319 } 320 } 321 } 322 323 func testReaddir(dir string, contents []string, t *testing.T) { 324 file, err := Open(dir) 325 if err != nil { 326 t.Fatalf("open %q failed: %v", dir, err) 327 } 328 defer file.Close() 329 s, err2 := file.Readdir(-1) 330 if err2 != nil { 331 t.Fatalf("readdir %q failed: %v", dir, err2) 332 } 333 for _, m := range contents { 334 found := false 335 for _, n := range s { 336 if equal(m, n.Name()) { 337 if found { 338 t.Error("present twice:", m) 339 } 340 found = true 341 } 342 } 343 if !found { 344 t.Error("could not find", m) 345 } 346 } 347 } 348 349 func TestReaddirnames(t *testing.T) { 350 testReaddirnames(".", dot, t) 351 testReaddirnames(sysdir.name, sysdir.files, t) 352 } 353 354 func TestReaddir(t *testing.T) { 355 testReaddir(".", dot, t) 356 testReaddir(sysdir.name, sysdir.files, t) 357 } 358 359 func benchmarkReaddirname(path string, b *testing.B) { 360 var nentries int 361 for i := 0; i < b.N; i++ { 362 f, err := Open(path) 363 if err != nil { 364 b.Fatalf("open %q failed: %v", path, err) 365 } 366 ns, err := f.Readdirnames(-1) 367 f.Close() 368 if err != nil { 369 b.Fatalf("readdirnames %q failed: %v", path, err) 370 } 371 nentries = len(ns) 372 } 373 b.Logf("benchmarkReaddirname %q: %d entries", path, nentries) 374 } 375 376 func benchmarkReaddir(path string, b *testing.B) { 377 var nentries int 378 for i := 0; i < b.N; i++ { 379 f, err := Open(path) 380 if err != nil { 381 b.Fatalf("open %q failed: %v", path, err) 382 } 383 fs, err := f.Readdir(-1) 384 f.Close() 385 if err != nil { 386 b.Fatalf("readdir %q failed: %v", path, err) 387 } 388 nentries = len(fs) 389 } 390 b.Logf("benchmarkReaddir %q: %d entries", path, nentries) 391 } 392 393 func BenchmarkReaddirname(b *testing.B) { 394 benchmarkReaddirname(".", b) 395 } 396 397 func BenchmarkReaddir(b *testing.B) { 398 benchmarkReaddir(".", b) 399 } 400 401 func benchmarkStat(b *testing.B, path string) { 402 b.ResetTimer() 403 for i := 0; i < b.N; i++ { 404 _, err := Stat(path) 405 if err != nil { 406 b.Fatalf("Stat(%q) failed: %v", path, err) 407 } 408 } 409 } 410 411 func benchmarkLstat(b *testing.B, path string) { 412 b.ResetTimer() 413 for i := 0; i < b.N; i++ { 414 _, err := Lstat(path) 415 if err != nil { 416 b.Fatalf("Lstat(%q) failed: %v", path, err) 417 } 418 } 419 } 420 421 func BenchmarkStatDot(b *testing.B) { 422 benchmarkStat(b, ".") 423 } 424 425 func BenchmarkStatFile(b *testing.B) { 426 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go")) 427 } 428 429 func BenchmarkStatDir(b *testing.B) { 430 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os")) 431 } 432 433 func BenchmarkLstatDot(b *testing.B) { 434 benchmarkLstat(b, ".") 435 } 436 437 func BenchmarkLstatFile(b *testing.B) { 438 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go")) 439 } 440 441 func BenchmarkLstatDir(b *testing.B) { 442 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os")) 443 } 444 445 // Read the directory one entry at a time. 446 func smallReaddirnames(file *File, length int, t *testing.T) []string { 447 names := make([]string, length) 448 count := 0 449 for { 450 d, err := file.Readdirnames(1) 451 if err == io.EOF { 452 break 453 } 454 if err != nil { 455 t.Fatalf("readdirnames %q failed: %v", file.Name(), err) 456 } 457 if len(d) == 0 { 458 t.Fatalf("readdirnames %q returned empty slice and no error", file.Name()) 459 } 460 names[count] = d[0] 461 count++ 462 } 463 return names[0:count] 464 } 465 466 // Check that reading a directory one entry at a time gives the same result 467 // as reading it all at once. 468 func TestReaddirnamesOneAtATime(t *testing.T) { 469 // big directory that doesn't change often. 470 dir := "/usr/bin" 471 switch runtime.GOOS { 472 case "android": 473 dir = "/system/bin" 474 case "darwin": 475 switch runtime.GOARCH { 476 case "arm", "arm64": 477 wd, err := Getwd() 478 if err != nil { 479 t.Fatal(err) 480 } 481 dir = wd 482 } 483 case "plan9": 484 dir = "/bin" 485 case "windows": 486 dir = Getenv("SystemRoot") + "\\system32" 487 } 488 file, err := Open(dir) 489 if err != nil { 490 t.Fatalf("open %q failed: %v", dir, err) 491 } 492 defer file.Close() 493 all, err1 := file.Readdirnames(-1) 494 if err1 != nil { 495 t.Fatalf("readdirnames %q failed: %v", dir, err1) 496 } 497 file1, err2 := Open(dir) 498 if err2 != nil { 499 t.Fatalf("open %q failed: %v", dir, err2) 500 } 501 defer file1.Close() 502 small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up 503 if len(small) < len(all) { 504 t.Fatalf("len(small) is %d, less than %d", len(small), len(all)) 505 } 506 for i, n := range all { 507 if small[i] != n { 508 t.Errorf("small read %q mismatch: %v", small[i], n) 509 } 510 } 511 } 512 513 func TestReaddirNValues(t *testing.T) { 514 if testing.Short() { 515 t.Skip("test.short; skipping") 516 } 517 dir, err := ioutil.TempDir("", "") 518 if err != nil { 519 t.Fatalf("TempDir: %v", err) 520 } 521 defer RemoveAll(dir) 522 for i := 1; i <= 105; i++ { 523 f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i))) 524 if err != nil { 525 t.Fatalf("Create: %v", err) 526 } 527 f.Write([]byte(strings.Repeat("X", i))) 528 f.Close() 529 } 530 531 var d *File 532 openDir := func() { 533 var err error 534 d, err = Open(dir) 535 if err != nil { 536 t.Fatalf("Open directory: %v", err) 537 } 538 } 539 540 readDirExpect := func(n, want int, wantErr error) { 541 fi, err := d.Readdir(n) 542 if err != wantErr { 543 t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr) 544 } 545 if g, e := len(fi), want; g != e { 546 t.Errorf("Readdir of %d got %d files, want %d", n, g, e) 547 } 548 } 549 550 readDirNamesExpect := func(n, want int, wantErr error) { 551 fi, err := d.Readdirnames(n) 552 if err != wantErr { 553 t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr) 554 } 555 if g, e := len(fi), want; g != e { 556 t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e) 557 } 558 } 559 560 for _, fn := range []func(int, int, error){readDirExpect, readDirNamesExpect} { 561 // Test the slurp case 562 openDir() 563 fn(0, 105, nil) 564 fn(0, 0, nil) 565 d.Close() 566 567 // Slurp with -1 instead 568 openDir() 569 fn(-1, 105, nil) 570 fn(-2, 0, nil) 571 fn(0, 0, nil) 572 d.Close() 573 574 // Test the bounded case 575 openDir() 576 fn(1, 1, nil) 577 fn(2, 2, nil) 578 fn(105, 102, nil) // and tests buffer >100 case 579 fn(3, 0, io.EOF) 580 d.Close() 581 } 582 } 583 584 func touch(t *testing.T, name string) { 585 f, err := Create(name) 586 if err != nil { 587 t.Fatal(err) 588 } 589 if err := f.Close(); err != nil { 590 t.Fatal(err) 591 } 592 } 593 594 func TestReaddirStatFailures(t *testing.T) { 595 switch runtime.GOOS { 596 case "windows", "plan9": 597 // Windows and Plan 9 already do this correctly, 598 // but are structured with different syscalls such 599 // that they don't use Lstat, so the hook below for 600 // testing it wouldn't work. 601 t.Skipf("skipping test on %v", runtime.GOOS) 602 } 603 dir, err := ioutil.TempDir("", "") 604 if err != nil { 605 t.Fatalf("TempDir: %v", err) 606 } 607 defer RemoveAll(dir) 608 touch(t, filepath.Join(dir, "good1")) 609 touch(t, filepath.Join(dir, "x")) // will disappear or have an error 610 touch(t, filepath.Join(dir, "good2")) 611 defer func() { 612 *LstatP = Lstat 613 }() 614 var xerr error // error to return for x 615 *LstatP = func(path string) (FileInfo, error) { 616 if xerr != nil && strings.HasSuffix(path, "x") { 617 return nil, xerr 618 } 619 return Lstat(path) 620 } 621 readDir := func() ([]FileInfo, error) { 622 d, err := Open(dir) 623 if err != nil { 624 t.Fatal(err) 625 } 626 defer d.Close() 627 return d.Readdir(-1) 628 } 629 mustReadDir := func(testName string) []FileInfo { 630 fis, err := readDir() 631 if err != nil { 632 t.Fatalf("%s: Readdir: %v", testName, err) 633 } 634 return fis 635 } 636 names := func(fis []FileInfo) []string { 637 s := make([]string, len(fis)) 638 for i, fi := range fis { 639 s[i] = fi.Name() 640 } 641 sort.Strings(s) 642 return s 643 } 644 645 if got, want := names(mustReadDir("initial readdir")), 646 []string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) { 647 t.Errorf("initial readdir got %q; want %q", got, want) 648 } 649 650 xerr = ErrNotExist 651 if got, want := names(mustReadDir("with x disappearing")), 652 []string{"good1", "good2"}; !reflect.DeepEqual(got, want) { 653 t.Errorf("with x disappearing, got %q; want %q", got, want) 654 } 655 656 xerr = errors.New("some real error") 657 if _, err := readDir(); err != xerr { 658 t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr) 659 } 660 } 661 662 // Readdir on a regular file should fail. 663 func TestReaddirOfFile(t *testing.T) { 664 f, err := ioutil.TempFile("", "_Go_ReaddirOfFile") 665 if err != nil { 666 t.Fatal(err) 667 } 668 defer Remove(f.Name()) 669 f.Write([]byte("foo")) 670 f.Close() 671 reg, err := Open(f.Name()) 672 if err != nil { 673 t.Fatal(err) 674 } 675 defer reg.Close() 676 677 names, err := reg.Readdirnames(-1) 678 if err == nil { 679 t.Error("Readdirnames succeeded; want non-nil error") 680 } 681 if len(names) > 0 { 682 t.Errorf("unexpected dir names in regular file: %q", names) 683 } 684 } 685 686 func TestHardLink(t *testing.T) { 687 testenv.MustHaveLink(t) 688 689 defer chtmpdir(t)() 690 from, to := "hardlinktestfrom", "hardlinktestto" 691 Remove(from) // Just in case. 692 file, err := Create(to) 693 if err != nil { 694 t.Fatalf("open %q failed: %v", to, err) 695 } 696 defer Remove(to) 697 if err = file.Close(); err != nil { 698 t.Errorf("close %q failed: %v", to, err) 699 } 700 err = Link(to, from) 701 if err != nil { 702 t.Fatalf("link %q, %q failed: %v", to, from, err) 703 } 704 705 none := "hardlinktestnone" 706 err = Link(none, none) 707 // Check the returned error is well-formed. 708 if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" { 709 t.Errorf("link %q, %q failed to return a valid error", none, none) 710 } 711 712 defer Remove(from) 713 tostat, err := Stat(to) 714 if err != nil { 715 t.Fatalf("stat %q failed: %v", to, err) 716 } 717 fromstat, err := Stat(from) 718 if err != nil { 719 t.Fatalf("stat %q failed: %v", from, err) 720 } 721 if !SameFile(tostat, fromstat) { 722 t.Errorf("link %q, %q did not create hard link", to, from) 723 } 724 // We should not be able to perform the same Link() a second time 725 err = Link(to, from) 726 switch err := err.(type) { 727 case *LinkError: 728 if err.Op != "link" { 729 t.Errorf("Link(%q, %q) err.Op = %q; want %q", to, from, err.Op, "link") 730 } 731 if err.Old != to { 732 t.Errorf("Link(%q, %q) err.Old = %q; want %q", to, from, err.Old, to) 733 } 734 if err.New != from { 735 t.Errorf("Link(%q, %q) err.New = %q; want %q", to, from, err.New, from) 736 } 737 if !IsExist(err.Err) { 738 t.Errorf("Link(%q, %q) err.Err = %q; want %q", to, from, err.Err, "file exists error") 739 } 740 case nil: 741 t.Errorf("link %q, %q: expected error, got nil", from, to) 742 default: 743 t.Errorf("link %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 744 } 745 } 746 747 // chtmpdir changes the working directory to a new temporary directory and 748 // provides a cleanup function. Used when PWD is read-only. 749 func chtmpdir(t *testing.T) func() { 750 if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") { 751 return func() {} // only needed on darwin/arm{,64} 752 } 753 oldwd, err := Getwd() 754 if err != nil { 755 t.Fatalf("chtmpdir: %v", err) 756 } 757 d, err := ioutil.TempDir("", "test") 758 if err != nil { 759 t.Fatalf("chtmpdir: %v", err) 760 } 761 if err := Chdir(d); err != nil { 762 t.Fatalf("chtmpdir: %v", err) 763 } 764 return func() { 765 if err := Chdir(oldwd); err != nil { 766 t.Fatalf("chtmpdir: %v", err) 767 } 768 RemoveAll(d) 769 } 770 } 771 772 func TestSymlink(t *testing.T) { 773 testenv.MustHaveSymlink(t) 774 775 defer chtmpdir(t)() 776 from, to := "symlinktestfrom", "symlinktestto" 777 Remove(from) // Just in case. 778 file, err := Create(to) 779 if err != nil { 780 t.Fatalf("Create(%q) failed: %v", to, err) 781 } 782 defer Remove(to) 783 if err = file.Close(); err != nil { 784 t.Errorf("Close(%q) failed: %v", to, err) 785 } 786 err = Symlink(to, from) 787 if err != nil { 788 t.Fatalf("Symlink(%q, %q) failed: %v", to, from, err) 789 } 790 defer Remove(from) 791 tostat, err := Lstat(to) 792 if err != nil { 793 t.Fatalf("Lstat(%q) failed: %v", to, err) 794 } 795 if tostat.Mode()&ModeSymlink != 0 { 796 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = %v, want 0", to, tostat.Mode()&ModeSymlink) 797 } 798 fromstat, err := Stat(from) 799 if err != nil { 800 t.Fatalf("Stat(%q) failed: %v", from, err) 801 } 802 if !SameFile(tostat, fromstat) { 803 t.Errorf("Symlink(%q, %q) did not create symlink", to, from) 804 } 805 fromstat, err = Lstat(from) 806 if err != nil { 807 t.Fatalf("Lstat(%q) failed: %v", from, err) 808 } 809 if fromstat.Mode()&ModeSymlink == 0 { 810 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = 0, want %v", from, ModeSymlink) 811 } 812 fromstat, err = Stat(from) 813 if err != nil { 814 t.Fatalf("Stat(%q) failed: %v", from, err) 815 } 816 if fromstat.Name() != from { 817 t.Errorf("Stat(%q).Name() = %q, want %q", from, fromstat.Name(), from) 818 } 819 if fromstat.Mode()&ModeSymlink != 0 { 820 t.Fatalf("Stat(%q).Mode()&ModeSymlink = %v, want 0", from, fromstat.Mode()&ModeSymlink) 821 } 822 s, err := Readlink(from) 823 if err != nil { 824 t.Fatalf("Readlink(%q) failed: %v", from, err) 825 } 826 if s != to { 827 t.Fatalf("Readlink(%q) = %q, want %q", from, s, to) 828 } 829 file, err = Open(from) 830 if err != nil { 831 t.Fatalf("Open(%q) failed: %v", from, err) 832 } 833 file.Close() 834 } 835 836 func TestLongSymlink(t *testing.T) { 837 testenv.MustHaveSymlink(t) 838 839 defer chtmpdir(t)() 840 s := "0123456789abcdef" 841 // Long, but not too long: a common limit is 255. 842 s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s 843 from := "longsymlinktestfrom" 844 Remove(from) // Just in case. 845 err := Symlink(s, from) 846 if err != nil { 847 t.Fatalf("symlink %q, %q failed: %v", s, from, err) 848 } 849 defer Remove(from) 850 r, err := Readlink(from) 851 if err != nil { 852 t.Fatalf("readlink %q failed: %v", from, err) 853 } 854 if r != s { 855 t.Fatalf("after symlink %q != %q", r, s) 856 } 857 } 858 859 func TestRename(t *testing.T) { 860 defer chtmpdir(t)() 861 from, to := "renamefrom", "renameto" 862 // Ensure we are not testing the overwrite case here. 863 Remove(from) 864 Remove(to) 865 866 file, err := Create(from) 867 if err != nil { 868 t.Fatalf("open %q failed: %v", from, err) 869 } 870 if err = file.Close(); err != nil { 871 t.Errorf("close %q failed: %v", from, err) 872 } 873 err = Rename(from, to) 874 if err != nil { 875 t.Fatalf("rename %q, %q failed: %v", to, from, err) 876 } 877 defer Remove(to) 878 _, err = Stat(to) 879 if err != nil { 880 t.Errorf("stat %q failed: %v", to, err) 881 } 882 } 883 884 func TestRenameOverwriteDest(t *testing.T) { 885 defer chtmpdir(t)() 886 from, to := "renamefrom", "renameto" 887 // Just in case. 888 Remove(from) 889 Remove(to) 890 891 toData := []byte("to") 892 fromData := []byte("from") 893 894 err := ioutil.WriteFile(to, toData, 0777) 895 if err != nil { 896 t.Fatalf("write file %q failed: %v", to, err) 897 } 898 899 err = ioutil.WriteFile(from, fromData, 0777) 900 if err != nil { 901 t.Fatalf("write file %q failed: %v", from, err) 902 } 903 err = Rename(from, to) 904 if err != nil { 905 t.Fatalf("rename %q, %q failed: %v", to, from, err) 906 } 907 defer Remove(to) 908 909 _, err = Stat(from) 910 if err == nil { 911 t.Errorf("from file %q still exists", from) 912 } 913 if err != nil && !IsNotExist(err) { 914 t.Fatalf("stat from: %v", err) 915 } 916 toFi, err := Stat(to) 917 if err != nil { 918 t.Fatalf("stat %q failed: %v", to, err) 919 } 920 if toFi.Size() != int64(len(fromData)) { 921 t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData)) 922 } 923 } 924 925 func TestRenameFailed(t *testing.T) { 926 defer chtmpdir(t)() 927 from, to := "renamefrom", "renameto" 928 // Ensure we are not testing the overwrite case here. 929 Remove(from) 930 Remove(to) 931 932 err := Rename(from, to) 933 switch err := err.(type) { 934 case *LinkError: 935 if err.Op != "rename" { 936 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) 937 } 938 if err.Old != from { 939 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) 940 } 941 if err.New != to { 942 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) 943 } 944 case nil: 945 t.Errorf("rename %q, %q: expected error, got nil", from, to) 946 947 // cleanup whatever was placed in "renameto" 948 Remove(to) 949 default: 950 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 951 } 952 } 953 954 func TestRenameNotExisting(t *testing.T) { 955 defer chtmpdir(t)() 956 from, to := "doesnt-exist", "dest" 957 958 Mkdir(to, 0777) 959 defer Remove(to) 960 961 if err := Rename(from, to); !IsNotExist(err) { 962 t.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from, to, err) 963 } 964 } 965 966 func TestRenameToDirFailed(t *testing.T) { 967 defer chtmpdir(t)() 968 from, to := "renamefrom", "renameto" 969 970 Remove(from) 971 Remove(to) 972 Mkdir(from, 0777) 973 Mkdir(to, 0777) 974 defer Remove(from) 975 defer Remove(to) 976 977 err := Rename(from, to) 978 switch err := err.(type) { 979 case *LinkError: 980 if err.Op != "rename" { 981 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) 982 } 983 if err.Old != from { 984 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) 985 } 986 if err.New != to { 987 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) 988 } 989 case nil: 990 t.Errorf("rename %q, %q: expected error, got nil", from, to) 991 992 // cleanup whatever was placed in "renameto" 993 Remove(to) 994 default: 995 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 996 } 997 } 998 999 func exec(t *testing.T, dir, cmd string, args []string, expect string) { 1000 r, w, err := Pipe() 1001 if err != nil { 1002 t.Fatalf("Pipe: %v", err) 1003 } 1004 defer r.Close() 1005 attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}} 1006 p, err := StartProcess(cmd, args, attr) 1007 if err != nil { 1008 t.Fatalf("StartProcess: %v", err) 1009 } 1010 w.Close() 1011 1012 var b bytes.Buffer 1013 io.Copy(&b, r) 1014 output := b.String() 1015 1016 fi1, _ := Stat(strings.TrimSpace(output)) 1017 fi2, _ := Stat(expect) 1018 if !SameFile(fi1, fi2) { 1019 t.Errorf("exec %q returned %q wanted %q", 1020 strings.Join(append([]string{cmd}, args...), " "), output, expect) 1021 } 1022 p.Wait() 1023 } 1024 1025 func TestStartProcess(t *testing.T) { 1026 testenv.MustHaveExec(t) 1027 1028 var dir, cmd string 1029 var args []string 1030 switch runtime.GOOS { 1031 case "android": 1032 t.Skip("android doesn't have /bin/pwd") 1033 case "windows": 1034 cmd = Getenv("COMSPEC") 1035 dir = Getenv("SystemRoot") 1036 args = []string{"/c", "cd"} 1037 default: 1038 var err error 1039 cmd, err = osexec.LookPath("pwd") 1040 if err != nil { 1041 t.Fatalf("Can't find pwd: %v", err) 1042 } 1043 dir = "/" 1044 args = []string{} 1045 t.Logf("Testing with %v", cmd) 1046 } 1047 cmddir, cmdbase := filepath.Split(cmd) 1048 args = append([]string{cmdbase}, args...) 1049 // Test absolute executable path. 1050 exec(t, dir, cmd, args, dir) 1051 // Test relative executable path. 1052 exec(t, cmddir, cmdbase, args, cmddir) 1053 } 1054 1055 func checkMode(t *testing.T, path string, mode FileMode) { 1056 dir, err := Stat(path) 1057 if err != nil { 1058 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 1059 } 1060 if dir.Mode()&0777 != mode { 1061 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode) 1062 } 1063 } 1064 1065 func TestChmod(t *testing.T) { 1066 // Chmod is not supported under windows. 1067 if runtime.GOOS == "windows" { 1068 return 1069 } 1070 f := newFile("TestChmod", t) 1071 defer Remove(f.Name()) 1072 defer f.Close() 1073 1074 if err := Chmod(f.Name(), 0456); err != nil { 1075 t.Fatalf("chmod %s 0456: %s", f.Name(), err) 1076 } 1077 checkMode(t, f.Name(), 0456) 1078 1079 if err := f.Chmod(0123); err != nil { 1080 t.Fatalf("chmod %s 0123: %s", f.Name(), err) 1081 } 1082 checkMode(t, f.Name(), 0123) 1083 } 1084 1085 func checkSize(t *testing.T, f *File, size int64) { 1086 dir, err := f.Stat() 1087 if err != nil { 1088 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err) 1089 } 1090 if dir.Size() != size { 1091 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size) 1092 } 1093 } 1094 1095 func TestFTruncate(t *testing.T) { 1096 f := newFile("TestFTruncate", t) 1097 defer Remove(f.Name()) 1098 defer f.Close() 1099 1100 checkSize(t, f, 0) 1101 f.Write([]byte("hello, world\n")) 1102 checkSize(t, f, 13) 1103 f.Truncate(10) 1104 checkSize(t, f, 10) 1105 f.Truncate(1024) 1106 checkSize(t, f, 1024) 1107 f.Truncate(0) 1108 checkSize(t, f, 0) 1109 _, err := f.Write([]byte("surprise!")) 1110 if err == nil { 1111 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 1112 } 1113 } 1114 1115 func TestTruncate(t *testing.T) { 1116 f := newFile("TestTruncate", t) 1117 defer Remove(f.Name()) 1118 defer f.Close() 1119 1120 checkSize(t, f, 0) 1121 f.Write([]byte("hello, world\n")) 1122 checkSize(t, f, 13) 1123 Truncate(f.Name(), 10) 1124 checkSize(t, f, 10) 1125 Truncate(f.Name(), 1024) 1126 checkSize(t, f, 1024) 1127 Truncate(f.Name(), 0) 1128 checkSize(t, f, 0) 1129 _, err := f.Write([]byte("surprise!")) 1130 if err == nil { 1131 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 1132 } 1133 } 1134 1135 // Use TempDir (via newFile) to make sure we're on a local file system, 1136 // so that timings are not distorted by latency and caching. 1137 // On NFS, timings can be off due to caching of meta-data on 1138 // NFS servers (Issue 848). 1139 func TestChtimes(t *testing.T) { 1140 f := newFile("TestChtimes", t) 1141 defer Remove(f.Name()) 1142 1143 f.Write([]byte("hello, world\n")) 1144 f.Close() 1145 1146 testChtimes(t, f.Name()) 1147 } 1148 1149 // Use TempDir (via newDir) to make sure we're on a local file system, 1150 // so that timings are not distorted by latency and caching. 1151 // On NFS, timings can be off due to caching of meta-data on 1152 // NFS servers (Issue 848). 1153 func TestChtimesDir(t *testing.T) { 1154 name := newDir("TestChtimes", t) 1155 defer RemoveAll(name) 1156 1157 testChtimes(t, name) 1158 } 1159 1160 func testChtimes(t *testing.T, name string) { 1161 st, err := Stat(name) 1162 if err != nil { 1163 t.Fatalf("Stat %s: %s", name, err) 1164 } 1165 preStat := st 1166 1167 // Move access and modification time back a second 1168 at := Atime(preStat) 1169 mt := preStat.ModTime() 1170 err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second)) 1171 if err != nil { 1172 t.Fatalf("Chtimes %s: %s", name, err) 1173 } 1174 1175 st, err = Stat(name) 1176 if err != nil { 1177 t.Fatalf("second Stat %s: %s", name, err) 1178 } 1179 postStat := st 1180 1181 pat := Atime(postStat) 1182 pmt := postStat.ModTime() 1183 if !pat.Before(at) { 1184 switch runtime.GOOS { 1185 case "plan9", "nacl": 1186 // Ignore. 1187 // Plan 9, NaCl: 1188 // Mtime is the time of the last change of 1189 // content. Similarly, atime is set whenever 1190 // the contents are accessed; also, it is set 1191 // whenever mtime is set. 1192 case "netbsd": 1193 t.Logf("AccessTime didn't go backwards; was=%v, after=%v (Ignoring. See NetBSD issue golang.org/issue/19293)", at, pat) 1194 default: 1195 t.Errorf("AccessTime didn't go backwards; was=%v, after=%v", at, pat) 1196 } 1197 } 1198 1199 if !pmt.Before(mt) { 1200 t.Errorf("ModTime didn't go backwards; was=%v, after=%v", mt, pmt) 1201 } 1202 } 1203 1204 func TestChdirAndGetwd(t *testing.T) { 1205 // TODO(brainman): file.Chdir() is not implemented on windows. 1206 if runtime.GOOS == "windows" { 1207 return 1208 } 1209 fd, err := Open(".") 1210 if err != nil { 1211 t.Fatalf("Open .: %s", err) 1212 } 1213 // These are chosen carefully not to be symlinks on a Mac 1214 // (unlike, say, /var, /etc), except /tmp, which we handle below. 1215 dirs := []string{"/", "/usr/bin", "/tmp"} 1216 // /usr/bin does not usually exist on Plan 9 or Android. 1217 switch runtime.GOOS { 1218 case "android": 1219 dirs = []string{"/", "/system/bin"} 1220 case "plan9": 1221 dirs = []string{"/", "/usr"} 1222 case "darwin": 1223 switch runtime.GOARCH { 1224 case "arm", "arm64": 1225 d1, err := ioutil.TempDir("", "d1") 1226 if err != nil { 1227 t.Fatalf("TempDir: %v", err) 1228 } 1229 d2, err := ioutil.TempDir("", "d2") 1230 if err != nil { 1231 t.Fatalf("TempDir: %v", err) 1232 } 1233 dirs = []string{d1, d2} 1234 } 1235 } 1236 oldwd := Getenv("PWD") 1237 for mode := 0; mode < 2; mode++ { 1238 for _, d := range dirs { 1239 if mode == 0 { 1240 err = Chdir(d) 1241 } else { 1242 fd1, err := Open(d) 1243 if err != nil { 1244 t.Errorf("Open %s: %s", d, err) 1245 continue 1246 } 1247 err = fd1.Chdir() 1248 fd1.Close() 1249 } 1250 if d == "/tmp" { 1251 Setenv("PWD", "/tmp") 1252 } 1253 pwd, err1 := Getwd() 1254 Setenv("PWD", oldwd) 1255 err2 := fd.Chdir() 1256 if err2 != nil { 1257 // We changed the current directory and cannot go back. 1258 // Don't let the tests continue; they'll scribble 1259 // all over some other directory. 1260 fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2) 1261 Exit(1) 1262 } 1263 if err != nil { 1264 fd.Close() 1265 t.Fatalf("Chdir %s: %s", d, err) 1266 } 1267 if err1 != nil { 1268 fd.Close() 1269 t.Fatalf("Getwd in %s: %s", d, err1) 1270 } 1271 if pwd != d { 1272 fd.Close() 1273 t.Fatalf("Getwd returned %q want %q", pwd, d) 1274 } 1275 } 1276 } 1277 fd.Close() 1278 } 1279 1280 // Test that Chdir+Getwd is program-wide. 1281 func TestProgWideChdir(t *testing.T) { 1282 const N = 10 1283 c := make(chan bool) 1284 cpwd := make(chan string) 1285 for i := 0; i < N; i++ { 1286 go func(i int) { 1287 // Lock half the goroutines in their own operating system 1288 // thread to exercise more scheduler possibilities. 1289 if i%2 == 1 { 1290 // On Plan 9, after calling LockOSThread, the goroutines 1291 // run on different processes which don't share the working 1292 // directory. This used to be an issue because Go expects 1293 // the working directory to be program-wide. 1294 // See issue 9428. 1295 runtime.LockOSThread() 1296 } 1297 <-c 1298 pwd, err := Getwd() 1299 if err != nil { 1300 t.Errorf("Getwd on goroutine %d: %v", i, err) 1301 return 1302 } 1303 cpwd <- pwd 1304 }(i) 1305 } 1306 oldwd, err := Getwd() 1307 if err != nil { 1308 t.Fatalf("Getwd: %v", err) 1309 } 1310 d, err := ioutil.TempDir("", "test") 1311 if err != nil { 1312 t.Fatalf("TempDir: %v", err) 1313 } 1314 defer func() { 1315 if err := Chdir(oldwd); err != nil { 1316 t.Fatalf("Chdir: %v", err) 1317 } 1318 RemoveAll(d) 1319 }() 1320 if err := Chdir(d); err != nil { 1321 t.Fatalf("Chdir: %v", err) 1322 } 1323 // OS X sets TMPDIR to a symbolic link. 1324 // So we resolve our working directory again before the test. 1325 d, err = Getwd() 1326 if err != nil { 1327 t.Fatalf("Getwd: %v", err) 1328 } 1329 close(c) 1330 for i := 0; i < N; i++ { 1331 pwd := <-cpwd 1332 if pwd != d { 1333 t.Errorf("Getwd returned %q; want %q", pwd, d) 1334 } 1335 } 1336 } 1337 1338 func TestSeek(t *testing.T) { 1339 f := newFile("TestSeek", t) 1340 defer Remove(f.Name()) 1341 defer f.Close() 1342 1343 const data = "hello, world\n" 1344 io.WriteString(f, data) 1345 1346 type test struct { 1347 in int64 1348 whence int 1349 out int64 1350 } 1351 var tests = []test{ 1352 {0, io.SeekCurrent, int64(len(data))}, 1353 {0, io.SeekStart, 0}, 1354 {5, io.SeekStart, 5}, 1355 {0, io.SeekEnd, int64(len(data))}, 1356 {0, io.SeekStart, 0}, 1357 {-1, io.SeekEnd, int64(len(data)) - 1}, 1358 {1 << 33, io.SeekStart, 1 << 33}, 1359 {1 << 33, io.SeekEnd, 1<<33 + int64(len(data))}, 1360 } 1361 for i, tt := range tests { 1362 off, err := f.Seek(tt.in, tt.whence) 1363 if off != tt.out || err != nil { 1364 if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 { 1365 // Reiserfs rejects the big seeks. 1366 // https://golang.org/issue/91 1367 break 1368 } 1369 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out) 1370 } 1371 } 1372 } 1373 1374 func TestSeekError(t *testing.T) { 1375 switch runtime.GOOS { 1376 case "plan9", "nacl": 1377 t.Skipf("skipping test on %v", runtime.GOOS) 1378 } 1379 1380 r, w, err := Pipe() 1381 if err != nil { 1382 t.Fatal(err) 1383 } 1384 _, err = r.Seek(0, 0) 1385 if err == nil { 1386 t.Fatal("Seek on pipe should fail") 1387 } 1388 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE { 1389 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err) 1390 } 1391 _, err = w.Seek(0, 0) 1392 if err == nil { 1393 t.Fatal("Seek on pipe should fail") 1394 } 1395 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE { 1396 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err) 1397 } 1398 } 1399 1400 type openErrorTest struct { 1401 path string 1402 mode int 1403 error error 1404 } 1405 1406 var openErrorTests = []openErrorTest{ 1407 { 1408 sfdir + "/no-such-file", 1409 O_RDONLY, 1410 syscall.ENOENT, 1411 }, 1412 { 1413 sfdir, 1414 O_WRONLY, 1415 syscall.EISDIR, 1416 }, 1417 { 1418 sfdir + "/" + sfname + "/no-such-file", 1419 O_WRONLY, 1420 syscall.ENOTDIR, 1421 }, 1422 } 1423 1424 func TestOpenError(t *testing.T) { 1425 for _, tt := range openErrorTests { 1426 f, err := OpenFile(tt.path, tt.mode, 0) 1427 if err == nil { 1428 t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode) 1429 f.Close() 1430 continue 1431 } 1432 perr, ok := err.(*PathError) 1433 if !ok { 1434 t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err) 1435 } 1436 if perr.Err != tt.error { 1437 if runtime.GOOS == "plan9" { 1438 syscallErrStr := perr.Err.Error() 1439 expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1) 1440 if !strings.HasSuffix(syscallErrStr, expectedErrStr) { 1441 // Some Plan 9 file servers incorrectly return 1442 // EACCES rather than EISDIR when a directory is 1443 // opened for write. 1444 if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) { 1445 continue 1446 } 1447 t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr) 1448 } 1449 continue 1450 } 1451 if runtime.GOOS == "dragonfly" { 1452 // DragonFly incorrectly returns EACCES rather 1453 // EISDIR when a directory is opened for write. 1454 if tt.error == syscall.EISDIR && perr.Err == syscall.EACCES { 1455 continue 1456 } 1457 } 1458 t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error()) 1459 } 1460 } 1461 } 1462 1463 func TestOpenNoName(t *testing.T) { 1464 f, err := Open("") 1465 if err == nil { 1466 t.Fatal(`Open("") succeeded`) 1467 f.Close() 1468 } 1469 } 1470 1471 func runBinHostname(t *testing.T) string { 1472 // Run /bin/hostname and collect output. 1473 r, w, err := Pipe() 1474 if err != nil { 1475 t.Fatal(err) 1476 } 1477 defer r.Close() 1478 const path = "/bin/hostname" 1479 p, err := StartProcess(path, []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}}) 1480 if err != nil { 1481 if _, err := Stat(path); IsNotExist(err) { 1482 t.Skipf("skipping test; test requires %s but it does not exist", path) 1483 } 1484 t.Fatal(err) 1485 } 1486 w.Close() 1487 1488 var b bytes.Buffer 1489 io.Copy(&b, r) 1490 _, err = p.Wait() 1491 if err != nil { 1492 t.Fatalf("run hostname Wait: %v", err) 1493 } 1494 err = p.Kill() 1495 if err == nil { 1496 t.Errorf("expected an error from Kill running 'hostname'") 1497 } 1498 output := b.String() 1499 if n := len(output); n > 0 && output[n-1] == '\n' { 1500 output = output[0 : n-1] 1501 } 1502 if output == "" { 1503 t.Fatalf("/bin/hostname produced no output") 1504 } 1505 1506 return output 1507 } 1508 1509 func testWindowsHostname(t *testing.T) { 1510 hostname, err := Hostname() 1511 if err != nil { 1512 t.Fatal(err) 1513 } 1514 cmd := osexec.Command("hostname") 1515 out, err := cmd.CombinedOutput() 1516 if err != nil { 1517 t.Fatalf("Failed to execute hostname command: %v %s", err, out) 1518 } 1519 want := strings.Trim(string(out), "\r\n") 1520 if hostname != want { 1521 t.Fatalf("Hostname() = %q, want %q", hostname, want) 1522 } 1523 } 1524 1525 func TestHostname(t *testing.T) { 1526 // There is no other way to fetch hostname on windows, but via winapi. 1527 // On Plan 9 it can be taken from #c/sysname as Hostname() does. 1528 switch runtime.GOOS { 1529 case "android", "plan9": 1530 t.Skipf("%s doesn't have /bin/hostname", runtime.GOOS) 1531 case "windows": 1532 testWindowsHostname(t) 1533 return 1534 } 1535 1536 testenv.MustHaveExec(t) 1537 1538 // Check internal Hostname() against the output of /bin/hostname. 1539 // Allow that the internal Hostname returns a Fully Qualified Domain Name 1540 // and the /bin/hostname only returns the first component 1541 hostname, err := Hostname() 1542 if err != nil { 1543 t.Fatalf("%v", err) 1544 } 1545 want := runBinHostname(t) 1546 if hostname != want { 1547 i := strings.Index(hostname, ".") 1548 if i < 0 || hostname[0:i] != want { 1549 t.Errorf("Hostname() = %q, want %q", hostname, want) 1550 } 1551 } 1552 } 1553 1554 func TestReadAt(t *testing.T) { 1555 f := newFile("TestReadAt", t) 1556 defer Remove(f.Name()) 1557 defer f.Close() 1558 1559 const data = "hello, world\n" 1560 io.WriteString(f, data) 1561 1562 b := make([]byte, 5) 1563 n, err := f.ReadAt(b, 7) 1564 if err != nil || n != len(b) { 1565 t.Fatalf("ReadAt 7: %d, %v", n, err) 1566 } 1567 if string(b) != "world" { 1568 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 1569 } 1570 } 1571 1572 // Verify that ReadAt doesn't affect seek offset. 1573 // In the Plan 9 kernel, there used to be a bug in the implementation of 1574 // the pread syscall, where the channel offset was erroneously updated after 1575 // calling pread on a file. 1576 func TestReadAtOffset(t *testing.T) { 1577 f := newFile("TestReadAtOffset", t) 1578 defer Remove(f.Name()) 1579 defer f.Close() 1580 1581 const data = "hello, world\n" 1582 io.WriteString(f, data) 1583 1584 f.Seek(0, 0) 1585 b := make([]byte, 5) 1586 1587 n, err := f.ReadAt(b, 7) 1588 if err != nil || n != len(b) { 1589 t.Fatalf("ReadAt 7: %d, %v", n, err) 1590 } 1591 if string(b) != "world" { 1592 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 1593 } 1594 1595 n, err = f.Read(b) 1596 if err != nil || n != len(b) { 1597 t.Fatalf("Read: %d, %v", n, err) 1598 } 1599 if string(b) != "hello" { 1600 t.Fatalf("Read: have %q want %q", string(b), "hello") 1601 } 1602 } 1603 1604 // Verify that ReadAt doesn't allow negative offset. 1605 func TestReadAtNegativeOffset(t *testing.T) { 1606 f := newFile("TestReadAtNegativeOffset", t) 1607 defer Remove(f.Name()) 1608 defer f.Close() 1609 1610 const data = "hello, world\n" 1611 io.WriteString(f, data) 1612 1613 f.Seek(0, 0) 1614 b := make([]byte, 5) 1615 1616 n, err := f.ReadAt(b, -10) 1617 1618 const wantsub = "negative offset" 1619 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 { 1620 t.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub) 1621 } 1622 } 1623 1624 func TestWriteAt(t *testing.T) { 1625 f := newFile("TestWriteAt", t) 1626 defer Remove(f.Name()) 1627 defer f.Close() 1628 1629 const data = "hello, world\n" 1630 io.WriteString(f, data) 1631 1632 n, err := f.WriteAt([]byte("WORLD"), 7) 1633 if err != nil || n != 5 { 1634 t.Fatalf("WriteAt 7: %d, %v", n, err) 1635 } 1636 1637 b, err := ioutil.ReadFile(f.Name()) 1638 if err != nil { 1639 t.Fatalf("ReadFile %s: %v", f.Name(), err) 1640 } 1641 if string(b) != "hello, WORLD\n" { 1642 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n") 1643 } 1644 } 1645 1646 // Verify that WriteAt doesn't allow negative offset. 1647 func TestWriteAtNegativeOffset(t *testing.T) { 1648 f := newFile("TestWriteAtNegativeOffset", t) 1649 defer Remove(f.Name()) 1650 defer f.Close() 1651 1652 n, err := f.WriteAt([]byte("WORLD"), -10) 1653 1654 const wantsub = "negative offset" 1655 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 { 1656 t.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub) 1657 } 1658 } 1659 1660 func writeFile(t *testing.T, fname string, flag int, text string) string { 1661 f, err := OpenFile(fname, flag, 0666) 1662 if err != nil { 1663 t.Fatalf("Open: %v", err) 1664 } 1665 n, err := io.WriteString(f, text) 1666 if err != nil { 1667 t.Fatalf("WriteString: %d, %v", n, err) 1668 } 1669 f.Close() 1670 data, err := ioutil.ReadFile(fname) 1671 if err != nil { 1672 t.Fatalf("ReadFile: %v", err) 1673 } 1674 return string(data) 1675 } 1676 1677 func TestAppend(t *testing.T) { 1678 defer chtmpdir(t)() 1679 const f = "append.txt" 1680 defer Remove(f) 1681 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 1682 if s != "new" { 1683 t.Fatalf("writeFile: have %q want %q", s, "new") 1684 } 1685 s = writeFile(t, f, O_APPEND|O_RDWR, "|append") 1686 if s != "new|append" { 1687 t.Fatalf("writeFile: have %q want %q", s, "new|append") 1688 } 1689 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append") 1690 if s != "new|append|append" { 1691 t.Fatalf("writeFile: have %q want %q", s, "new|append|append") 1692 } 1693 err := Remove(f) 1694 if err != nil { 1695 t.Fatalf("Remove: %v", err) 1696 } 1697 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append") 1698 if s != "new&append" { 1699 t.Fatalf("writeFile: after append have %q want %q", s, "new&append") 1700 } 1701 s = writeFile(t, f, O_CREATE|O_RDWR, "old") 1702 if s != "old&append" { 1703 t.Fatalf("writeFile: after create have %q want %q", s, "old&append") 1704 } 1705 s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 1706 if s != "new" { 1707 t.Fatalf("writeFile: after truncate have %q want %q", s, "new") 1708 } 1709 } 1710 1711 func TestStatDirWithTrailingSlash(t *testing.T) { 1712 // Create new temporary directory and arrange to clean it up. 1713 path, err := ioutil.TempDir("", "/_TestStatDirWithSlash_") 1714 if err != nil { 1715 t.Fatalf("TempDir: %s", err) 1716 } 1717 defer RemoveAll(path) 1718 1719 // Stat of path should succeed. 1720 _, err = Stat(path) 1721 if err != nil { 1722 t.Fatalf("stat %s failed: %s", path, err) 1723 } 1724 1725 // Stat of path+"/" should succeed too. 1726 path += "/" 1727 _, err = Stat(path) 1728 if err != nil { 1729 t.Fatalf("stat %s failed: %s", path, err) 1730 } 1731 } 1732 1733 func TestNilProcessStateString(t *testing.T) { 1734 var ps *ProcessState 1735 s := ps.String() 1736 if s != "<nil>" { 1737 t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>") 1738 } 1739 } 1740 1741 func TestSameFile(t *testing.T) { 1742 defer chtmpdir(t)() 1743 fa, err := Create("a") 1744 if err != nil { 1745 t.Fatalf("Create(a): %v", err) 1746 } 1747 defer Remove(fa.Name()) 1748 fa.Close() 1749 fb, err := Create("b") 1750 if err != nil { 1751 t.Fatalf("Create(b): %v", err) 1752 } 1753 defer Remove(fb.Name()) 1754 fb.Close() 1755 1756 ia1, err := Stat("a") 1757 if err != nil { 1758 t.Fatalf("Stat(a): %v", err) 1759 } 1760 ia2, err := Stat("a") 1761 if err != nil { 1762 t.Fatalf("Stat(a): %v", err) 1763 } 1764 if !SameFile(ia1, ia2) { 1765 t.Errorf("files should be same") 1766 } 1767 1768 ib, err := Stat("b") 1769 if err != nil { 1770 t.Fatalf("Stat(b): %v", err) 1771 } 1772 if SameFile(ia1, ib) { 1773 t.Errorf("files should be different") 1774 } 1775 } 1776 1777 func TestDevNullFile(t *testing.T) { 1778 f, err := Open(DevNull) 1779 if err != nil { 1780 t.Fatalf("Open(%s): %v", DevNull, err) 1781 } 1782 defer f.Close() 1783 fi, err := f.Stat() 1784 if err != nil { 1785 t.Fatalf("Stat(%s): %v", DevNull, err) 1786 } 1787 name := filepath.Base(DevNull) 1788 if fi.Name() != name { 1789 t.Fatalf("wrong file name have %v want %v", fi.Name(), name) 1790 } 1791 if fi.Size() != 0 { 1792 t.Fatalf("wrong file size have %d want 0", fi.Size()) 1793 } 1794 } 1795 1796 var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output") 1797 1798 func TestLargeWriteToConsole(t *testing.T) { 1799 if !*testLargeWrite { 1800 t.Skip("skipping console-flooding test; enable with -large_write") 1801 } 1802 b := make([]byte, 32000) 1803 for i := range b { 1804 b[i] = '.' 1805 } 1806 b[len(b)-1] = '\n' 1807 n, err := Stdout.Write(b) 1808 if err != nil { 1809 t.Fatalf("Write to os.Stdout failed: %v", err) 1810 } 1811 if n != len(b) { 1812 t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n) 1813 } 1814 n, err = Stderr.Write(b) 1815 if err != nil { 1816 t.Fatalf("Write to os.Stderr failed: %v", err) 1817 } 1818 if n != len(b) { 1819 t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n) 1820 } 1821 } 1822 1823 func TestStatDirModeExec(t *testing.T) { 1824 const mode = 0111 1825 1826 path, err := ioutil.TempDir("", "go-build") 1827 if err != nil { 1828 t.Fatalf("Failed to create temp directory: %v", err) 1829 } 1830 defer RemoveAll(path) 1831 1832 if err := Chmod(path, 0777); err != nil { 1833 t.Fatalf("Chmod %q 0777: %v", path, err) 1834 } 1835 1836 dir, err := Stat(path) 1837 if err != nil { 1838 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 1839 } 1840 if dir.Mode()&mode != mode { 1841 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode) 1842 } 1843 } 1844 1845 func TestStatStdin(t *testing.T) { 1846 switch runtime.GOOS { 1847 case "android", "plan9": 1848 t.Skipf("%s doesn't have /bin/sh", runtime.GOOS) 1849 } 1850 1851 testenv.MustHaveExec(t) 1852 1853 if Getenv("GO_WANT_HELPER_PROCESS") == "1" { 1854 st, err := Stdin.Stat() 1855 if err != nil { 1856 t.Fatalf("Stat failed: %v", err) 1857 } 1858 fmt.Println(st.Mode() & ModeNamedPipe) 1859 Exit(0) 1860 } 1861 1862 fi, err := Stdin.Stat() 1863 if err != nil { 1864 t.Fatal(err) 1865 } 1866 switch mode := fi.Mode(); { 1867 case mode&ModeCharDevice != 0: 1868 case mode&ModeNamedPipe != 0: 1869 default: 1870 t.Fatalf("unexpected Stdin mode (%v), want ModeCharDevice or ModeNamedPipe", mode) 1871 } 1872 1873 var cmd *osexec.Cmd 1874 if runtime.GOOS == "windows" { 1875 cmd = osexec.Command("cmd", "/c", "echo output | "+Args[0]+" -test.run=TestStatStdin") 1876 } else { 1877 cmd = osexec.Command("/bin/sh", "-c", "echo output | "+Args[0]+" -test.run=TestStatStdin") 1878 } 1879 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") 1880 1881 output, err := cmd.CombinedOutput() 1882 if err != nil { 1883 t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) 1884 } 1885 1886 // result will be like "prw-rw-rw" 1887 if len(output) < 1 || output[0] != 'p' { 1888 t.Fatalf("Child process reports stdin is not pipe '%v'", string(output)) 1889 } 1890 } 1891 1892 func TestStatRelativeSymlink(t *testing.T) { 1893 testenv.MustHaveSymlink(t) 1894 1895 tmpdir, err := ioutil.TempDir("", "TestStatRelativeSymlink") 1896 if err != nil { 1897 t.Fatal(err) 1898 } 1899 defer RemoveAll(tmpdir) 1900 1901 target := filepath.Join(tmpdir, "target") 1902 f, err := Create(target) 1903 if err != nil { 1904 t.Fatal(err) 1905 } 1906 defer f.Close() 1907 1908 st, err := f.Stat() 1909 if err != nil { 1910 t.Fatal(err) 1911 } 1912 1913 link := filepath.Join(tmpdir, "link") 1914 err = Symlink(filepath.Base(target), link) 1915 if err != nil { 1916 t.Fatal(err) 1917 } 1918 1919 st1, err := Stat(link) 1920 if err != nil { 1921 t.Fatal(err) 1922 } 1923 1924 if !SameFile(st, st1) { 1925 t.Error("Stat doesn't follow relative symlink") 1926 } 1927 1928 if runtime.GOOS == "windows" { 1929 Remove(link) 1930 err = Symlink(target[len(filepath.VolumeName(target)):], link) 1931 if err != nil { 1932 t.Fatal(err) 1933 } 1934 1935 st1, err := Stat(link) 1936 if err != nil { 1937 t.Fatal(err) 1938 } 1939 1940 if !SameFile(st, st1) { 1941 t.Error("Stat doesn't follow relative symlink") 1942 } 1943 } 1944 } 1945 1946 func TestReadAtEOF(t *testing.T) { 1947 f := newFile("TestReadAtEOF", t) 1948 defer Remove(f.Name()) 1949 defer f.Close() 1950 1951 _, err := f.ReadAt(make([]byte, 10), 0) 1952 switch err { 1953 case io.EOF: 1954 // all good 1955 case nil: 1956 t.Fatalf("ReadAt succeeded") 1957 default: 1958 t.Fatalf("ReadAt failed: %s", err) 1959 } 1960 } 1961 1962 func TestLongPath(t *testing.T) { 1963 tmpdir := newDir("TestLongPath", t) 1964 defer func(d string) { 1965 if err := RemoveAll(d); err != nil { 1966 t.Fatalf("RemoveAll failed: %v", err) 1967 } 1968 }(tmpdir) 1969 1970 // Test the boundary of 247 and fewer bytes (normal) and 248 and more bytes (adjusted). 1971 sizes := []int{247, 248, 249, 400} 1972 for len(tmpdir) < 400 { 1973 tmpdir += "/dir3456789" 1974 } 1975 for _, sz := range sizes { 1976 t.Run(fmt.Sprintf("length=%d", sz), func(t *testing.T) { 1977 sizedTempDir := tmpdir[:sz-1] + "x" // Ensure it does not end with a slash. 1978 1979 // The various sized runs are for this call to trigger the boundary 1980 // condition. 1981 if err := MkdirAll(sizedTempDir, 0755); err != nil { 1982 t.Fatalf("MkdirAll failed: %v", err) 1983 } 1984 data := []byte("hello world\n") 1985 if err := ioutil.WriteFile(sizedTempDir+"/foo.txt", data, 0644); err != nil { 1986 t.Fatalf("ioutil.WriteFile() failed: %v", err) 1987 } 1988 if err := Rename(sizedTempDir+"/foo.txt", sizedTempDir+"/bar.txt"); err != nil { 1989 t.Fatalf("Rename failed: %v", err) 1990 } 1991 mtime := time.Now().Truncate(time.Minute) 1992 if err := Chtimes(sizedTempDir+"/bar.txt", mtime, mtime); err != nil { 1993 t.Fatalf("Chtimes failed: %v", err) 1994 } 1995 names := []string{"bar.txt"} 1996 if testenv.HasSymlink() { 1997 if err := Symlink(sizedTempDir+"/bar.txt", sizedTempDir+"/symlink.txt"); err != nil { 1998 t.Fatalf("Symlink failed: %v", err) 1999 } 2000 names = append(names, "symlink.txt") 2001 } 2002 if testenv.HasLink() { 2003 if err := Link(sizedTempDir+"/bar.txt", sizedTempDir+"/link.txt"); err != nil { 2004 t.Fatalf("Link failed: %v", err) 2005 } 2006 names = append(names, "link.txt") 2007 } 2008 for _, wantSize := range []int64{int64(len(data)), 0} { 2009 for _, name := range names { 2010 path := sizedTempDir + "/" + name 2011 dir, err := Stat(path) 2012 if err != nil { 2013 t.Fatalf("Stat(%q) failed: %v", path, err) 2014 } 2015 filesize := size(path, t) 2016 if dir.Size() != filesize || filesize != wantSize { 2017 t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize) 2018 } 2019 err = Chmod(path, dir.Mode()) 2020 if err != nil { 2021 t.Fatalf("Chmod(%q) failed: %v", path, err) 2022 } 2023 } 2024 if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil { 2025 t.Fatalf("Truncate failed: %v", err) 2026 } 2027 } 2028 }) 2029 } 2030 } 2031 2032 func testKillProcess(t *testing.T, processKiller func(p *Process)) { 2033 testenv.MustHaveExec(t) 2034 2035 // Re-exec the test binary itself to emulate "sleep 1". 2036 cmd := osexec.Command(Args[0], "-test.run", "TestSleep") 2037 err := cmd.Start() 2038 if err != nil { 2039 t.Fatalf("Failed to start test process: %v", err) 2040 } 2041 go func() { 2042 time.Sleep(100 * time.Millisecond) 2043 processKiller(cmd.Process) 2044 }() 2045 err = cmd.Wait() 2046 if err == nil { 2047 t.Errorf("Test process succeeded, but expected to fail") 2048 } 2049 } 2050 2051 // TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we 2052 // don't have to rely on an external "sleep" command being available. 2053 func TestSleep(t *testing.T) { 2054 if testing.Short() { 2055 t.Skip("Skipping in short mode") 2056 } 2057 time.Sleep(time.Second) 2058 } 2059 2060 func TestKillStartProcess(t *testing.T) { 2061 testKillProcess(t, func(p *Process) { 2062 err := p.Kill() 2063 if err != nil { 2064 t.Fatalf("Failed to kill test process: %v", err) 2065 } 2066 }) 2067 } 2068 2069 func TestGetppid(t *testing.T) { 2070 if runtime.GOOS == "plan9" { 2071 // TODO: golang.org/issue/8206 2072 t.Skipf("skipping test on plan9; see issue 8206") 2073 } 2074 2075 testenv.MustHaveExec(t) 2076 2077 if Getenv("GO_WANT_HELPER_PROCESS") == "1" { 2078 fmt.Print(Getppid()) 2079 Exit(0) 2080 } 2081 2082 cmd := osexec.Command(Args[0], "-test.run=TestGetppid") 2083 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") 2084 2085 // verify that Getppid() from the forked process reports our process id 2086 output, err := cmd.CombinedOutput() 2087 if err != nil { 2088 t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) 2089 } 2090 2091 childPpid := string(output) 2092 ourPid := fmt.Sprintf("%d", Getpid()) 2093 if childPpid != ourPid { 2094 t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid) 2095 } 2096 } 2097 2098 func TestKillFindProcess(t *testing.T) { 2099 testKillProcess(t, func(p *Process) { 2100 p2, err := FindProcess(p.Pid) 2101 if err != nil { 2102 t.Fatalf("Failed to find test process: %v", err) 2103 } 2104 err = p2.Kill() 2105 if err != nil { 2106 t.Fatalf("Failed to kill test process: %v", err) 2107 } 2108 }) 2109 } 2110 2111 var nilFileMethodTests = []struct { 2112 name string 2113 f func(*File) error 2114 }{ 2115 {"Chdir", func(f *File) error { return f.Chdir() }}, 2116 {"Close", func(f *File) error { return f.Close() }}, 2117 {"Chmod", func(f *File) error { return f.Chmod(0) }}, 2118 {"Chown", func(f *File) error { return f.Chown(0, 0) }}, 2119 {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }}, 2120 {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }}, 2121 {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }}, 2122 {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }}, 2123 {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }}, 2124 {"Stat", func(f *File) error { _, err := f.Stat(); return err }}, 2125 {"Sync", func(f *File) error { return f.Sync() }}, 2126 {"Truncate", func(f *File) error { return f.Truncate(0) }}, 2127 {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }}, 2128 {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }}, 2129 {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }}, 2130 } 2131 2132 // Test that all File methods give ErrInvalid if the receiver is nil. 2133 func TestNilFileMethods(t *testing.T) { 2134 for _, tt := range nilFileMethodTests { 2135 var file *File 2136 got := tt.f(file) 2137 if got != ErrInvalid { 2138 t.Errorf("%v should fail when f is nil; got %v", tt.name, got) 2139 } 2140 } 2141 } 2142 2143 func mkdirTree(t *testing.T, root string, level, max int) { 2144 if level >= max { 2145 return 2146 } 2147 level++ 2148 for i := 'a'; i < 'c'; i++ { 2149 dir := filepath.Join(root, string(i)) 2150 if err := Mkdir(dir, 0700); err != nil { 2151 t.Fatal(err) 2152 } 2153 mkdirTree(t, dir, level, max) 2154 } 2155 } 2156 2157 // Test that simultaneous RemoveAll do not report an error. 2158 // As long as it gets removed, we should be happy. 2159 func TestRemoveAllRace(t *testing.T) { 2160 if runtime.GOOS == "windows" { 2161 // Windows has very strict rules about things like 2162 // removing directories while someone else has 2163 // them open. The racing doesn't work out nicely 2164 // like it does on Unix. 2165 t.Skip("skipping on windows") 2166 } 2167 2168 n := runtime.GOMAXPROCS(16) 2169 defer runtime.GOMAXPROCS(n) 2170 root, err := ioutil.TempDir("", "issue") 2171 if err != nil { 2172 t.Fatal(err) 2173 } 2174 mkdirTree(t, root, 1, 6) 2175 hold := make(chan struct{}) 2176 var wg sync.WaitGroup 2177 for i := 0; i < 4; i++ { 2178 wg.Add(1) 2179 go func() { 2180 defer wg.Done() 2181 <-hold 2182 err := RemoveAll(root) 2183 if err != nil { 2184 t.Errorf("unexpected error: %T, %q", err, err) 2185 } 2186 }() 2187 } 2188 close(hold) // let workers race to remove root 2189 wg.Wait() 2190 } 2191 2192 // Test that reading from a pipe doesn't use up a thread. 2193 func TestPipeThreads(t *testing.T) { 2194 switch runtime.GOOS { 2195 case "freebsd": 2196 t.Skip("skipping on FreeBSD; issue 19093") 2197 case "solaris": 2198 t.Skip("skipping on Solaris; issue 19111") 2199 case "windows": 2200 t.Skip("skipping on Windows; issue 19098") 2201 case "plan9": 2202 t.Skip("skipping on Plan 9; does not support runtime poller") 2203 } 2204 2205 threads := 100 2206 2207 // OpenBSD has a low default for max number of files. 2208 if runtime.GOOS == "openbsd" { 2209 threads = 50 2210 } 2211 2212 r := make([]*File, threads) 2213 w := make([]*File, threads) 2214 for i := 0; i < threads; i++ { 2215 rp, wp, err := Pipe() 2216 if err != nil { 2217 for j := 0; j < i; j++ { 2218 r[j].Close() 2219 w[j].Close() 2220 } 2221 t.Fatal(err) 2222 } 2223 r[i] = rp 2224 w[i] = wp 2225 } 2226 2227 defer debug.SetMaxThreads(debug.SetMaxThreads(threads / 2)) 2228 2229 creading := make(chan bool, threads) 2230 cdone := make(chan bool, threads) 2231 for i := 0; i < threads; i++ { 2232 go func(i int) { 2233 var b [1]byte 2234 creading <- true 2235 if _, err := r[i].Read(b[:]); err != nil { 2236 t.Error(err) 2237 } 2238 if err := r[i].Close(); err != nil { 2239 t.Error(err) 2240 } 2241 cdone <- true 2242 }(i) 2243 } 2244 2245 for i := 0; i < threads; i++ { 2246 <-creading 2247 } 2248 2249 // If we are still alive, it means that the 100 goroutines did 2250 // not require 100 threads. 2251 2252 for i := 0; i < threads; i++ { 2253 if _, err := w[i].Write([]byte{0}); err != nil { 2254 t.Error(err) 2255 } 2256 if err := w[i].Close(); err != nil { 2257 t.Error(err) 2258 } 2259 <-cdone 2260 } 2261 } 2262 2263 func TestDoubleCloseError(t *testing.T) { 2264 path := sfdir + "/" + sfname 2265 file, err := Open(path) 2266 if err != nil { 2267 t.Fatal(err) 2268 } 2269 if err := file.Close(); err != nil { 2270 t.Fatalf("unexpected error from Close: %v", err) 2271 } 2272 if err := file.Close(); err == nil { 2273 t.Error("second Close did not fail") 2274 } else if pe, ok := err.(*PathError); !ok { 2275 t.Errorf("second Close returned unexpected error type %T; expected os.PathError", pe) 2276 } else if pe.Err != ErrClosed { 2277 t.Errorf("second Close returned %q, wanted %q", err, ErrClosed) 2278 } else { 2279 t.Logf("second close returned expected error %q", err) 2280 } 2281 }