github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/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 } 725 726 // chtmpdir changes the working directory to a new temporary directory and 727 // provides a cleanup function. Used when PWD is read-only. 728 func chtmpdir(t *testing.T) func() { 729 if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") { 730 return func() {} // only needed on darwin/arm{,64} 731 } 732 oldwd, err := Getwd() 733 if err != nil { 734 t.Fatalf("chtmpdir: %v", err) 735 } 736 d, err := ioutil.TempDir("", "test") 737 if err != nil { 738 t.Fatalf("chtmpdir: %v", err) 739 } 740 if err := Chdir(d); err != nil { 741 t.Fatalf("chtmpdir: %v", err) 742 } 743 return func() { 744 if err := Chdir(oldwd); err != nil { 745 t.Fatalf("chtmpdir: %v", err) 746 } 747 RemoveAll(d) 748 } 749 } 750 751 func TestSymlink(t *testing.T) { 752 testenv.MustHaveSymlink(t) 753 754 defer chtmpdir(t)() 755 from, to := "symlinktestfrom", "symlinktestto" 756 Remove(from) // Just in case. 757 file, err := Create(to) 758 if err != nil { 759 t.Fatalf("Create(%q) failed: %v", to, err) 760 } 761 defer Remove(to) 762 if err = file.Close(); err != nil { 763 t.Errorf("Close(%q) failed: %v", to, err) 764 } 765 err = Symlink(to, from) 766 if err != nil { 767 t.Fatalf("Symlink(%q, %q) failed: %v", to, from, err) 768 } 769 defer Remove(from) 770 tostat, err := Lstat(to) 771 if err != nil { 772 t.Fatalf("Lstat(%q) failed: %v", to, err) 773 } 774 if tostat.Mode()&ModeSymlink != 0 { 775 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = %v, want 0", to, tostat.Mode()&ModeSymlink) 776 } 777 fromstat, err := Stat(from) 778 if err != nil { 779 t.Fatalf("Stat(%q) failed: %v", from, err) 780 } 781 if !SameFile(tostat, fromstat) { 782 t.Errorf("Symlink(%q, %q) did not create symlink", to, from) 783 } 784 fromstat, err = Lstat(from) 785 if err != nil { 786 t.Fatalf("Lstat(%q) failed: %v", from, err) 787 } 788 if fromstat.Mode()&ModeSymlink == 0 { 789 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = 0, want %v", from, ModeSymlink) 790 } 791 fromstat, err = Stat(from) 792 if err != nil { 793 t.Fatalf("Stat(%q) failed: %v", from, err) 794 } 795 if fromstat.Name() != from { 796 t.Errorf("Stat(%q).Name() = %q, want %q", from, fromstat.Name(), from) 797 } 798 if fromstat.Mode()&ModeSymlink != 0 { 799 t.Fatalf("Stat(%q).Mode()&ModeSymlink = %v, want 0", from, fromstat.Mode()&ModeSymlink) 800 } 801 s, err := Readlink(from) 802 if err != nil { 803 t.Fatalf("Readlink(%q) failed: %v", from, err) 804 } 805 if s != to { 806 t.Fatalf("Readlink(%q) = %q, want %q", from, s, to) 807 } 808 file, err = Open(from) 809 if err != nil { 810 t.Fatalf("Open(%q) failed: %v", from, err) 811 } 812 file.Close() 813 } 814 815 func TestLongSymlink(t *testing.T) { 816 testenv.MustHaveSymlink(t) 817 818 defer chtmpdir(t)() 819 s := "0123456789abcdef" 820 // Long, but not too long: a common limit is 255. 821 s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s 822 from := "longsymlinktestfrom" 823 Remove(from) // Just in case. 824 err := Symlink(s, from) 825 if err != nil { 826 t.Fatalf("symlink %q, %q failed: %v", s, from, err) 827 } 828 defer Remove(from) 829 r, err := Readlink(from) 830 if err != nil { 831 t.Fatalf("readlink %q failed: %v", from, err) 832 } 833 if r != s { 834 t.Fatalf("after symlink %q != %q", r, s) 835 } 836 } 837 838 func TestRename(t *testing.T) { 839 defer chtmpdir(t)() 840 from, to := "renamefrom", "renameto" 841 // Ensure we are not testing the overwrite case here. 842 Remove(from) 843 Remove(to) 844 845 file, err := Create(from) 846 if err != nil { 847 t.Fatalf("open %q failed: %v", from, err) 848 } 849 if err = file.Close(); err != nil { 850 t.Errorf("close %q failed: %v", from, err) 851 } 852 err = Rename(from, to) 853 if err != nil { 854 t.Fatalf("rename %q, %q failed: %v", to, from, err) 855 } 856 defer Remove(to) 857 _, err = Stat(to) 858 if err != nil { 859 t.Errorf("stat %q failed: %v", to, err) 860 } 861 } 862 863 func TestRenameOverwriteDest(t *testing.T) { 864 defer chtmpdir(t)() 865 from, to := "renamefrom", "renameto" 866 // Just in case. 867 Remove(from) 868 Remove(to) 869 870 toData := []byte("to") 871 fromData := []byte("from") 872 873 err := ioutil.WriteFile(to, toData, 0777) 874 if err != nil { 875 t.Fatalf("write file %q failed: %v", to, err) 876 } 877 878 err = ioutil.WriteFile(from, fromData, 0777) 879 if err != nil { 880 t.Fatalf("write file %q failed: %v", from, err) 881 } 882 err = Rename(from, to) 883 if err != nil { 884 t.Fatalf("rename %q, %q failed: %v", to, from, err) 885 } 886 defer Remove(to) 887 888 _, err = Stat(from) 889 if err == nil { 890 t.Errorf("from file %q still exists", from) 891 } 892 if err != nil && !IsNotExist(err) { 893 t.Fatalf("stat from: %v", err) 894 } 895 toFi, err := Stat(to) 896 if err != nil { 897 t.Fatalf("stat %q failed: %v", to, err) 898 } 899 if toFi.Size() != int64(len(fromData)) { 900 t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData)) 901 } 902 } 903 904 func TestRenameFailed(t *testing.T) { 905 defer chtmpdir(t)() 906 from, to := "renamefrom", "renameto" 907 // Ensure we are not testing the overwrite case here. 908 Remove(from) 909 Remove(to) 910 911 err := Rename(from, to) 912 switch err := err.(type) { 913 case *LinkError: 914 if err.Op != "rename" { 915 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) 916 } 917 if err.Old != from { 918 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) 919 } 920 if err.New != to { 921 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) 922 } 923 case nil: 924 t.Errorf("rename %q, %q: expected error, got nil", from, to) 925 926 // cleanup whatever was placed in "renameto" 927 Remove(to) 928 default: 929 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 930 } 931 } 932 933 func TestRenameNotExisting(t *testing.T) { 934 defer chtmpdir(t)() 935 from, to := "doesnt-exist", "dest" 936 937 Mkdir(to, 0777) 938 defer Remove(to) 939 940 if err := Rename(from, to); !IsNotExist(err) { 941 t.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from, to, err) 942 } 943 } 944 945 func TestRenameToDirFailed(t *testing.T) { 946 defer chtmpdir(t)() 947 from, to := "renamefrom", "renameto" 948 949 Remove(from) 950 Remove(to) 951 Mkdir(from, 0777) 952 Mkdir(to, 0777) 953 defer Remove(from) 954 defer Remove(to) 955 956 err := Rename(from, to) 957 switch err := err.(type) { 958 case *LinkError: 959 if err.Op != "rename" { 960 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) 961 } 962 if err.Old != from { 963 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) 964 } 965 if err.New != to { 966 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) 967 } 968 case nil: 969 t.Errorf("rename %q, %q: expected error, got nil", from, to) 970 971 // cleanup whatever was placed in "renameto" 972 Remove(to) 973 default: 974 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 975 } 976 } 977 978 func exec(t *testing.T, dir, cmd string, args []string, expect string) { 979 r, w, err := Pipe() 980 if err != nil { 981 t.Fatalf("Pipe: %v", err) 982 } 983 defer r.Close() 984 attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}} 985 p, err := StartProcess(cmd, args, attr) 986 if err != nil { 987 t.Fatalf("StartProcess: %v", err) 988 } 989 w.Close() 990 991 var b bytes.Buffer 992 io.Copy(&b, r) 993 output := b.String() 994 995 fi1, _ := Stat(strings.TrimSpace(output)) 996 fi2, _ := Stat(expect) 997 if !SameFile(fi1, fi2) { 998 t.Errorf("exec %q returned %q wanted %q", 999 strings.Join(append([]string{cmd}, args...), " "), output, expect) 1000 } 1001 p.Wait() 1002 } 1003 1004 func TestStartProcess(t *testing.T) { 1005 testenv.MustHaveExec(t) 1006 1007 var dir, cmd string 1008 var args []string 1009 switch runtime.GOOS { 1010 case "android": 1011 t.Skip("android doesn't have /bin/pwd") 1012 case "windows": 1013 cmd = Getenv("COMSPEC") 1014 dir = Getenv("SystemRoot") 1015 args = []string{"/c", "cd"} 1016 default: 1017 var err error 1018 cmd, err = osexec.LookPath("pwd") 1019 if err != nil { 1020 t.Fatalf("Can't find pwd: %v", err) 1021 } 1022 dir = "/" 1023 args = []string{} 1024 t.Logf("Testing with %v", cmd) 1025 } 1026 cmddir, cmdbase := filepath.Split(cmd) 1027 args = append([]string{cmdbase}, args...) 1028 // Test absolute executable path. 1029 exec(t, dir, cmd, args, dir) 1030 // Test relative executable path. 1031 exec(t, cmddir, cmdbase, args, cmddir) 1032 } 1033 1034 func checkMode(t *testing.T, path string, mode FileMode) { 1035 dir, err := Stat(path) 1036 if err != nil { 1037 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 1038 } 1039 if dir.Mode()&0777 != mode { 1040 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode) 1041 } 1042 } 1043 1044 func TestChmod(t *testing.T) { 1045 // Chmod is not supported under windows. 1046 if runtime.GOOS == "windows" { 1047 return 1048 } 1049 f := newFile("TestChmod", t) 1050 defer Remove(f.Name()) 1051 defer f.Close() 1052 1053 if err := Chmod(f.Name(), 0456); err != nil { 1054 t.Fatalf("chmod %s 0456: %s", f.Name(), err) 1055 } 1056 checkMode(t, f.Name(), 0456) 1057 1058 if err := f.Chmod(0123); err != nil { 1059 t.Fatalf("chmod %s 0123: %s", f.Name(), err) 1060 } 1061 checkMode(t, f.Name(), 0123) 1062 } 1063 1064 func checkSize(t *testing.T, f *File, size int64) { 1065 dir, err := f.Stat() 1066 if err != nil { 1067 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err) 1068 } 1069 if dir.Size() != size { 1070 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size) 1071 } 1072 } 1073 1074 func TestFTruncate(t *testing.T) { 1075 f := newFile("TestFTruncate", t) 1076 defer Remove(f.Name()) 1077 defer f.Close() 1078 1079 checkSize(t, f, 0) 1080 f.Write([]byte("hello, world\n")) 1081 checkSize(t, f, 13) 1082 f.Truncate(10) 1083 checkSize(t, f, 10) 1084 f.Truncate(1024) 1085 checkSize(t, f, 1024) 1086 f.Truncate(0) 1087 checkSize(t, f, 0) 1088 _, err := f.Write([]byte("surprise!")) 1089 if err == nil { 1090 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 1091 } 1092 } 1093 1094 func TestTruncate(t *testing.T) { 1095 f := newFile("TestTruncate", t) 1096 defer Remove(f.Name()) 1097 defer f.Close() 1098 1099 checkSize(t, f, 0) 1100 f.Write([]byte("hello, world\n")) 1101 checkSize(t, f, 13) 1102 Truncate(f.Name(), 10) 1103 checkSize(t, f, 10) 1104 Truncate(f.Name(), 1024) 1105 checkSize(t, f, 1024) 1106 Truncate(f.Name(), 0) 1107 checkSize(t, f, 0) 1108 _, err := f.Write([]byte("surprise!")) 1109 if err == nil { 1110 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 1111 } 1112 } 1113 1114 // Use TempDir (via newFile) to make sure we're on a local file system, 1115 // so that timings are not distorted by latency and caching. 1116 // On NFS, timings can be off due to caching of meta-data on 1117 // NFS servers (Issue 848). 1118 func TestChtimes(t *testing.T) { 1119 f := newFile("TestChtimes", t) 1120 defer Remove(f.Name()) 1121 1122 f.Write([]byte("hello, world\n")) 1123 f.Close() 1124 1125 testChtimes(t, f.Name()) 1126 } 1127 1128 // Use TempDir (via newDir) to make sure we're on a local file system, 1129 // so that timings are not distorted by latency and caching. 1130 // On NFS, timings can be off due to caching of meta-data on 1131 // NFS servers (Issue 848). 1132 func TestChtimesDir(t *testing.T) { 1133 name := newDir("TestChtimes", t) 1134 defer RemoveAll(name) 1135 1136 testChtimes(t, name) 1137 } 1138 1139 func testChtimes(t *testing.T, name string) { 1140 st, err := Stat(name) 1141 if err != nil { 1142 t.Fatalf("Stat %s: %s", name, err) 1143 } 1144 preStat := st 1145 1146 // Move access and modification time back a second 1147 at := Atime(preStat) 1148 mt := preStat.ModTime() 1149 err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second)) 1150 if err != nil { 1151 t.Fatalf("Chtimes %s: %s", name, err) 1152 } 1153 1154 st, err = Stat(name) 1155 if err != nil { 1156 t.Fatalf("second Stat %s: %s", name, err) 1157 } 1158 postStat := st 1159 1160 pat := Atime(postStat) 1161 pmt := postStat.ModTime() 1162 if !pat.Before(at) { 1163 switch runtime.GOOS { 1164 case "plan9", "nacl": 1165 // Ignore. 1166 // Plan 9, NaCl: 1167 // Mtime is the time of the last change of 1168 // content. Similarly, atime is set whenever 1169 // the contents are accessed; also, it is set 1170 // whenever mtime is set. 1171 case "netbsd": 1172 t.Logf("AccessTime didn't go backwards; was=%d, after=%d (Ignoring. See NetBSD issue golang.org/issue/19293)", at, pat) 1173 default: 1174 t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat) 1175 } 1176 } 1177 1178 if !pmt.Before(mt) { 1179 t.Errorf("ModTime didn't go backwards; was=%v, after=%v", mt, pmt) 1180 } 1181 } 1182 1183 func TestChdirAndGetwd(t *testing.T) { 1184 // TODO(brainman): file.Chdir() is not implemented on windows. 1185 if runtime.GOOS == "windows" { 1186 return 1187 } 1188 fd, err := Open(".") 1189 if err != nil { 1190 t.Fatalf("Open .: %s", err) 1191 } 1192 // These are chosen carefully not to be symlinks on a Mac 1193 // (unlike, say, /var, /etc), except /tmp, which we handle below. 1194 dirs := []string{"/", "/usr/bin", "/tmp"} 1195 // /usr/bin does not usually exist on Plan 9 or Android. 1196 switch runtime.GOOS { 1197 case "android": 1198 dirs = []string{"/", "/system/bin"} 1199 case "plan9": 1200 dirs = []string{"/", "/usr"} 1201 case "darwin": 1202 switch runtime.GOARCH { 1203 case "arm", "arm64": 1204 d1, err := ioutil.TempDir("", "d1") 1205 if err != nil { 1206 t.Fatalf("TempDir: %v", err) 1207 } 1208 d2, err := ioutil.TempDir("", "d2") 1209 if err != nil { 1210 t.Fatalf("TempDir: %v", err) 1211 } 1212 dirs = []string{d1, d2} 1213 } 1214 } 1215 oldwd := Getenv("PWD") 1216 for mode := 0; mode < 2; mode++ { 1217 for _, d := range dirs { 1218 if mode == 0 { 1219 err = Chdir(d) 1220 } else { 1221 fd1, err := Open(d) 1222 if err != nil { 1223 t.Errorf("Open %s: %s", d, err) 1224 continue 1225 } 1226 err = fd1.Chdir() 1227 fd1.Close() 1228 } 1229 if d == "/tmp" { 1230 Setenv("PWD", "/tmp") 1231 } 1232 pwd, err1 := Getwd() 1233 Setenv("PWD", oldwd) 1234 err2 := fd.Chdir() 1235 if err2 != nil { 1236 // We changed the current directory and cannot go back. 1237 // Don't let the tests continue; they'll scribble 1238 // all over some other directory. 1239 fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2) 1240 Exit(1) 1241 } 1242 if err != nil { 1243 fd.Close() 1244 t.Fatalf("Chdir %s: %s", d, err) 1245 } 1246 if err1 != nil { 1247 fd.Close() 1248 t.Fatalf("Getwd in %s: %s", d, err1) 1249 } 1250 if pwd != d { 1251 fd.Close() 1252 t.Fatalf("Getwd returned %q want %q", pwd, d) 1253 } 1254 } 1255 } 1256 fd.Close() 1257 } 1258 1259 // Test that Chdir+Getwd is program-wide. 1260 func TestProgWideChdir(t *testing.T) { 1261 const N = 10 1262 c := make(chan bool) 1263 cpwd := make(chan string) 1264 for i := 0; i < N; i++ { 1265 go func(i int) { 1266 // Lock half the goroutines in their own operating system 1267 // thread to exercise more scheduler possibilities. 1268 if i%2 == 1 { 1269 // On Plan 9, after calling LockOSThread, the goroutines 1270 // run on different processes which don't share the working 1271 // directory. This used to be an issue because Go expects 1272 // the working directory to be program-wide. 1273 // See issue 9428. 1274 runtime.LockOSThread() 1275 } 1276 <-c 1277 pwd, err := Getwd() 1278 if err != nil { 1279 t.Errorf("Getwd on goroutine %d: %v", i, err) 1280 return 1281 } 1282 cpwd <- pwd 1283 }(i) 1284 } 1285 oldwd, err := Getwd() 1286 if err != nil { 1287 t.Fatalf("Getwd: %v", err) 1288 } 1289 d, err := ioutil.TempDir("", "test") 1290 if err != nil { 1291 t.Fatalf("TempDir: %v", err) 1292 } 1293 defer func() { 1294 if err := Chdir(oldwd); err != nil { 1295 t.Fatalf("Chdir: %v", err) 1296 } 1297 RemoveAll(d) 1298 }() 1299 if err := Chdir(d); err != nil { 1300 t.Fatalf("Chdir: %v", err) 1301 } 1302 // OS X sets TMPDIR to a symbolic link. 1303 // So we resolve our working directory again before the test. 1304 d, err = Getwd() 1305 if err != nil { 1306 t.Fatalf("Getwd: %v", err) 1307 } 1308 close(c) 1309 for i := 0; i < N; i++ { 1310 pwd := <-cpwd 1311 if pwd != d { 1312 t.Errorf("Getwd returned %q; want %q", pwd, d) 1313 } 1314 } 1315 } 1316 1317 func TestSeek(t *testing.T) { 1318 f := newFile("TestSeek", t) 1319 defer Remove(f.Name()) 1320 defer f.Close() 1321 1322 const data = "hello, world\n" 1323 io.WriteString(f, data) 1324 1325 type test struct { 1326 in int64 1327 whence int 1328 out int64 1329 } 1330 var tests = []test{ 1331 {0, io.SeekCurrent, int64(len(data))}, 1332 {0, io.SeekStart, 0}, 1333 {5, io.SeekStart, 5}, 1334 {0, io.SeekEnd, int64(len(data))}, 1335 {0, io.SeekStart, 0}, 1336 {-1, io.SeekEnd, int64(len(data)) - 1}, 1337 {1 << 33, io.SeekStart, 1 << 33}, 1338 {1 << 33, io.SeekEnd, 1<<33 + int64(len(data))}, 1339 } 1340 for i, tt := range tests { 1341 off, err := f.Seek(tt.in, tt.whence) 1342 if off != tt.out || err != nil { 1343 if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 { 1344 // Reiserfs rejects the big seeks. 1345 // https://golang.org/issue/91 1346 break 1347 } 1348 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out) 1349 } 1350 } 1351 } 1352 1353 func TestSeekError(t *testing.T) { 1354 switch runtime.GOOS { 1355 case "plan9", "nacl": 1356 t.Skipf("skipping test on %v", runtime.GOOS) 1357 } 1358 1359 r, w, err := Pipe() 1360 if err != nil { 1361 t.Fatal(err) 1362 } 1363 _, err = r.Seek(0, 0) 1364 if err == nil { 1365 t.Fatal("Seek on pipe should fail") 1366 } 1367 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE { 1368 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err) 1369 } 1370 _, err = w.Seek(0, 0) 1371 if err == nil { 1372 t.Fatal("Seek on pipe should fail") 1373 } 1374 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE { 1375 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err) 1376 } 1377 } 1378 1379 type openErrorTest struct { 1380 path string 1381 mode int 1382 error error 1383 } 1384 1385 var openErrorTests = []openErrorTest{ 1386 { 1387 sfdir + "/no-such-file", 1388 O_RDONLY, 1389 syscall.ENOENT, 1390 }, 1391 { 1392 sfdir, 1393 O_WRONLY, 1394 syscall.EISDIR, 1395 }, 1396 { 1397 sfdir + "/" + sfname + "/no-such-file", 1398 O_WRONLY, 1399 syscall.ENOTDIR, 1400 }, 1401 } 1402 1403 func TestOpenError(t *testing.T) { 1404 for _, tt := range openErrorTests { 1405 f, err := OpenFile(tt.path, tt.mode, 0) 1406 if err == nil { 1407 t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode) 1408 f.Close() 1409 continue 1410 } 1411 perr, ok := err.(*PathError) 1412 if !ok { 1413 t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err) 1414 } 1415 if perr.Err != tt.error { 1416 if runtime.GOOS == "plan9" { 1417 syscallErrStr := perr.Err.Error() 1418 expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1) 1419 if !strings.HasSuffix(syscallErrStr, expectedErrStr) { 1420 // Some Plan 9 file servers incorrectly return 1421 // EACCES rather than EISDIR when a directory is 1422 // opened for write. 1423 if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) { 1424 continue 1425 } 1426 t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr) 1427 } 1428 continue 1429 } 1430 if runtime.GOOS == "dragonfly" { 1431 // DragonFly incorrectly returns EACCES rather 1432 // EISDIR when a directory is opened for write. 1433 if tt.error == syscall.EISDIR && perr.Err == syscall.EACCES { 1434 continue 1435 } 1436 } 1437 t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error()) 1438 } 1439 } 1440 } 1441 1442 func TestOpenNoName(t *testing.T) { 1443 f, err := Open("") 1444 if err == nil { 1445 t.Fatal(`Open("") succeeded`) 1446 f.Close() 1447 } 1448 } 1449 1450 func runBinHostname(t *testing.T) string { 1451 // Run /bin/hostname and collect output. 1452 r, w, err := Pipe() 1453 if err != nil { 1454 t.Fatal(err) 1455 } 1456 defer r.Close() 1457 const path = "/bin/hostname" 1458 p, err := StartProcess(path, []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}}) 1459 if err != nil { 1460 if _, err := Stat(path); IsNotExist(err) { 1461 t.Skipf("skipping test; test requires %s but it does not exist", path) 1462 } 1463 t.Fatal(err) 1464 } 1465 w.Close() 1466 1467 var b bytes.Buffer 1468 io.Copy(&b, r) 1469 _, err = p.Wait() 1470 if err != nil { 1471 t.Fatalf("run hostname Wait: %v", err) 1472 } 1473 err = p.Kill() 1474 if err == nil { 1475 t.Errorf("expected an error from Kill running 'hostname'") 1476 } 1477 output := b.String() 1478 if n := len(output); n > 0 && output[n-1] == '\n' { 1479 output = output[0 : n-1] 1480 } 1481 if output == "" { 1482 t.Fatalf("/bin/hostname produced no output") 1483 } 1484 1485 return output 1486 } 1487 1488 func testWindowsHostname(t *testing.T) { 1489 hostname, err := Hostname() 1490 if err != nil { 1491 t.Fatal(err) 1492 } 1493 cmd := osexec.Command("hostname") 1494 out, err := cmd.CombinedOutput() 1495 if err != nil { 1496 t.Fatalf("Failed to execute hostname command: %v %s", err, out) 1497 } 1498 want := strings.Trim(string(out), "\r\n") 1499 if hostname != want { 1500 t.Fatalf("Hostname() = %q, want %q", hostname, want) 1501 } 1502 } 1503 1504 func TestHostname(t *testing.T) { 1505 // There is no other way to fetch hostname on windows, but via winapi. 1506 // On Plan 9 it can be taken from #c/sysname as Hostname() does. 1507 switch runtime.GOOS { 1508 case "android", "plan9": 1509 t.Skipf("%s doesn't have /bin/hostname", runtime.GOOS) 1510 case "windows": 1511 testWindowsHostname(t) 1512 return 1513 } 1514 1515 testenv.MustHaveExec(t) 1516 1517 // Check internal Hostname() against the output of /bin/hostname. 1518 // Allow that the internal Hostname returns a Fully Qualified Domain Name 1519 // and the /bin/hostname only returns the first component 1520 hostname, err := Hostname() 1521 if err != nil { 1522 t.Fatalf("%v", err) 1523 } 1524 want := runBinHostname(t) 1525 if hostname != want { 1526 i := strings.Index(hostname, ".") 1527 if i < 0 || hostname[0:i] != want { 1528 t.Errorf("Hostname() = %q, want %q", hostname, want) 1529 } 1530 } 1531 } 1532 1533 func TestReadAt(t *testing.T) { 1534 f := newFile("TestReadAt", t) 1535 defer Remove(f.Name()) 1536 defer f.Close() 1537 1538 const data = "hello, world\n" 1539 io.WriteString(f, data) 1540 1541 b := make([]byte, 5) 1542 n, err := f.ReadAt(b, 7) 1543 if err != nil || n != len(b) { 1544 t.Fatalf("ReadAt 7: %d, %v", n, err) 1545 } 1546 if string(b) != "world" { 1547 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 1548 } 1549 } 1550 1551 // Verify that ReadAt doesn't affect seek offset. 1552 // In the Plan 9 kernel, there used to be a bug in the implementation of 1553 // the pread syscall, where the channel offset was erroneously updated after 1554 // calling pread on a file. 1555 func TestReadAtOffset(t *testing.T) { 1556 f := newFile("TestReadAtOffset", t) 1557 defer Remove(f.Name()) 1558 defer f.Close() 1559 1560 const data = "hello, world\n" 1561 io.WriteString(f, data) 1562 1563 f.Seek(0, 0) 1564 b := make([]byte, 5) 1565 1566 n, err := f.ReadAt(b, 7) 1567 if err != nil || n != len(b) { 1568 t.Fatalf("ReadAt 7: %d, %v", n, err) 1569 } 1570 if string(b) != "world" { 1571 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 1572 } 1573 1574 n, err = f.Read(b) 1575 if err != nil || n != len(b) { 1576 t.Fatalf("Read: %d, %v", n, err) 1577 } 1578 if string(b) != "hello" { 1579 t.Fatalf("Read: have %q want %q", string(b), "hello") 1580 } 1581 } 1582 1583 // Verify that ReadAt doesn't allow negative offset. 1584 func TestReadAtNegativeOffset(t *testing.T) { 1585 f := newFile("TestReadAtNegativeOffset", t) 1586 defer Remove(f.Name()) 1587 defer f.Close() 1588 1589 const data = "hello, world\n" 1590 io.WriteString(f, data) 1591 1592 f.Seek(0, 0) 1593 b := make([]byte, 5) 1594 1595 n, err := f.ReadAt(b, -10) 1596 1597 const wantsub = "negative offset" 1598 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 { 1599 t.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub) 1600 } 1601 } 1602 1603 func TestWriteAt(t *testing.T) { 1604 f := newFile("TestWriteAt", t) 1605 defer Remove(f.Name()) 1606 defer f.Close() 1607 1608 const data = "hello, world\n" 1609 io.WriteString(f, data) 1610 1611 n, err := f.WriteAt([]byte("WORLD"), 7) 1612 if err != nil || n != 5 { 1613 t.Fatalf("WriteAt 7: %d, %v", n, err) 1614 } 1615 1616 b, err := ioutil.ReadFile(f.Name()) 1617 if err != nil { 1618 t.Fatalf("ReadFile %s: %v", f.Name(), err) 1619 } 1620 if string(b) != "hello, WORLD\n" { 1621 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n") 1622 } 1623 } 1624 1625 // Verify that WriteAt doesn't allow negative offset. 1626 func TestWriteAtNegativeOffset(t *testing.T) { 1627 f := newFile("TestWriteAtNegativeOffset", t) 1628 defer Remove(f.Name()) 1629 defer f.Close() 1630 1631 n, err := f.WriteAt([]byte("WORLD"), -10) 1632 1633 const wantsub = "negative offset" 1634 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 { 1635 t.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub) 1636 } 1637 } 1638 1639 func writeFile(t *testing.T, fname string, flag int, text string) string { 1640 f, err := OpenFile(fname, flag, 0666) 1641 if err != nil { 1642 t.Fatalf("Open: %v", err) 1643 } 1644 n, err := io.WriteString(f, text) 1645 if err != nil { 1646 t.Fatalf("WriteString: %d, %v", n, err) 1647 } 1648 f.Close() 1649 data, err := ioutil.ReadFile(fname) 1650 if err != nil { 1651 t.Fatalf("ReadFile: %v", err) 1652 } 1653 return string(data) 1654 } 1655 1656 func TestAppend(t *testing.T) { 1657 defer chtmpdir(t)() 1658 const f = "append.txt" 1659 defer Remove(f) 1660 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 1661 if s != "new" { 1662 t.Fatalf("writeFile: have %q want %q", s, "new") 1663 } 1664 s = writeFile(t, f, O_APPEND|O_RDWR, "|append") 1665 if s != "new|append" { 1666 t.Fatalf("writeFile: have %q want %q", s, "new|append") 1667 } 1668 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append") 1669 if s != "new|append|append" { 1670 t.Fatalf("writeFile: have %q want %q", s, "new|append|append") 1671 } 1672 err := Remove(f) 1673 if err != nil { 1674 t.Fatalf("Remove: %v", err) 1675 } 1676 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append") 1677 if s != "new&append" { 1678 t.Fatalf("writeFile: after append have %q want %q", s, "new&append") 1679 } 1680 s = writeFile(t, f, O_CREATE|O_RDWR, "old") 1681 if s != "old&append" { 1682 t.Fatalf("writeFile: after create have %q want %q", s, "old&append") 1683 } 1684 s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 1685 if s != "new" { 1686 t.Fatalf("writeFile: after truncate have %q want %q", s, "new") 1687 } 1688 } 1689 1690 func TestStatDirWithTrailingSlash(t *testing.T) { 1691 // Create new temporary directory and arrange to clean it up. 1692 path, err := ioutil.TempDir("", "/_TestStatDirWithSlash_") 1693 if err != nil { 1694 t.Fatalf("TempDir: %s", err) 1695 } 1696 defer RemoveAll(path) 1697 1698 // Stat of path should succeed. 1699 _, err = Stat(path) 1700 if err != nil { 1701 t.Fatalf("stat %s failed: %s", path, err) 1702 } 1703 1704 // Stat of path+"/" should succeed too. 1705 path += "/" 1706 _, err = Stat(path) 1707 if err != nil { 1708 t.Fatalf("stat %s failed: %s", path, err) 1709 } 1710 } 1711 1712 func TestNilProcessStateString(t *testing.T) { 1713 var ps *ProcessState 1714 s := ps.String() 1715 if s != "<nil>" { 1716 t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>") 1717 } 1718 } 1719 1720 func TestSameFile(t *testing.T) { 1721 defer chtmpdir(t)() 1722 fa, err := Create("a") 1723 if err != nil { 1724 t.Fatalf("Create(a): %v", err) 1725 } 1726 defer Remove(fa.Name()) 1727 fa.Close() 1728 fb, err := Create("b") 1729 if err != nil { 1730 t.Fatalf("Create(b): %v", err) 1731 } 1732 defer Remove(fb.Name()) 1733 fb.Close() 1734 1735 ia1, err := Stat("a") 1736 if err != nil { 1737 t.Fatalf("Stat(a): %v", err) 1738 } 1739 ia2, err := Stat("a") 1740 if err != nil { 1741 t.Fatalf("Stat(a): %v", err) 1742 } 1743 if !SameFile(ia1, ia2) { 1744 t.Errorf("files should be same") 1745 } 1746 1747 ib, err := Stat("b") 1748 if err != nil { 1749 t.Fatalf("Stat(b): %v", err) 1750 } 1751 if SameFile(ia1, ib) { 1752 t.Errorf("files should be different") 1753 } 1754 } 1755 1756 func TestDevNullFile(t *testing.T) { 1757 f, err := Open(DevNull) 1758 if err != nil { 1759 t.Fatalf("Open(%s): %v", DevNull, err) 1760 } 1761 defer f.Close() 1762 fi, err := f.Stat() 1763 if err != nil { 1764 t.Fatalf("Stat(%s): %v", DevNull, err) 1765 } 1766 name := filepath.Base(DevNull) 1767 if fi.Name() != name { 1768 t.Fatalf("wrong file name have %v want %v", fi.Name(), name) 1769 } 1770 if fi.Size() != 0 { 1771 t.Fatalf("wrong file size have %d want 0", fi.Size()) 1772 } 1773 } 1774 1775 var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output") 1776 1777 func TestLargeWriteToConsole(t *testing.T) { 1778 if !*testLargeWrite { 1779 t.Skip("skipping console-flooding test; enable with -large_write") 1780 } 1781 b := make([]byte, 32000) 1782 for i := range b { 1783 b[i] = '.' 1784 } 1785 b[len(b)-1] = '\n' 1786 n, err := Stdout.Write(b) 1787 if err != nil { 1788 t.Fatalf("Write to os.Stdout failed: %v", err) 1789 } 1790 if n != len(b) { 1791 t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n) 1792 } 1793 n, err = Stderr.Write(b) 1794 if err != nil { 1795 t.Fatalf("Write to os.Stderr failed: %v", err) 1796 } 1797 if n != len(b) { 1798 t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n) 1799 } 1800 } 1801 1802 func TestStatDirModeExec(t *testing.T) { 1803 const mode = 0111 1804 1805 path, err := ioutil.TempDir("", "go-build") 1806 if err != nil { 1807 t.Fatalf("Failed to create temp directory: %v", err) 1808 } 1809 defer RemoveAll(path) 1810 1811 if err := Chmod(path, 0777); err != nil { 1812 t.Fatalf("Chmod %q 0777: %v", path, err) 1813 } 1814 1815 dir, err := Stat(path) 1816 if err != nil { 1817 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 1818 } 1819 if dir.Mode()&mode != mode { 1820 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode) 1821 } 1822 } 1823 1824 func TestStatStdin(t *testing.T) { 1825 switch runtime.GOOS { 1826 case "android", "plan9": 1827 t.Skipf("%s doesn't have /bin/sh", runtime.GOOS) 1828 } 1829 1830 testenv.MustHaveExec(t) 1831 1832 if Getenv("GO_WANT_HELPER_PROCESS") == "1" { 1833 st, err := Stdin.Stat() 1834 if err != nil { 1835 t.Fatalf("Stat failed: %v", err) 1836 } 1837 fmt.Println(st.Mode() & ModeNamedPipe) 1838 Exit(0) 1839 } 1840 1841 fi, err := Stdin.Stat() 1842 if err != nil { 1843 t.Fatal(err) 1844 } 1845 switch mode := fi.Mode(); { 1846 case mode&ModeCharDevice != 0: 1847 case mode&ModeNamedPipe != 0: 1848 default: 1849 t.Fatalf("unexpected Stdin mode (%v), want ModeCharDevice or ModeNamedPipe", mode) 1850 } 1851 1852 var cmd *osexec.Cmd 1853 if runtime.GOOS == "windows" { 1854 cmd = osexec.Command("cmd", "/c", "echo output | "+Args[0]+" -test.run=TestStatStdin") 1855 } else { 1856 cmd = osexec.Command("/bin/sh", "-c", "echo output | "+Args[0]+" -test.run=TestStatStdin") 1857 } 1858 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") 1859 1860 output, err := cmd.CombinedOutput() 1861 if err != nil { 1862 t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) 1863 } 1864 1865 // result will be like "prw-rw-rw" 1866 if len(output) < 1 || output[0] != 'p' { 1867 t.Fatalf("Child process reports stdin is not pipe '%v'", string(output)) 1868 } 1869 } 1870 1871 func TestStatRelativeSymlink(t *testing.T) { 1872 testenv.MustHaveSymlink(t) 1873 1874 tmpdir, err := ioutil.TempDir("", "TestStatRelativeSymlink") 1875 if err != nil { 1876 t.Fatal(err) 1877 } 1878 defer RemoveAll(tmpdir) 1879 1880 target := filepath.Join(tmpdir, "target") 1881 f, err := Create(target) 1882 if err != nil { 1883 t.Fatal(err) 1884 } 1885 defer f.Close() 1886 1887 st, err := f.Stat() 1888 if err != nil { 1889 t.Fatal(err) 1890 } 1891 1892 link := filepath.Join(tmpdir, "link") 1893 err = Symlink(filepath.Base(target), link) 1894 if err != nil { 1895 t.Fatal(err) 1896 } 1897 1898 st1, err := Stat(link) 1899 if err != nil { 1900 t.Fatal(err) 1901 } 1902 1903 if !SameFile(st, st1) { 1904 t.Error("Stat doesn't follow relative symlink") 1905 } 1906 1907 if runtime.GOOS == "windows" { 1908 Remove(link) 1909 err = Symlink(target[len(filepath.VolumeName(target)):], link) 1910 if err != nil { 1911 t.Fatal(err) 1912 } 1913 1914 st1, err := Stat(link) 1915 if err != nil { 1916 t.Fatal(err) 1917 } 1918 1919 if !SameFile(st, st1) { 1920 t.Error("Stat doesn't follow relative symlink") 1921 } 1922 } 1923 } 1924 1925 func TestReadAtEOF(t *testing.T) { 1926 f := newFile("TestReadAtEOF", t) 1927 defer Remove(f.Name()) 1928 defer f.Close() 1929 1930 _, err := f.ReadAt(make([]byte, 10), 0) 1931 switch err { 1932 case io.EOF: 1933 // all good 1934 case nil: 1935 t.Fatalf("ReadAt succeeded") 1936 default: 1937 t.Fatalf("ReadAt failed: %s", err) 1938 } 1939 } 1940 1941 func TestLongPath(t *testing.T) { 1942 tmpdir := newDir("TestLongPath", t) 1943 defer func(d string) { 1944 if err := RemoveAll(d); err != nil { 1945 t.Fatalf("RemoveAll failed: %v", err) 1946 } 1947 }(tmpdir) 1948 1949 // Test the boundary of 247 and fewer bytes (normal) and 248 and more bytes (adjusted). 1950 sizes := []int{247, 248, 249, 400} 1951 for len(tmpdir) < 400 { 1952 tmpdir += "/dir3456789" 1953 } 1954 for _, sz := range sizes { 1955 t.Run(fmt.Sprintf("length=%d", sz), func(t *testing.T) { 1956 sizedTempDir := tmpdir[:sz-1] + "x" // Ensure it does not end with a slash. 1957 1958 // The various sized runs are for this call to trigger the boundary 1959 // condition. 1960 if err := MkdirAll(sizedTempDir, 0755); err != nil { 1961 t.Fatalf("MkdirAll failed: %v", err) 1962 } 1963 data := []byte("hello world\n") 1964 if err := ioutil.WriteFile(sizedTempDir+"/foo.txt", data, 0644); err != nil { 1965 t.Fatalf("ioutil.WriteFile() failed: %v", err) 1966 } 1967 if err := Rename(sizedTempDir+"/foo.txt", sizedTempDir+"/bar.txt"); err != nil { 1968 t.Fatalf("Rename failed: %v", err) 1969 } 1970 mtime := time.Now().Truncate(time.Minute) 1971 if err := Chtimes(sizedTempDir+"/bar.txt", mtime, mtime); err != nil { 1972 t.Fatalf("Chtimes failed: %v", err) 1973 } 1974 names := []string{"bar.txt"} 1975 if testenv.HasSymlink() { 1976 if err := Symlink(sizedTempDir+"/bar.txt", sizedTempDir+"/symlink.txt"); err != nil { 1977 t.Fatalf("Symlink failed: %v", err) 1978 } 1979 names = append(names, "symlink.txt") 1980 } 1981 if testenv.HasLink() { 1982 if err := Link(sizedTempDir+"/bar.txt", sizedTempDir+"/link.txt"); err != nil { 1983 t.Fatalf("Link failed: %v", err) 1984 } 1985 names = append(names, "link.txt") 1986 } 1987 for _, wantSize := range []int64{int64(len(data)), 0} { 1988 for _, name := range names { 1989 path := sizedTempDir + "/" + name 1990 dir, err := Stat(path) 1991 if err != nil { 1992 t.Fatalf("Stat(%q) failed: %v", path, err) 1993 } 1994 filesize := size(path, t) 1995 if dir.Size() != filesize || filesize != wantSize { 1996 t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize) 1997 } 1998 err = Chmod(path, dir.Mode()) 1999 if err != nil { 2000 t.Fatalf("Chmod(%q) failed: %v", path, err) 2001 } 2002 } 2003 if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil { 2004 t.Fatalf("Truncate failed: %v", err) 2005 } 2006 } 2007 }) 2008 } 2009 } 2010 2011 func testKillProcess(t *testing.T, processKiller func(p *Process)) { 2012 testenv.MustHaveExec(t) 2013 2014 // Re-exec the test binary itself to emulate "sleep 1". 2015 cmd := osexec.Command(Args[0], "-test.run", "TestSleep") 2016 err := cmd.Start() 2017 if err != nil { 2018 t.Fatalf("Failed to start test process: %v", err) 2019 } 2020 go func() { 2021 time.Sleep(100 * time.Millisecond) 2022 processKiller(cmd.Process) 2023 }() 2024 err = cmd.Wait() 2025 if err == nil { 2026 t.Errorf("Test process succeeded, but expected to fail") 2027 } 2028 } 2029 2030 // TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we 2031 // don't have to rely on an external "sleep" command being available. 2032 func TestSleep(t *testing.T) { 2033 if testing.Short() { 2034 t.Skip("Skipping in short mode") 2035 } 2036 time.Sleep(time.Second) 2037 } 2038 2039 func TestKillStartProcess(t *testing.T) { 2040 testKillProcess(t, func(p *Process) { 2041 err := p.Kill() 2042 if err != nil { 2043 t.Fatalf("Failed to kill test process: %v", err) 2044 } 2045 }) 2046 } 2047 2048 func TestGetppid(t *testing.T) { 2049 if runtime.GOOS == "plan9" { 2050 // TODO: golang.org/issue/8206 2051 t.Skipf("skipping test on plan9; see issue 8206") 2052 } 2053 2054 testenv.MustHaveExec(t) 2055 2056 if Getenv("GO_WANT_HELPER_PROCESS") == "1" { 2057 fmt.Print(Getppid()) 2058 Exit(0) 2059 } 2060 2061 cmd := osexec.Command(Args[0], "-test.run=TestGetppid") 2062 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") 2063 2064 // verify that Getppid() from the forked process reports our process id 2065 output, err := cmd.CombinedOutput() 2066 if err != nil { 2067 t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) 2068 } 2069 2070 childPpid := string(output) 2071 ourPid := fmt.Sprintf("%d", Getpid()) 2072 if childPpid != ourPid { 2073 t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid) 2074 } 2075 } 2076 2077 func TestKillFindProcess(t *testing.T) { 2078 testKillProcess(t, func(p *Process) { 2079 p2, err := FindProcess(p.Pid) 2080 if err != nil { 2081 t.Fatalf("Failed to find test process: %v", err) 2082 } 2083 err = p2.Kill() 2084 if err != nil { 2085 t.Fatalf("Failed to kill test process: %v", err) 2086 } 2087 }) 2088 } 2089 2090 var nilFileMethodTests = []struct { 2091 name string 2092 f func(*File) error 2093 }{ 2094 {"Chdir", func(f *File) error { return f.Chdir() }}, 2095 {"Close", func(f *File) error { return f.Close() }}, 2096 {"Chmod", func(f *File) error { return f.Chmod(0) }}, 2097 {"Chown", func(f *File) error { return f.Chown(0, 0) }}, 2098 {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }}, 2099 {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }}, 2100 {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }}, 2101 {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }}, 2102 {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }}, 2103 {"Stat", func(f *File) error { _, err := f.Stat(); return err }}, 2104 {"Sync", func(f *File) error { return f.Sync() }}, 2105 {"Truncate", func(f *File) error { return f.Truncate(0) }}, 2106 {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }}, 2107 {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }}, 2108 {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }}, 2109 } 2110 2111 // Test that all File methods give ErrInvalid if the receiver is nil. 2112 func TestNilFileMethods(t *testing.T) { 2113 for _, tt := range nilFileMethodTests { 2114 var file *File 2115 got := tt.f(file) 2116 if got != ErrInvalid { 2117 t.Errorf("%v should fail when f is nil; got %v", tt.name, got) 2118 } 2119 } 2120 } 2121 2122 func mkdirTree(t *testing.T, root string, level, max int) { 2123 if level >= max { 2124 return 2125 } 2126 level++ 2127 for i := 'a'; i < 'c'; i++ { 2128 dir := filepath.Join(root, string(i)) 2129 if err := Mkdir(dir, 0700); err != nil { 2130 t.Fatal(err) 2131 } 2132 mkdirTree(t, dir, level, max) 2133 } 2134 } 2135 2136 // Test that simultaneous RemoveAll do not report an error. 2137 // As long as it gets removed, we should be happy. 2138 func TestRemoveAllRace(t *testing.T) { 2139 if runtime.GOOS == "windows" { 2140 // Windows has very strict rules about things like 2141 // removing directories while someone else has 2142 // them open. The racing doesn't work out nicely 2143 // like it does on Unix. 2144 t.Skip("skipping on windows") 2145 } 2146 2147 n := runtime.GOMAXPROCS(16) 2148 defer runtime.GOMAXPROCS(n) 2149 root, err := ioutil.TempDir("", "issue") 2150 if err != nil { 2151 t.Fatal(err) 2152 } 2153 mkdirTree(t, root, 1, 6) 2154 hold := make(chan struct{}) 2155 var wg sync.WaitGroup 2156 for i := 0; i < 4; i++ { 2157 wg.Add(1) 2158 go func() { 2159 defer wg.Done() 2160 <-hold 2161 err := RemoveAll(root) 2162 if err != nil { 2163 t.Errorf("unexpected error: %T, %q", err, err) 2164 } 2165 }() 2166 } 2167 close(hold) // let workers race to remove root 2168 wg.Wait() 2169 } 2170 2171 // Test that reading from a pipe doesn't use up a thread. 2172 func TestPipeThreads(t *testing.T) { 2173 switch runtime.GOOS { 2174 case "freebsd": 2175 t.Skip("skipping on FreeBSD; issue 19093") 2176 case "solaris": 2177 t.Skip("skipping on Solaris; issue 19111") 2178 case "windows": 2179 t.Skip("skipping on Windows; issue 19098") 2180 case "plan9": 2181 t.Skip("skipping on Plan 9; does not support runtime poller") 2182 } 2183 2184 threads := 100 2185 2186 // OpenBSD has a low default for max number of files. 2187 if runtime.GOOS == "openbsd" { 2188 threads = 50 2189 } 2190 2191 r := make([]*File, threads) 2192 w := make([]*File, threads) 2193 for i := 0; i < threads; i++ { 2194 rp, wp, err := Pipe() 2195 if err != nil { 2196 for j := 0; j < i; j++ { 2197 r[j].Close() 2198 w[j].Close() 2199 } 2200 t.Fatal(err) 2201 } 2202 r[i] = rp 2203 w[i] = wp 2204 } 2205 2206 defer debug.SetMaxThreads(debug.SetMaxThreads(threads / 2)) 2207 2208 var wg sync.WaitGroup 2209 wg.Add(threads) 2210 c := make(chan bool, threads) 2211 for i := 0; i < threads; i++ { 2212 go func(i int) { 2213 defer wg.Done() 2214 var b [1]byte 2215 c <- true 2216 if _, err := r[i].Read(b[:]); err != nil { 2217 t.Error(err) 2218 } 2219 }(i) 2220 } 2221 2222 for i := 0; i < threads; i++ { 2223 <-c 2224 } 2225 2226 // If we are still alive, it means that the 100 goroutines did 2227 // not require 100 threads. 2228 2229 for i := 0; i < threads; i++ { 2230 if _, err := w[i].Write([]byte{0}); err != nil { 2231 t.Error(err) 2232 } 2233 if err := w[i].Close(); err != nil { 2234 t.Error(err) 2235 } 2236 } 2237 2238 wg.Wait() 2239 2240 for i := 0; i < threads; i++ { 2241 if err := r[i].Close(); err != nil { 2242 t.Error(err) 2243 } 2244 } 2245 } 2246 2247 func TestDoubleCloseError(t *testing.T) { 2248 path := sfdir + "/" + sfname 2249 file, err := Open(path) 2250 if err != nil { 2251 t.Fatal(err) 2252 } 2253 if err := file.Close(); err != nil { 2254 t.Fatalf("unexpected error from Close: %v", err) 2255 } 2256 if err := file.Close(); err == nil { 2257 t.Error("second Close did not fail") 2258 } else if pe, ok := err.(*PathError); !ok { 2259 t.Errorf("second Close returned unexpected error type %T; expected os.PathError", pe) 2260 } else if pe.Err != ErrClosed { 2261 t.Errorf("second Close returned %q, wanted %q", err, ErrClosed) 2262 } else { 2263 t.Logf("second close returned expected error %q", err) 2264 } 2265 }