summaryrefslogtreecommitdiffhomepage
path: root/test/util
diff options
context:
space:
mode:
authorIan Lewis <ianmlewis@gmail.com>2020-08-17 21:44:31 -0400
committerIan Lewis <ianmlewis@gmail.com>2020-08-17 21:44:31 -0400
commitac324f646ee3cb7955b0b45a7453aeb9671cbdf1 (patch)
tree0cbc5018e8807421d701d190dc20525726c7ca76 /test/util
parent352ae1022ce19de28fc72e034cc469872ad79d06 (diff)
parent6d0c5803d557d453f15ac6f683697eeb46dab680 (diff)
Merge branch 'master' into ip-forwarding
- Merges aleksej-paschenko's with HEAD - Adds vfs2 support for ip_forward
Diffstat (limited to 'test/util')
-rw-r--r--test/util/BUILD65
-rw-r--r--test/util/capability_util.cc12
-rw-r--r--test/util/fs_util.cc17
-rw-r--r--test/util/fs_util.h18
-rw-r--r--test/util/fs_util_test.cc4
-rw-r--r--test/util/mount_util.h9
-rw-r--r--test/util/multiprocess_util.h6
-rw-r--r--test/util/platform_util.cc48
-rw-r--r--test/util/platform_util.h56
-rw-r--r--test/util/posix_error_test.cc1
-rw-r--r--test/util/pty_util.cc10
-rw-r--r--test/util/pty_util.h3
-rw-r--r--test/util/rlimit_util.cc1
-rw-r--r--test/util/save_util_linux.cc18
-rw-r--r--test/util/save_util_other.cc4
-rw-r--r--test/util/signal_util.cc1
-rw-r--r--test/util/signal_util.h15
-rw-r--r--test/util/temp_path.cc3
-rw-r--r--test/util/temp_path.h1
-rw-r--r--test/util/temp_umask.h39
-rw-r--r--test/util/test_main.cc2
-rw-r--r--test/util/test_util.cc49
-rw-r--r--test/util/test_util.h62
-rw-r--r--test/util/test_util_impl.cc52
-rw-r--r--test/util/test_util_runfiles.cc50
-rw-r--r--test/util/test_util_test.cc1
26 files changed, 465 insertions, 82 deletions
diff --git a/test/util/BUILD b/test/util/BUILD
index 5d2a9cc2c..2a17c33ee 100644
--- a/test/util/BUILD
+++ b/test/util/BUILD
@@ -1,5 +1,4 @@
-load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
-load("//test/syscalls:build_defs.bzl", "select_for_linux")
+load("//tools:defs.bzl", "cc_library", "cc_test", "gbenchmark", "gtest", "select_system")
package(
default_visibility = ["//:sandbox"],
@@ -42,7 +41,7 @@ cc_library(
":save_util",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -56,7 +55,7 @@ cc_library(
":posix_error",
":test_util",
"@com_google_absl//absl/strings",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -68,7 +67,7 @@ cc_test(
":proc_util",
":test_main",
":test_util",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -88,7 +87,7 @@ cc_library(
":file_descriptor",
":posix_error",
"@com_google_absl//absl/strings",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -102,7 +101,7 @@ cc_test(
":temp_path",
":test_main",
":test_util",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -135,19 +134,20 @@ cc_library(
":cleanup",
":posix_error",
":test_util",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
cc_library(
name = "save_util",
testonly = 1,
- srcs = ["save_util.cc"] +
- select_for_linux(
- ["save_util_linux.cc"],
- ["save_util_other.cc"],
- ),
+ srcs = [
+ "save_util.cc",
+ "save_util_linux.cc",
+ "save_util_other.cc",
+ ],
hdrs = ["save_util.h"],
+ defines = select_system(),
)
cc_library(
@@ -166,6 +166,14 @@ cc_library(
)
cc_library(
+ name = "platform_util",
+ testonly = 1,
+ srcs = ["platform_util.cc"],
+ hdrs = ["platform_util.h"],
+ deps = [":test_util"],
+)
+
+cc_library(
name = "posix_error",
testonly = 1,
srcs = ["posix_error.cc"],
@@ -175,7 +183,7 @@ cc_library(
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:variant",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -186,7 +194,7 @@ cc_test(
deps = [
":posix_error",
":test_main",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -210,7 +218,7 @@ cc_library(
":cleanup",
":posix_error",
":test_util",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -225,27 +233,34 @@ cc_library(
":test_util",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
cc_library(
name = "test_util",
testonly = 1,
- srcs = ["test_util.cc"],
+ srcs = [
+ "test_util.cc",
+ "test_util_impl.cc",
+ "test_util_runfiles.cc",
+ ],
hdrs = ["test_util.h"],
+ defines = select_system(),
deps = [
":fs_util",
":logging",
":posix_error",
":save_util",
+ "@bazel_tools//tools/cpp/runfiles",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/flags:parse",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/time",
- "@com_google_googletest//:gtest",
+ gtest,
+ gbenchmark,
],
)
@@ -277,7 +292,7 @@ cc_library(
":posix_error",
":test_util",
"@com_google_absl//absl/time",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -288,7 +303,7 @@ cc_test(
deps = [
":test_main",
":test_util",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -308,7 +323,7 @@ cc_library(
":file_descriptor",
":posix_error",
":save_util",
- "@com_google_googletest//:gtest",
+ gtest,
],
)
@@ -335,3 +350,9 @@ cc_library(
":save_util",
],
)
+
+cc_library(
+ name = "temp_umask",
+ testonly = 1,
+ hdrs = ["temp_umask.h"],
+)
diff --git a/test/util/capability_util.cc b/test/util/capability_util.cc
index 5d733887b..a1b994c45 100644
--- a/test/util/capability_util.cc
+++ b/test/util/capability_util.cc
@@ -36,10 +36,10 @@ PosixErrorOr<bool> CanCreateUserNamespace() {
ASSIGN_OR_RETURN_ERRNO(
auto child_stack,
MmapAnon(kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE));
- int const child_pid =
- clone(+[](void*) { return 0; },
- reinterpret_cast<void*>(child_stack.addr() + kPageSize),
- CLONE_NEWUSER | SIGCHLD, /* arg = */ nullptr);
+ int const child_pid = clone(
+ +[](void*) { return 0; },
+ reinterpret_cast<void*>(child_stack.addr() + kPageSize),
+ CLONE_NEWUSER | SIGCHLD, /* arg = */ nullptr);
if (child_pid > 0) {
int status;
int const ret = waitpid(child_pid, &status, /* options = */ 0);
@@ -63,13 +63,13 @@ PosixErrorOr<bool> CanCreateUserNamespace() {
// is in a chroot environment (i.e., the caller's root directory does
// not match the root directory of the mount namespace in which it
// resides)."
- std::cerr << "clone(CLONE_NEWUSER) failed with EPERM";
+ std::cerr << "clone(CLONE_NEWUSER) failed with EPERM" << std::endl;
return false;
} else if (errno == EUSERS) {
// "(since Linux 3.11) CLONE_NEWUSER was specified in flags, and the call
// would cause the limit on the number of nested user namespaces to be
// exceeded. See user_namespaces(7)."
- std::cerr << "clone(CLONE_NEWUSER) failed with EUSERS";
+ std::cerr << "clone(CLONE_NEWUSER) failed with EUSERS" << std::endl;
return false;
} else {
// Unexpected error code; indicate an actual error.
diff --git a/test/util/fs_util.cc b/test/util/fs_util.cc
index 88b1e7911..5418948fe 100644
--- a/test/util/fs_util.cc
+++ b/test/util/fs_util.cc
@@ -105,6 +105,15 @@ PosixErrorOr<struct stat> Stat(absl::string_view path) {
return stat_buf;
}
+PosixErrorOr<struct stat> Lstat(absl::string_view path) {
+ struct stat stat_buf;
+ int res = lstat(std::string(path).c_str(), &stat_buf);
+ if (res < 0) {
+ return PosixError(errno, absl::StrCat("lstat ", path));
+ }
+ return stat_buf;
+}
+
PosixErrorOr<struct stat> Fstat(int fd) {
struct stat stat_buf;
int res = fstat(fd, &stat_buf);
@@ -116,18 +125,18 @@ PosixErrorOr<struct stat> Fstat(int fd) {
PosixErrorOr<bool> Exists(absl::string_view path) {
struct stat stat_buf;
- int res = stat(std::string(path).c_str(), &stat_buf);
+ int res = lstat(std::string(path).c_str(), &stat_buf);
if (res < 0) {
if (errno == ENOENT) {
return false;
}
- return PosixError(errno, absl::StrCat("stat ", path));
+ return PosixError(errno, absl::StrCat("lstat ", path));
}
return true;
}
PosixErrorOr<bool> IsDirectory(absl::string_view path) {
- ASSIGN_OR_RETURN_ERRNO(struct stat stat_buf, Stat(path));
+ ASSIGN_OR_RETURN_ERRNO(struct stat stat_buf, Lstat(path));
if (S_ISDIR(stat_buf.st_mode)) {
return true;
}
@@ -443,7 +452,7 @@ PosixErrorOr<std::string> MakeAbsolute(absl::string_view filename,
std::string CleanPath(const absl::string_view unclean_path) {
std::string path = std::string(unclean_path);
- const char *src = path.c_str();
+ const char* src = path.c_str();
std::string::iterator dst = path.begin();
// Check for absolute path and determine initial backtrack limit.
diff --git a/test/util/fs_util.h b/test/util/fs_util.h
index ee1b341d7..8cdac23a1 100644
--- a/test/util/fs_util.h
+++ b/test/util/fs_util.h
@@ -26,6 +26,17 @@
namespace gvisor {
namespace testing {
+
+// O_LARGEFILE as defined by Linux. glibc tries to be clever by setting it to 0
+// because "it isn't needed", even though Linux can return it via F_GETFL.
+#if defined(__x86_64__)
+constexpr int kOLargeFile = 00100000;
+#elif defined(__aarch64__)
+constexpr int kOLargeFile = 00400000;
+#else
+#error "Unknown architecture"
+#endif
+
// Returns a status or the current working directory.
PosixErrorOr<std::string> GetCWD();
@@ -33,9 +44,14 @@ PosixErrorOr<std::string> GetCWD();
// can't be determined.
PosixErrorOr<bool> Exists(absl::string_view path);
-// Returns a stat structure for the given path or an error.
+// Returns a stat structure for the given path or an error. If the path
+// represents a symlink, it will be traversed.
PosixErrorOr<struct stat> Stat(absl::string_view path);
+// Returns a stat structure for the given path or an error. If the path
+// represents a symlink, it will not be traversed.
+PosixErrorOr<struct stat> Lstat(absl::string_view path);
+
// Returns a stat struct for the given fd.
PosixErrorOr<struct stat> Fstat(int fd);
diff --git a/test/util/fs_util_test.cc b/test/util/fs_util_test.cc
index 2a200320a..657b6a46e 100644
--- a/test/util/fs_util_test.cc
+++ b/test/util/fs_util_test.cc
@@ -12,12 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "test/util/fs_util.h"
+
#include <errno.h>
+
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#include "test/util/fs_util.h"
#include "test/util/posix_error.h"
#include "test/util/temp_path.h"
#include "test/util/test_util.h"
diff --git a/test/util/mount_util.h b/test/util/mount_util.h
index 38ec6c8a1..09e2281eb 100644
--- a/test/util/mount_util.h
+++ b/test/util/mount_util.h
@@ -17,6 +17,7 @@
#include <errno.h>
#include <sys/mount.h>
+
#include <functional>
#include <string>
@@ -30,10 +31,10 @@ namespace testing {
// Mount mounts the filesystem, and unmounts when the returned reference is
// destroyed.
-inline PosixErrorOr<Cleanup> Mount(const std::string &source,
- const std::string &target,
- const std::string &fstype, uint64_t mountflags,
- const std::string &data,
+inline PosixErrorOr<Cleanup> Mount(const std::string& source,
+ const std::string& target,
+ const std::string& fstype,
+ uint64_t mountflags, const std::string& data,
uint64_t umountflags) {
if (mount(source.c_str(), target.c_str(), fstype.c_str(), mountflags,
data.c_str()) == -1) {
diff --git a/test/util/multiprocess_util.h b/test/util/multiprocess_util.h
index 61526b4e7..2f3bf4a6f 100644
--- a/test/util/multiprocess_util.h
+++ b/test/util/multiprocess_util.h
@@ -99,11 +99,13 @@ inline PosixErrorOr<Cleanup> ForkAndExec(const std::string& filename,
const ExecveArray& argv,
const ExecveArray& envv, pid_t* child,
int* execve_errno) {
- return ForkAndExec(filename, argv, envv, [] {}, child, execve_errno);
+ return ForkAndExec(
+ filename, argv, envv, [] {}, child, execve_errno);
}
// Equivalent to ForkAndExec, except using dirfd and flags with execveat.
-PosixErrorOr<Cleanup> ForkAndExecveat(int32_t dirfd, const std::string& pathname,
+PosixErrorOr<Cleanup> ForkAndExecveat(int32_t dirfd,
+ const std::string& pathname,
const ExecveArray& argv,
const ExecveArray& envv, int flags,
const std::function<void()>& fn,
diff --git a/test/util/platform_util.cc b/test/util/platform_util.cc
new file mode 100644
index 000000000..c9200d381
--- /dev/null
+++ b/test/util/platform_util.cc
@@ -0,0 +1,48 @@
+// Copyright 2020 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "test/util/platform_util.h"
+
+#include "test/util/test_util.h"
+
+namespace gvisor {
+namespace testing {
+
+PlatformSupport PlatformSupport32Bit() {
+ if (GvisorPlatform() == Platform::kPtrace ||
+ GvisorPlatform() == Platform::kKVM) {
+ return PlatformSupport::NotSupported;
+ } else {
+ return PlatformSupport::Allowed;
+ }
+}
+
+PlatformSupport PlatformSupportAlignmentCheck() {
+ return PlatformSupport::Allowed;
+}
+
+PlatformSupport PlatformSupportMultiProcess() {
+ return PlatformSupport::Allowed;
+}
+
+PlatformSupport PlatformSupportInt3() {
+ if (GvisorPlatform() == Platform::kKVM) {
+ return PlatformSupport::NotSupported;
+ } else {
+ return PlatformSupport::Allowed;
+ }
+}
+
+} // namespace testing
+} // namespace gvisor
diff --git a/test/util/platform_util.h b/test/util/platform_util.h
new file mode 100644
index 000000000..28cc92371
--- /dev/null
+++ b/test/util/platform_util.h
@@ -0,0 +1,56 @@
+// Copyright 2020 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef GVISOR_TEST_UTIL_PLATFORM_UTIL_H_
+#define GVISOR_TEST_UTIL_PLATFORM_UTIL_H_
+
+namespace gvisor {
+namespace testing {
+
+// PlatformSupport is a generic enumeration of classes of support.
+//
+// It is up to the individual functions and callers to agree on the precise
+// definition for each case. The document here generally refers to 32-bit
+// as an example. Many cases will use only NotSupported and Allowed.
+enum class PlatformSupport {
+ // The feature is not supported on the current platform.
+ //
+ // In the case of 32-bit, this means that calls will generally be interpreted
+ // as 64-bit calls, and there is no support for 32-bit binaries, long calls,
+ // etc. This usually means that the underlying implementation just pretends
+ // that 32-bit doesn't exist.
+ NotSupported,
+
+ // Calls will be ignored by the kernel with a fixed error.
+ Ignored,
+
+ // Calls will result in a SIGSEGV or similar fault.
+ Segfault,
+
+ // The feature is supported as expected.
+ //
+ // In the case of 32-bit, this means that the system call or far call will be
+ // handled properly.
+ Allowed,
+};
+
+PlatformSupport PlatformSupport32Bit();
+PlatformSupport PlatformSupportAlignmentCheck();
+PlatformSupport PlatformSupportMultiProcess();
+PlatformSupport PlatformSupportInt3();
+
+} // namespace testing
+} // namespace gvisor
+
+#endif // GVISOR_TEST_UTIL_PLATFORM_UTL_H_
diff --git a/test/util/posix_error_test.cc b/test/util/posix_error_test.cc
index d67270842..bf9465abb 100644
--- a/test/util/posix_error_test.cc
+++ b/test/util/posix_error_test.cc
@@ -15,6 +15,7 @@
#include "test/util/posix_error.h"
#include <errno.h>
+
#include "gmock/gmock.h"
#include "gtest/gtest.h"
diff --git a/test/util/pty_util.cc b/test/util/pty_util.cc
index c0fd9a095..c01f916aa 100644
--- a/test/util/pty_util.cc
+++ b/test/util/pty_util.cc
@@ -24,6 +24,14 @@ namespace gvisor {
namespace testing {
PosixErrorOr<FileDescriptor> OpenSlave(const FileDescriptor& master) {
+ PosixErrorOr<int> n = SlaveID(master);
+ if (!n.ok()) {
+ return PosixErrorOr<FileDescriptor>(n.error());
+ }
+ return Open(absl::StrCat("/dev/pts/", n.ValueOrDie()), O_RDWR | O_NONBLOCK);
+}
+
+PosixErrorOr<int> SlaveID(const FileDescriptor& master) {
// Get pty index.
int n;
int ret = ioctl(master.get(), TIOCGPTN, &n);
@@ -38,7 +46,7 @@ PosixErrorOr<FileDescriptor> OpenSlave(const FileDescriptor& master) {
return PosixError(errno, "ioctl(TIOSPTLCK) failed");
}
- return Open(absl::StrCat("/dev/pts/", n), O_RDWR | O_NONBLOCK);
+ return n;
}
} // namespace testing
diff --git a/test/util/pty_util.h b/test/util/pty_util.h
index 367b14f15..0722da379 100644
--- a/test/util/pty_util.h
+++ b/test/util/pty_util.h
@@ -24,6 +24,9 @@ namespace testing {
// Opens the slave end of the passed master as R/W and nonblocking.
PosixErrorOr<FileDescriptor> OpenSlave(const FileDescriptor& master);
+// Get the number of the slave end of the master.
+PosixErrorOr<int> SlaveID(const FileDescriptor& master);
+
} // namespace testing
} // namespace gvisor
diff --git a/test/util/rlimit_util.cc b/test/util/rlimit_util.cc
index 684253f78..d7bfc1606 100644
--- a/test/util/rlimit_util.cc
+++ b/test/util/rlimit_util.cc
@@ -15,6 +15,7 @@
#include "test/util/rlimit_util.h"
#include <sys/resource.h>
+
#include <cerrno>
#include "test/util/cleanup.h"
diff --git a/test/util/save_util_linux.cc b/test/util/save_util_linux.cc
index 7a0f14342..d0aea8e6a 100644
--- a/test/util/save_util_linux.cc
+++ b/test/util/save_util_linux.cc
@@ -12,22 +12,38 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#ifdef __linux__
+
#include <errno.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "test/util/save_util.h"
+#if defined(__x86_64__) || defined(__i386__)
+#define SYS_TRIGGER_SAVE SYS_create_module
+#elif defined(__aarch64__)
+#define SYS_TRIGGER_SAVE SYS_finit_module
+#else
+#error "Unknown architecture"
+#endif
+
namespace gvisor {
namespace testing {
void MaybeSave() {
if (internal::ShouldSave()) {
int orig_errno = errno;
- syscall(SYS_create_module, nullptr, 0);
+ // We use it to trigger saving the sentry state
+ // when this syscall is called.
+ // Notice: this needs to be a valid syscall
+ // that is not used in any of the syscall tests.
+ syscall(SYS_TRIGGER_SAVE, nullptr, 0);
errno = orig_errno;
}
}
} // namespace testing
} // namespace gvisor
+
+#endif
diff --git a/test/util/save_util_other.cc b/test/util/save_util_other.cc
index 1aca663b7..931af2c29 100644
--- a/test/util/save_util_other.cc
+++ b/test/util/save_util_other.cc
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#ifndef __linux__
+
namespace gvisor {
namespace testing {
@@ -21,3 +23,5 @@ void MaybeSave() {
} // namespace testing
} // namespace gvisor
+
+#endif
diff --git a/test/util/signal_util.cc b/test/util/signal_util.cc
index 26738864f..5ee95ee80 100644
--- a/test/util/signal_util.cc
+++ b/test/util/signal_util.cc
@@ -15,6 +15,7 @@
#include "test/util/signal_util.h"
#include <signal.h>
+
#include <ostream>
#include "gtest/gtest.h"
diff --git a/test/util/signal_util.h b/test/util/signal_util.h
index 7fd2af015..e7b66aa51 100644
--- a/test/util/signal_util.h
+++ b/test/util/signal_util.h
@@ -18,6 +18,7 @@
#include <signal.h>
#include <sys/syscall.h>
#include <unistd.h>
+
#include <ostream>
#include "gmock/gmock.h"
@@ -84,6 +85,20 @@ inline void FixupFault(ucontext_t* ctx) {
// The encoding is 0x48 0xab 0x00.
ctx->uc_mcontext.gregs[REG_RIP] += 3;
}
+#elif __aarch64__
+inline void Fault() {
+ // Zero and dereference x0.
+ asm("mov xzr, x0\r\n"
+ "str xzr, [x0]\r\n"
+ :
+ :
+ : "x0");
+}
+
+inline void FixupFault(ucontext_t* ctx) {
+ // Skip the bad instruction above.
+ ctx->uc_mcontext.pc += 4;
+}
#endif
} // namespace testing
diff --git a/test/util/temp_path.cc b/test/util/temp_path.cc
index 35aacb172..e1bdee7fd 100644
--- a/test/util/temp_path.cc
+++ b/test/util/temp_path.cc
@@ -56,7 +56,7 @@ void TryDeleteRecursively(std::string const& path) {
if (undeleted_dirs || undeleted_files || !status.ok()) {
std::cerr << path << ": failed to delete " << undeleted_dirs
<< " directories and " << undeleted_files
- << " files: " << status;
+ << " files: " << status << std::endl;
}
}
}
@@ -77,6 +77,7 @@ std::string NewTempAbsPath() {
std::string NewTempRelPath() { return NextTempBasename(); }
std::string GetAbsoluteTestTmpdir() {
+ // Note that TEST_TMPDIR is guaranteed to be set.
char* env_tmpdir = getenv("TEST_TMPDIR");
std::string tmp_dir =
env_tmpdir != nullptr ? std::string(env_tmpdir) : "/tmp";
diff --git a/test/util/temp_path.h b/test/util/temp_path.h
index 92d669503..9e5ac11f4 100644
--- a/test/util/temp_path.h
+++ b/test/util/temp_path.h
@@ -16,6 +16,7 @@
#define GVISOR_TEST_UTIL_TEMP_PATH_H_
#include <sys/stat.h>
+
#include <string>
#include <utility>
diff --git a/test/util/temp_umask.h b/test/util/temp_umask.h
new file mode 100644
index 000000000..e7de84a54
--- /dev/null
+++ b/test/util/temp_umask.h
@@ -0,0 +1,39 @@
+// Copyright 2018 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef GVISOR_TEST_UTIL_TEMP_UMASK_H_
+#define GVISOR_TEST_UTIL_TEMP_UMASK_H_
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+namespace gvisor {
+namespace testing {
+
+class TempUmask {
+ public:
+ // Sets the process umask to `mask`.
+ explicit TempUmask(mode_t mask) : old_mask_(umask(mask)) {}
+
+ // Sets the process umask to its previous value.
+ ~TempUmask() { umask(old_mask_); }
+
+ private:
+ mode_t old_mask_;
+};
+
+} // namespace testing
+} // namespace gvisor
+
+#endif // GVISOR_TEST_UTIL_TEMP_UMASK_H_
diff --git a/test/util/test_main.cc b/test/util/test_main.cc
index 5c7ee0064..1f389e58f 100644
--- a/test/util/test_main.cc
+++ b/test/util/test_main.cc
@@ -16,5 +16,5 @@
int main(int argc, char** argv) {
gvisor::testing::TestInit(&argc, &argv);
- return RUN_ALL_TESTS();
+ return gvisor::testing::RunAllTests();
}
diff --git a/test/util/test_util.cc b/test/util/test_util.cc
index ba0dcf7d0..d0c1d6426 100644
--- a/test/util/test_util.cc
+++ b/test/util/test_util.cc
@@ -40,24 +40,38 @@
namespace gvisor {
namespace testing {
-#define TEST_ON_GVISOR "TEST_ON_GVISOR"
+constexpr char kGvisorNetwork[] = "GVISOR_NETWORK";
+constexpr char kGvisorVfs[] = "GVISOR_VFS";
+constexpr char kFuseEnabled[] = "FUSE_ENABLED";
bool IsRunningOnGvisor() { return GvisorPlatform() != Platform::kNative; }
-Platform GvisorPlatform() {
+const std::string GvisorPlatform() {
// Set by runner.go.
- char* env = getenv(TEST_ON_GVISOR);
+ const char* env = getenv(kTestOnGvisor);
if (!env) {
return Platform::kNative;
}
- if (strcmp(env, "ptrace") == 0) {
- return Platform::kPtrace;
- }
- if (strcmp(env, "kvm") == 0) {
- return Platform::kKVM;
+ return std::string(env);
+}
+
+bool IsRunningWithHostinet() {
+ const char* env = getenv(kGvisorNetwork);
+ return env && strcmp(env, "host") == 0;
+}
+
+bool IsRunningWithVFS1() {
+ const char* env = getenv(kGvisorVfs);
+ if (env == nullptr) {
+ // If not set, it's running on Linux.
+ return false;
}
- std::cerr << "unknown platform " << env;
- abort();
+ return strcmp(env, "VFS1") == 0;
+}
+
+bool IsFUSEEnabled() {
+ const char* env = getenv(kFuseEnabled);
+ return env && strcmp(env, "TRUE") == 0;
}
// Inline cpuid instruction. Preserve %ebx/%rbx register. In PIC compilations
@@ -70,7 +84,6 @@ Platform GvisorPlatform() {
"xchg %%rdi, %%rbx\n" \
: "=a"(a), "=D"(b), "=c"(c), "=d"(d) \
: "a"(a_inp), "2"(c_inp))
-#endif // defined(__x86_64__)
CPUVendor GetCPUVendor() {
uint32_t eax, ebx, ecx, edx;
@@ -87,6 +100,7 @@ CPUVendor GetCPUVendor() {
}
return CPUVendor::kUnknownVendor;
}
+#endif // defined(__x86_64__)
bool operator==(const KernelVersion& first, const KernelVersion& second) {
return first.major == second.major && first.minor == second.minor &&
@@ -116,9 +130,6 @@ PosixErrorOr<KernelVersion> GetKernelVersion() {
return ParseKernelVersion(buf.release);
}
-void SetupGvisorDeathTest() {
-}
-
std::string CPUSetToString(const cpu_set_t& set, size_t cpus) {
std::string str = "cpuset[";
for (unsigned int n = 0; n < cpus; n++) {
@@ -224,15 +235,5 @@ bool Equivalent(uint64_t current, uint64_t target, double tolerance) {
return abs_diff <= static_cast<uint64_t>(tolerance * target);
}
-void TestInit(int* argc, char*** argv) {
- ::testing::InitGoogleTest(argc, *argv);
- ::absl::ParseCommandLine(*argc, *argv);
-
- // Always mask SIGPIPE as it's common and tests aren't expected to handle it.
- struct sigaction sa = {};
- sa.sa_handler = SIG_IGN;
- TEST_CHECK(sigaction(SIGPIPE, &sa, nullptr) == 0);
-}
-
} // namespace testing
} // namespace gvisor
diff --git a/test/util/test_util.h b/test/util/test_util.h
index b9d2dc2ba..373c54f32 100644
--- a/test/util/test_util.h
+++ b/test/util/test_util.h
@@ -26,16 +26,13 @@
// IsRunningOnGvisor returns true if the test is known to be running on gVisor.
// GvisorPlatform can be used to get more detail:
//
-// switch (GvisorPlatform()) {
-// case Platform::kNative:
-// case Platform::kGvisor:
-// EXPECT_THAT(mmap(...), SyscallSucceeds());
-// break;
-// case Platform::kPtrace:
-// EXPECT_THAT(mmap(...), SyscallFailsWithErrno(ENOSYS));
-// break;
+// if (GvisorPlatform() == Platform::kPtrace) {
+// ...
// }
//
+// SetupGvisorDeathTest ensures that signal handling does not interfere with
+/// tests that rely on fatal signals.
+//
// Matchers
// ========
//
@@ -198,6 +195,8 @@
namespace gvisor {
namespace testing {
+constexpr char kTestOnGvisor[] = "TEST_ON_GVISOR";
+
// TestInit must be called prior to RUN_ALL_TESTS.
//
// This parses all arguments and adjusts argc and argv appropriately.
@@ -213,15 +212,24 @@ void TestInit(int* argc, char*** argv);
if (expr) GTEST_SKIP() << #expr; \
} while (0)
-enum class Platform {
- kNative,
- kKVM,
- kPtrace,
-};
+// Platform contains platform names.
+namespace Platform {
+constexpr char kNative[] = "native";
+constexpr char kPtrace[] = "ptrace";
+constexpr char kKVM[] = "kvm";
+constexpr char kFuchsia[] = "fuchsia";
+} // namespace Platform
+
bool IsRunningOnGvisor();
-Platform GvisorPlatform();
+const std::string GvisorPlatform();
+bool IsRunningWithHostinet();
+// TODO(gvisor.dev/issue/1624): Delete once VFS1 is gone.
+bool IsRunningWithVFS1();
+bool IsFUSEEnabled();
+#ifdef __linux__
void SetupGvisorDeathTest();
+#endif
struct KernelVersion {
int major;
@@ -560,6 +568,25 @@ ssize_t ApplyFileIoSyscall(F const& f, size_t const count) {
} // namespace internal
+inline PosixErrorOr<std::string> ReadAllFd(int fd) {
+ std::string all;
+ all.reserve(128 * 1024); // arbitrary.
+
+ std::vector<char> buffer(16 * 1024);
+ for (;;) {
+ auto const bytes = RetryEINTR(read)(fd, buffer.data(), buffer.size());
+ if (bytes < 0) {
+ return PosixError(errno, "file read");
+ }
+ if (bytes == 0) {
+ return std::move(all);
+ }
+ if (bytes > 0) {
+ all.append(buffer.data(), bytes);
+ }
+ }
+}
+
inline ssize_t ReadFd(int fd, void* buf, size_t count) {
return internal::ApplyFileIoSyscall(
[&](size_t completed) {
@@ -762,7 +789,14 @@ MATCHER_P2(EquivalentWithin, target, tolerance,
return Equivalent(arg, target, tolerance);
}
+// Returns the absolute path to the a data dependency. 'path' is the runfile
+// location relative to workspace root.
+#ifdef __linux__
+std::string RunfilePath(std::string path);
+#endif
+
void TestInit(int* argc, char*** argv);
+int RunAllTests(void);
} // namespace testing
} // namespace gvisor
diff --git a/test/util/test_util_impl.cc b/test/util/test_util_impl.cc
new file mode 100644
index 000000000..7e1ad9e66
--- /dev/null
+++ b/test/util/test_util_impl.cc
@@ -0,0 +1,52 @@
+// Copyright 2019 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <signal.h>
+
+#include "gtest/gtest.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+#include "benchmark/benchmark.h"
+#include "test/util/logging.h"
+
+extern bool FLAGS_benchmark_list_tests;
+extern std::string FLAGS_benchmark_filter;
+
+namespace gvisor {
+namespace testing {
+
+void SetupGvisorDeathTest() {}
+
+void TestInit(int* argc, char*** argv) {
+ ::testing::InitGoogleTest(argc, *argv);
+ benchmark::Initialize(argc, *argv);
+ ::absl::ParseCommandLine(*argc, *argv);
+
+ // Always mask SIGPIPE as it's common and tests aren't expected to handle it.
+ struct sigaction sa = {};
+ sa.sa_handler = SIG_IGN;
+ TEST_CHECK(sigaction(SIGPIPE, &sa, nullptr) == 0);
+}
+
+int RunAllTests() {
+ if (FLAGS_benchmark_list_tests || FLAGS_benchmark_filter != ".") {
+ benchmark::RunSpecifiedBenchmarks();
+ return 0;
+ } else {
+ return RUN_ALL_TESTS();
+ }
+}
+
+} // namespace testing
+} // namespace gvisor
diff --git a/test/util/test_util_runfiles.cc b/test/util/test_util_runfiles.cc
new file mode 100644
index 000000000..694d21692
--- /dev/null
+++ b/test/util/test_util_runfiles.cc
@@ -0,0 +1,50 @@
+// Copyright 2019 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __fuchsia__
+
+#include <iostream>
+#include <string>
+
+#include "test/util/fs_util.h"
+#include "test/util/test_util.h"
+#include "tools/cpp/runfiles/runfiles.h"
+
+namespace gvisor {
+namespace testing {
+
+std::string RunfilePath(std::string path) {
+ static const bazel::tools::cpp::runfiles::Runfiles* const runfiles = [] {
+ std::string error;
+ auto* runfiles =
+ bazel::tools::cpp::runfiles::Runfiles::CreateForTest(&error);
+ if (runfiles == nullptr) {
+ std::cerr << "Unable to find runfiles: " << error << std::endl;
+ }
+ return runfiles;
+ }();
+
+ if (!runfiles) {
+ // Can't find runfiles? This probably won't work, but __main__/path is our
+ // best guess.
+ return JoinPath("__main__", path);
+ }
+
+ return runfiles->Rlocation(JoinPath("__main__", path));
+}
+
+} // namespace testing
+} // namespace gvisor
+
+#endif // __fuchsia__
diff --git a/test/util/test_util_test.cc b/test/util/test_util_test.cc
index b7300d9e5..f42100374 100644
--- a/test/util/test_util_test.cc
+++ b/test/util/test_util_test.cc
@@ -15,6 +15,7 @@
#include "test/util/test_util.h"
#include <errno.h>
+
#include <vector>
#include "gmock/gmock.h"