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