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