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