From 88eb85aaee56831ad49eaf7aa80d73de9814cde2 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 22 May 2018 14:53:54 +0200 Subject: [PATCH] unix: add tests for *xattr functions Based on the tests in github.com/pkg/xattr Change-Id: I3af73ad538877da042602708248063c218260a2e Reviewed-on: https://go-review.googlesource.com/114135 Run-TryBot: Tobias Klauser TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- unix/syscall_darwin_test.go | 19 ++++++++ unix/syscall_freebsd_test.go | 15 ++++++ unix/syscall_linux_test.go | 14 ++++++ unix/xattr_test.go | 92 ++++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 unix/syscall_darwin_test.go create mode 100644 unix/xattr_test.go diff --git a/unix/syscall_darwin_test.go b/unix/syscall_darwin_test.go new file mode 100644 index 00000000..65691d5c --- /dev/null +++ b/unix/syscall_darwin_test.go @@ -0,0 +1,19 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix_test + +// stringsFromByteSlice converts a sequence of attributes to a []string. +// On Darwin, each entry is a NULL-terminated string. +func stringsFromByteSlice(buf []byte) []string { + var result []string + off := 0 + for i, b := range buf { + if b == 0 { + result = append(result, string(buf[off:i])) + off = i + 1 + } + } + return result +} diff --git a/unix/syscall_freebsd_test.go b/unix/syscall_freebsd_test.go index 654439e0..0fec1a82 100644 --- a/unix/syscall_freebsd_test.go +++ b/unix/syscall_freebsd_test.go @@ -295,3 +295,18 @@ func TestCapRightsSetAndClear(t *testing.T) { t.Fatalf("Wrong rights set") } } + +// stringsFromByteSlice converts a sequence of attributes to a []string. +// On FreeBSD, each entry consists of a single byte containing the length +// of the attribute name, followed by the attribute name. +// The name is _not_ NULL-terminated. +func stringsFromByteSlice(buf []byte) []string { + var result []string + i := 0 + for i < len(buf) { + next := i + 1 + int(buf[i]) + result = append(result, string(buf[i+1:next])) + i = next + } + return result +} diff --git a/unix/syscall_linux_test.go b/unix/syscall_linux_test.go index a2bc4401..6429bd25 100644 --- a/unix/syscall_linux_test.go +++ b/unix/syscall_linux_test.go @@ -371,3 +371,17 @@ func TestStatx(t *testing.T) { t.Errorf("Statx: returned stat mtime does not match Lstat") } } + +// stringsFromByteSlice converts a sequence of attributes to a []string. +// On Linux, each entry is a NULL-terminated string. +func stringsFromByteSlice(buf []byte) []string { + var result []string + off := 0 + for i, b := range buf { + if b == 0 { + result = append(result, string(buf[off:i])) + off = i + 1 + } + } + return result +} diff --git a/unix/xattr_test.go b/unix/xattr_test.go new file mode 100644 index 00000000..78cf9224 --- /dev/null +++ b/unix/xattr_test.go @@ -0,0 +1,92 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin freebsd linux + +package unix_test + +import ( + "runtime" + "strings" + "testing" + + "golang.org/x/sys/unix" +) + +func TestXattr(t *testing.T) { + defer chtmpdir(t)() + + f := "xattr1" + touch(t, f) + + xattrName := "user.test" + xattrDataSet := "gopher" + err := unix.Setxattr(f, xattrName, []byte(xattrDataSet), 0) + if err == unix.ENOTSUP || err == unix.EOPNOTSUPP { + t.Skip("filesystem does not support extended attributes, skipping test") + } else if err != nil { + t.Fatalf("Setxattr: %v", err) + } + + // find size + size, err := unix.Listxattr(f, nil) + if err != nil { + t.Fatalf("Listxattr: %v", err) + } + + if size <= 0 { + t.Fatalf("Listxattr returned an empty list of attributes") + } + + buf := make([]byte, size) + read, err := unix.Listxattr(f, buf) + if err != nil { + t.Fatalf("Listxattr: %v", err) + } + + xattrs := stringsFromByteSlice(buf[:read]) + + xattrWant := xattrName + if runtime.GOOS == "freebsd" { + // On FreeBSD, the namespace is stored separately from the xattr + // name and Listxattr doesn't return the namespace prefix. + xattrWant = strings.TrimPrefix(xattrWant, "user.") + } + found := false + for _, name := range xattrs { + if name == xattrWant { + found = true + } + } + + if !found { + t.Errorf("Listxattr did not return previously set attribute '%s'", xattrName) + } + + // find size + size, err = unix.Getxattr(f, xattrName, nil) + if err != nil { + t.Fatalf("Getxattr: %v", err) + } + + if size <= 0 { + t.Fatalf("Getxattr returned an empty attribute") + } + + xattrDataGet := make([]byte, size) + _, err = unix.Getxattr(f, xattrName, xattrDataGet) + if err != nil { + t.Fatalf("Getxattr: %v", err) + } + + got := string(xattrDataGet) + if got != xattrDataSet { + t.Errorf("Getxattr: expected attribute value %s, got %s", xattrDataSet, got) + } + + err = unix.Removexattr(f, xattrName) + if err != nil { + t.Fatalf("Removexattr: %v", err) + } +}