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