diff --git a/src/os/os_chmod_test.go b/src/os/os_chmod_test.go index 6b72b4319c..af7fef52c0 100644 --- a/src/os/os_chmod_test.go +++ b/src/os/os_chmod_test.go @@ -33,75 +33,36 @@ func TestChmod(t *testing.T) { } -func TestChown(t *testing.T) { - var ( - TEST_UID_1 = 1001 - TEST_GID_1 = 127 - TEST_UID_2 = 0 - TEST_GID_2 = 0 - ERR_PERM_DENIED = "permission denied" - ERR_OP_NOT_PERMITTED = "operation not permitted" - ) - +// Since testing syscalls requires a static, predictable environment that has to be controlled +// by the CI, we don't test for success but for failures and verify that the error messages are as expected. +// EACCES is returned when the user does not have the required permissions to change the ownership of the file +// ENOENT is returned when the file does not exist +// ENOTDIR is returned when the file is not a directory +func TestChownErr(t *testing.T) { if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { - t.Skip() + t.Skip("skipping on " + runtime.GOOS) } + var ( + TEST_UID_ROOT = 0 + TEST_GID_ROOT = 0 + ) + f := newFile("TestChown", t) defer Remove(f.Name()) defer f.Close() - // User with CI permissions run chown on owned file - // This test does not change the initial permissions of the file - // It only checks if the chown operation was successful and consistent - if err := Chown(f.Name(), TEST_UID_1, TEST_GID_1); err != nil { - if err.Error() != ERR_OP_NOT_PERMITTED { - t.Fatalf("chown(%s, uid=%v, gid=%v): got %v, want != nil", f.Name(), TEST_UID_1, TEST_GID_1, err) + // EACCES + if err := Chown(f.Name(), TEST_UID_ROOT, TEST_GID_ROOT); err != nil { + if err.(syscall.Errno) != syscall.EPERM { + t.Fatalf("chown(%s, uid=%v, gid=%v): got '%v', want %v", f.Name(), TEST_UID_ROOT, TEST_GID_ROOT, err, syscall.EPERM) } } - fi, err := Stat(f.Name()) - if err != nil { - t.Fatalf("stat %s: got %v, want nil", f.Name(), err) - } - - if fi.Sys() == nil { - t.Fatalf("stat %s: fi.Sys(): got nil", f.Name()) - } - - s, ok := fi.Sys().(*syscall.Stat_t) - if !ok { - t.Fatalf("stat %s: fi.Sys(): is not *syscall.Stat_t", f.Name()) - } - - uid, gid := s.Uid, s.Gid - if uid != uint32(TEST_UID_1) || gid != uint32(TEST_GID_1) { - t.Fatalf("chown(%s, %d, %d): want (%d,%d), got (%d, %d)", f.Name(), TEST_UID_1, TEST_GID_1, TEST_UID_1, TEST_GID_1, uid, gid) - } - - // Root permission denied - if err = Chown(f.Name(), TEST_UID_2, TEST_GID_2); err.Error() != ERR_PERM_DENIED { - t.Fatalf("chown(%s, uid=%v, gid=%v): got %v, want != nil", f.Name(), TEST_UID_2, TEST_GID_2, err) - } - - fi, err = Stat(f.Name()) - if err != nil { - t.Fatalf("stat %s: got %v, want nil", f.Name(), err) - } - - if fi.Sys() == nil { - t.Fatalf("stat %s: fi.Sys(): got nil", f.Name()) - } - - s, ok = fi.Sys().(*syscall.Stat_t) - if !ok { - t.Fatalf("stat %s: fi.Sys(): is not *syscall.Stat_t", f.Name()) - } - uid, gid = s.Uid, s.Gid - if uid != uint32(TEST_UID_2) || gid != uint32(TEST_GID_2) { - // Chown will fail due to permissions denied, so the UID and GID should stay the same - if uid != uint32(TEST_UID_1) && gid != uint32(TEST_GID_1) { - t.Fatalf("chown(%s, %d, %d): want (%d,%d), got (%d, %d)", f.Name(), TEST_UID_2, TEST_GID_2, TEST_UID_2, TEST_GID_2, uid, gid) + // ENOENT + if err := Chown("invalid", Geteuid(), Getgid()); err != nil { + if err.(syscall.Errno) != syscall.ENOENT { + t.Fatalf("chown(%s, uid=%v, gid=%v): got '%v', want %v", f.Name(), Geteuid(), Getegid(), err, syscall.ENOENT) } } }