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