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