diff options
Diffstat (limited to 'test/runner')
-rw-r--r-- | test/runner/BUILD | 29 | ||||
-rw-r--r-- | test/runner/defs.bzl | 229 | ||||
-rw-r--r-- | test/runner/gtest/BUILD | 9 | ||||
-rw-r--r-- | test/runner/gtest/gtest.go | 188 | ||||
-rw-r--r-- | test/runner/runner.go | 496 |
5 files changed, 0 insertions, 951 deletions
diff --git a/test/runner/BUILD b/test/runner/BUILD deleted file mode 100644 index 582d2946d..000000000 --- a/test/runner/BUILD +++ /dev/null @@ -1,29 +0,0 @@ -load("//tools:defs.bzl", "bzl_library", "go_binary") - -package(licenses = ["notice"]) - -go_binary( - name = "runner", - testonly = 1, - srcs = ["runner.go"], - data = [ - "//runsc", - ], - visibility = ["//:sandbox"], - deps = [ - "//pkg/log", - "//pkg/test/testutil", - "//runsc/specutils", - "//test/runner/gtest", - "//test/uds", - "@com_github_opencontainers_runtime_spec//specs-go:go_default_library", - "@com_github_syndtr_gocapability//capability:go_default_library", - "@org_golang_x_sys//unix:go_default_library", - ], -) - -bzl_library( - name = "defs_bzl", - srcs = ["defs.bzl"], - visibility = ["//visibility:private"], -) diff --git a/test/runner/defs.bzl b/test/runner/defs.bzl deleted file mode 100644 index 2a0ef2cec..000000000 --- a/test/runner/defs.bzl +++ /dev/null @@ -1,229 +0,0 @@ -"""Defines a rule for syscall test targets.""" - -load("//tools:defs.bzl", "default_platform", "platforms") - -def _runner_test_impl(ctx): - # Generate a runner binary. - runner = ctx.actions.declare_file(ctx.label.name) - runner_content = "\n".join([ - "#!/bin/bash", - "set -euf -x -o pipefail", - "if [[ -n \"${TEST_UNDECLARED_OUTPUTS_DIR}\" ]]; then", - " mkdir -p \"${TEST_UNDECLARED_OUTPUTS_DIR}\"", - " chmod a+rwx \"${TEST_UNDECLARED_OUTPUTS_DIR}\"", - "fi", - "exec %s %s \"$@\" %s\n" % ( - ctx.files.runner[0].short_path, - " ".join(ctx.attr.runner_args), - ctx.files.test[0].short_path, - ), - ]) - ctx.actions.write(runner, runner_content, is_executable = True) - - # Return with all transitive files. - runfiles = ctx.runfiles( - transitive_files = depset(transitive = [ - target.data_runfiles.files - for target in (ctx.attr.runner, ctx.attr.test) - if hasattr(target, "data_runfiles") - ]), - files = ctx.files.runner + ctx.files.test, - collect_default = True, - collect_data = True, - ) - return [DefaultInfo(executable = runner, runfiles = runfiles)] - -_runner_test = rule( - attrs = { - "runner": attr.label( - default = "//test/runner:runner", - ), - "test": attr.label( - mandatory = True, - ), - "runner_args": attr.string_list(), - "data": attr.label_list( - allow_files = True, - ), - }, - test = True, - implementation = _runner_test_impl, -) - -def _syscall_test( - test, - platform, - use_tmpfs, - tags, - debug, - network = "none", - file_access = "exclusive", - overlay = False, - add_uds_tree = False, - vfs2 = False, - fuse = False, - **kwargs): - # Prepend "runsc" to non-native platform names. - full_platform = platform if platform == "native" else "runsc_" + platform - - # Name the test appropriately. - name = test.split(":")[1] + "_" + full_platform - if file_access == "shared": - name += "_shared" - if overlay: - name += "_overlay" - if vfs2: - name += "_vfs2" - if fuse: - name += "_fuse" - if network != "none": - name += "_" + network + "net" - - # Apply all tags. - if tags == None: - tags = [] - - # Add the full_platform and file access in a tag to make it easier to run - # all the tests on a specific flavor. Use --test_tag_filters=ptrace,file_shared. - tags = list(tags) - tags += [full_platform, "file_" + file_access] - - # Disable off-host networking. - tags.append("requires-net:loopback") - tags.append("requires-net:ipv4") - tags.append("block-network") - - # gotsan makes sense only if tests are running in gVisor. - if platform == "native": - tags.append("nogotsan") - - runner_args = [ - # Arguments are passed directly to runner binary. - "--platform=" + platform, - "--network=" + network, - "--use-tmpfs=" + str(use_tmpfs), - "--file-access=" + file_access, - "--overlay=" + str(overlay), - "--add-uds-tree=" + str(add_uds_tree), - "--vfs2=" + str(vfs2), - "--fuse=" + str(fuse), - "--strace=" + str(debug), - "--debug=" + str(debug), - ] - - # Call the rule above. - _runner_test( - name = name, - test = test, - runner_args = runner_args, - tags = tags, - **kwargs - ) - -def syscall_test( - test, - use_tmpfs = False, - add_overlay = False, - add_uds_tree = False, - add_hostinet = False, - vfs2 = True, - fuse = False, - debug = True, - tags = None, - **kwargs): - """syscall_test is a macro that will create targets for all platforms. - - Args: - test: the test target. - use_tmpfs: use tmpfs in the defined tests. - add_overlay: add an overlay test. - add_uds_tree: add a UDS test. - add_hostinet: add a hostinet test. - vfs2: enable VFS2 support. - fuse: enable FUSE support. - debug: enable debug output. - tags: starting test tags. - **kwargs: additional test arguments. - """ - if not tags: - tags = [] - - if vfs2 and not fuse: - # Generate a vfs1 plain test. Most testing will now be - # biased towards vfs2, with only a single vfs1 case. - _syscall_test( - test = test, - platform = default_platform, - use_tmpfs = use_tmpfs, - add_uds_tree = add_uds_tree, - tags = tags + platforms[default_platform], - debug = debug, - vfs2 = False, - **kwargs - ) - - if not fuse: - # Generate a native test if fuse is not required. - _syscall_test( - test = test, - platform = "native", - use_tmpfs = False, - add_uds_tree = add_uds_tree, - tags = tags, - debug = debug, - **kwargs - ) - - for (platform, platform_tags) in platforms.items(): - _syscall_test( - test = test, - platform = platform, - use_tmpfs = use_tmpfs, - add_uds_tree = add_uds_tree, - tags = platform_tags + tags, - fuse = fuse, - vfs2 = vfs2, - debug = debug, - **kwargs - ) - - if add_overlay: - _syscall_test( - test = test, - platform = default_platform, - use_tmpfs = use_tmpfs, - add_uds_tree = add_uds_tree, - tags = platforms[default_platform] + tags, - debug = debug, - fuse = fuse, - vfs2 = vfs2, - overlay = True, - **kwargs - ) - if add_hostinet: - _syscall_test( - test = test, - platform = default_platform, - use_tmpfs = use_tmpfs, - network = "host", - add_uds_tree = add_uds_tree, - tags = platforms[default_platform] + tags, - debug = debug, - fuse = fuse, - vfs2 = vfs2, - **kwargs - ) - if not use_tmpfs: - # Also test shared gofer access. - _syscall_test( - test = test, - platform = default_platform, - use_tmpfs = use_tmpfs, - add_uds_tree = add_uds_tree, - tags = platforms[default_platform] + tags, - debug = debug, - file_access = "shared", - fuse = fuse, - vfs2 = vfs2, - **kwargs - ) diff --git a/test/runner/gtest/BUILD b/test/runner/gtest/BUILD deleted file mode 100644 index de4b2727c..000000000 --- a/test/runner/gtest/BUILD +++ /dev/null @@ -1,9 +0,0 @@ -load("//tools:defs.bzl", "go_library") - -package(licenses = ["notice"]) - -go_library( - name = "gtest", - srcs = ["gtest.go"], - visibility = ["//:sandbox"], -) diff --git a/test/runner/gtest/gtest.go b/test/runner/gtest/gtest.go deleted file mode 100644 index 2ad5f58ef..000000000 --- a/test/runner/gtest/gtest.go +++ /dev/null @@ -1,188 +0,0 @@ -// 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. - -// Package gtest contains helpers for running google-test tests from Go. -package gtest - -import ( - "fmt" - "os/exec" - "strings" -) - -var ( - // listTestFlag is the flag that will list tests in gtest binaries. - listTestFlag = "--gtest_list_tests" - - // filterTestFlag is the flag that will filter tests in gtest binaries. - filterTestFlag = "--gtest_filter" - - // listBechmarkFlag is the flag that will list benchmarks in gtest binaries. - listBenchmarkFlag = "--benchmark_list_tests" - - // filterBenchmarkFlag is the flag that will run specified benchmarks. - filterBenchmarkFlag = "--benchmark_filter" -) - -// BuildTestArgs builds arguments to be passed to the test binary to execute -// only the test cases in `indices`. -func BuildTestArgs(indices []int, testCases []TestCase) []string { - var testFilter, benchFilter string - for _, tci := range indices { - tc := testCases[tci] - if tc.all { - // No argument will make all tests run. - return nil - } - if tc.benchmark { - if len(benchFilter) > 0 { - benchFilter += "|" - } - benchFilter += "^" + tc.Name + "$" - } else { - if len(testFilter) > 0 { - testFilter += ":" - } - testFilter += tc.FullName() - } - } - - var args []string - if len(testFilter) > 0 { - args = append(args, fmt.Sprintf("%s=%s", filterTestFlag, testFilter)) - } - if len(benchFilter) > 0 { - args = append(args, fmt.Sprintf("%s=%s", filterBenchmarkFlag, benchFilter)) - } - return args -} - -// TestCase is a single gtest test case. -type TestCase struct { - // Suite is the suite for this test. - Suite string - - // Name is the name of this individual test. - Name string - - // all indicates that this will run without flags. This takes - // precendence over benchmark below. - all bool - - // benchmark indicates that this is a benchmark. In this case, the - // suite will be empty, and we will use the appropriate test and - // benchmark flags. - benchmark bool -} - -// FullName returns the name of the test including the suite. It is suitable to -// pass to "-gtest_filter". -func (tc TestCase) FullName() string { - return fmt.Sprintf("%s.%s", tc.Suite, tc.Name) -} - -// ParseTestCases calls a gtest test binary to list its test and returns a -// slice with the name and suite of each test. -// -// If benchmarks is true, then benchmarks will be included in the list of test -// cases provided. Note that this requires the binary to support the -// benchmarks_list_tests flag. -func ParseTestCases(testBin string, benchmarks bool, extraArgs ...string) ([]TestCase, error) { - // Run to extract test cases. - args := append([]string{listTestFlag}, extraArgs...) - cmd := exec.Command(testBin, args...) - out, err := cmd.Output() - if err != nil { - // We failed to list tests with the given flags. Just - // return something that will run the binary with no - // flags, which should execute all tests. - fmt.Printf("failed to get test list: %v\n", err) - return []TestCase{ - { - Suite: "Default", - Name: "All", - all: true, - }, - }, nil - } - - // Parse test output. - var t []TestCase - var suite string - for _, line := range strings.Split(string(out), "\n") { - // Strip comments. - line = strings.Split(line, "#")[0] - - // New suite? - if !strings.HasPrefix(line, " ") { - suite = strings.TrimSuffix(strings.TrimSpace(line), ".") - continue - } - - // Individual test. - name := strings.TrimSpace(line) - - // Do we have a suite yet? - if suite == "" { - return nil, fmt.Errorf("test without a suite: %v", name) - } - - // Add this individual test. - t = append(t, TestCase{ - Suite: suite, - Name: name, - }) - } - - // Finished? - if !benchmarks { - return t, nil - } - - // Run again to extract benchmarks. - args = append([]string{listBenchmarkFlag}, extraArgs...) - cmd = exec.Command(testBin, args...) - out, err = cmd.Output() - if err != nil { - // We were able to enumerate tests above, but not benchmarks? - // We requested them, so we return an error in this case. - exitErr, ok := err.(*exec.ExitError) - if !ok { - return nil, fmt.Errorf("could not enumerate gtest benchmarks: %v", err) - } - return nil, fmt.Errorf("could not enumerate gtest benchmarks: %v\nstderr\n%s", err, exitErr.Stderr) - } - - benches := strings.Trim(string(out), "\n") - if len(benches) == 0 { - return t, nil - } - - // Parse benchmark output. - for _, line := range strings.Split(benches, "\n") { - // Strip comments. - line = strings.Split(line, "#")[0] - - // Single benchmark. - name := strings.TrimSpace(line) - - // Add the single benchmark. - t = append(t, TestCase{ - Suite: "Benchmarks", - Name: name, - benchmark: true, - }) - } - return t, nil -} diff --git a/test/runner/runner.go b/test/runner/runner.go deleted file mode 100644 index d314a5036..000000000 --- a/test/runner/runner.go +++ /dev/null @@ -1,496 +0,0 @@ -// 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. - -// Binary syscall_test_runner runs the syscall test suites in gVisor -// containers and on the host platform. -package main - -import ( - "flag" - "fmt" - "io/ioutil" - "os" - "os/exec" - "os/signal" - "path/filepath" - "strings" - "syscall" - "time" - - specs "github.com/opencontainers/runtime-spec/specs-go" - "github.com/syndtr/gocapability/capability" - "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/log" - "gvisor.dev/gvisor/pkg/test/testutil" - "gvisor.dev/gvisor/runsc/specutils" - "gvisor.dev/gvisor/test/runner/gtest" - "gvisor.dev/gvisor/test/uds" -) - -var ( - debug = flag.Bool("debug", false, "enable debug logs") - strace = flag.Bool("strace", false, "enable strace logs") - platform = flag.String("platform", "ptrace", "platform to run on") - network = flag.String("network", "none", "network stack to run on (sandbox, host, none)") - useTmpfs = flag.Bool("use-tmpfs", false, "mounts tmpfs for /tmp") - fileAccess = flag.String("file-access", "exclusive", "mounts root in exclusive or shared mode") - overlay = flag.Bool("overlay", false, "wrap filesystem mounts with writable tmpfs overlay") - vfs2 = flag.Bool("vfs2", false, "enable VFS2") - fuse = flag.Bool("fuse", false, "enable FUSE") - runscPath = flag.String("runsc", "", "path to runsc binary") - - addUDSTree = flag.Bool("add-uds-tree", false, "expose a tree of UDS utilities for use in tests") - // TODO(gvisor.dev/issue/4572): properly support leak checking for runsc, and - // set to true as the default for the test runner. - leakCheck = flag.Bool("leak-check", false, "check for reference leaks") -) - -func main() { - flag.Parse() - if flag.NArg() != 1 { - fatalf("test must be provided") - } - - log.SetLevel(log.Info) - if *debug { - log.SetLevel(log.Debug) - } - - if *platform != "native" && *runscPath == "" { - if err := testutil.ConfigureExePath(); err != nil { - panic(err.Error()) - } - *runscPath = specutils.ExePath - } - - // Make sure stdout and stderr are opened with O_APPEND, otherwise logs - // from outside the sandbox can (and will) stomp on logs from inside - // the sandbox. - for _, f := range []*os.File{os.Stdout, os.Stderr} { - flags, err := unix.FcntlInt(f.Fd(), unix.F_GETFL, 0) - if err != nil { - fatalf("error getting file flags for %v: %v", f, err) - } - if flags&unix.O_APPEND == 0 { - flags |= unix.O_APPEND - if _, err := unix.FcntlInt(f.Fd(), unix.F_SETFL, flags); err != nil { - fatalf("error setting file flags for %v: %v", f, err) - } - } - } - - // Resolve the absolute path for the binary. - testBin, err := filepath.Abs(flag.Args()[0]) - if err != nil { - fatalf("Abs(%q) failed: %v", flag.Args()[0], err) - } - - // Get all test cases in each binary. - testCases, err := gtest.ParseTestCases(testBin, true) - if err != nil { - fatalf("ParseTestCases(%q) failed: %v", testBin, err) - } - - // Get subset of tests corresponding to shard. - indices, err := testutil.TestIndicesForShard(len(testCases)) - if err != nil { - fatalf("TestsForShard() failed: %v", err) - } - if len(indices) == 0 { - log.Warningf("No tests to run in this shard") - return - } - args := gtest.BuildTestArgs(indices, testCases) - - switch *platform { - case "native": - if err := runTestCaseNative(testBin, args); err != nil { - fatalf(err.Error()) - } - default: - if err := runTestCaseRunsc(testBin, args); err != nil { - fatalf(err.Error()) - } - } -} - -// runTestCaseNative runs the test case directly on the host machine. -func runTestCaseNative(testBin string, args []string) error { - // These tests might be running in parallel, so make sure they have a - // unique test temp dir. - tmpDir, err := ioutil.TempDir(testutil.TmpDir(), "") - if err != nil { - return fmt.Errorf("could not create temp dir: %v", err) - } - defer os.RemoveAll(tmpDir) - - // Replace TEST_TMPDIR in the current environment with something - // unique. - env := os.Environ() - newEnvVar := "TEST_TMPDIR=" + tmpDir - var found bool - for i, kv := range env { - if strings.HasPrefix(kv, "TEST_TMPDIR=") { - env[i] = newEnvVar - found = true - break - } - } - if !found { - env = append(env, newEnvVar) - } - // Remove shard env variables so that the gunit binary does not try to - // interpret them. - env = filterEnv(env, "TEST_SHARD_INDEX", "TEST_TOTAL_SHARDS", "GTEST_SHARD_INDEX", "GTEST_TOTAL_SHARDS") - - if *addUDSTree { - socketDir, cleanup, err := uds.CreateSocketTree("/tmp") - if err != nil { - return fmt.Errorf("failed to create socket tree: %v", err) - } - defer cleanup() - - env = append(env, "TEST_UDS_TREE="+socketDir) - // On Linux, the concept of "attach" location doesn't exist. - // Just pass the same path to make these test identical. - env = append(env, "TEST_UDS_ATTACH_TREE="+socketDir) - } - - cmd := exec.Command(testBin, args...) - cmd.Env = env - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.SysProcAttr = &unix.SysProcAttr{} - - if specutils.HasCapabilities(capability.CAP_SYS_ADMIN) { - cmd.SysProcAttr.Cloneflags |= unix.CLONE_NEWUTS - } - - if specutils.HasCapabilities(capability.CAP_NET_ADMIN) { - cmd.SysProcAttr.Cloneflags |= unix.CLONE_NEWNET - } - - if err := cmd.Run(); err != nil { - ws := err.(*exec.ExitError).Sys().(syscall.WaitStatus) - return fmt.Errorf("test exited with status %d, want 0", ws.ExitStatus()) - } - return nil -} - -// runRunsc runs spec in runsc in a standard test configuration. -// -// runsc logs will be saved to a path in TEST_UNDECLARED_OUTPUTS_DIR. -// -// Returns an error if the sandboxed application exits non-zero. -func runRunsc(spec *specs.Spec) error { - bundleDir, cleanup, err := testutil.SetupBundleDir(spec) - if err != nil { - return fmt.Errorf("SetupBundleDir failed: %v", err) - } - defer cleanup() - - rootDir, cleanup, err := testutil.SetupRootDir() - if err != nil { - return fmt.Errorf("SetupRootDir failed: %v", err) - } - defer cleanup() - - id := testutil.RandomContainerID() - log.Infof("Running test in container %q", id) - specutils.LogSpec(spec) - - args := []string{ - "-root", rootDir, - "-network", *network, - "-log-format=text", - "-TESTONLY-unsafe-nonroot=true", - "-net-raw=true", - fmt.Sprintf("-panic-signal=%d", unix.SIGTERM), - "-watchdog-action=panic", - "-platform", *platform, - "-file-access", *fileAccess, - } - if *overlay { - args = append(args, "-overlay") - } - if *vfs2 { - args = append(args, "-vfs2") - if *fuse { - args = append(args, "-fuse") - } - } - if *debug { - args = append(args, "-debug", "-log-packets=true") - } - if *strace { - args = append(args, "-strace") - } - if *addUDSTree { - args = append(args, "-fsgofer-host-uds") - } - if *leakCheck { - args = append(args, "-ref-leak-mode=log-names") - } - - testLogDir := os.Getenv("TEST_UNDECLARED_OUTPUTS_DIR") - if len(testLogDir) > 0 { - debugLogDir, err := ioutil.TempDir(testLogDir, "runsc") - if err != nil { - return fmt.Errorf("could not create temp dir: %v", err) - } - debugLogDir += "/" - log.Infof("runsc logs: %s", debugLogDir) - args = append(args, "-debug-log", debugLogDir) - args = append(args, "-coverage-report", debugLogDir) - - // Default -log sends messages to stderr which makes reading the test log - // difficult. Instead, drop them when debug log is enabled given it's a - // better place for these messages. - args = append(args, "-log=/dev/null") - } - - // Current process doesn't have CAP_SYS_ADMIN, create user namespace and run - // as root inside that namespace to get it. - rArgs := append(args, "run", "--bundle", bundleDir, id) - cmd := exec.Command(*runscPath, rArgs...) - cmd.SysProcAttr = &unix.SysProcAttr{ - Cloneflags: unix.CLONE_NEWUSER | unix.CLONE_NEWNS, - // Set current user/group as root inside the namespace. - UidMappings: []syscall.SysProcIDMap{ - {ContainerID: 0, HostID: os.Getuid(), Size: 1}, - }, - GidMappings: []syscall.SysProcIDMap{ - {ContainerID: 0, HostID: os.Getgid(), Size: 1}, - }, - GidMappingsEnableSetgroups: false, - Credential: &syscall.Credential{ - Uid: 0, - Gid: 0, - }, - } - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - sig := make(chan os.Signal, 1) - defer close(sig) - signal.Notify(sig, unix.SIGTERM) - defer signal.Stop(sig) - go func() { - s, ok := <-sig - if !ok { - return - } - log.Warningf("Got signal: %v", s) - done := make(chan bool, 1) - dArgs := append([]string{}, args...) - dArgs = append(dArgs, "-alsologtostderr=true", "debug", "--stacks", id) - go func(dArgs []string) { - debug := exec.Command(*runscPath, dArgs...) - debug.Stdout = os.Stdout - debug.Stderr = os.Stderr - debug.Run() - done <- true - }(dArgs) - - timeout := time.After(3 * time.Second) - select { - case <-timeout: - log.Infof("runsc debug --stacks is timeouted") - case <-done: - } - - log.Warningf("Send SIGTERM to the sandbox process") - dArgs = append(args, "debug", - fmt.Sprintf("--signal=%d", unix.SIGTERM), - id) - signal := exec.Command(*runscPath, dArgs...) - signal.Stdout = os.Stdout - signal.Stderr = os.Stderr - signal.Run() - }() - - err = cmd.Run() - if err == nil && len(testLogDir) > 0 { - // If the test passed, then we erase the log directory. This speeds up - // uploading logs in continuous integration & saves on disk space. - _ = os.RemoveAll(testLogDir) - } - - return err -} - -// setupUDSTree updates the spec to expose a UDS tree for gofer socket testing. -func setupUDSTree(spec *specs.Spec) (cleanup func(), err error) { - socketDir, cleanup, err := uds.CreateSocketTree("/tmp") - if err != nil { - return nil, fmt.Errorf("failed to create socket tree: %v", err) - } - - // Standard access to entire tree. - spec.Mounts = append(spec.Mounts, specs.Mount{ - Destination: "/tmp/sockets", - Source: socketDir, - Type: "bind", - }) - - // Individial attach points for each socket to test mounts that attach - // directly to the sockets. - spec.Mounts = append(spec.Mounts, specs.Mount{ - Destination: "/tmp/sockets-attach/stream/echo", - Source: filepath.Join(socketDir, "stream/echo"), - Type: "bind", - }) - spec.Mounts = append(spec.Mounts, specs.Mount{ - Destination: "/tmp/sockets-attach/stream/nonlistening", - Source: filepath.Join(socketDir, "stream/nonlistening"), - Type: "bind", - }) - spec.Mounts = append(spec.Mounts, specs.Mount{ - Destination: "/tmp/sockets-attach/seqpacket/echo", - Source: filepath.Join(socketDir, "seqpacket/echo"), - Type: "bind", - }) - spec.Mounts = append(spec.Mounts, specs.Mount{ - Destination: "/tmp/sockets-attach/seqpacket/nonlistening", - Source: filepath.Join(socketDir, "seqpacket/nonlistening"), - Type: "bind", - }) - spec.Mounts = append(spec.Mounts, specs.Mount{ - Destination: "/tmp/sockets-attach/dgram/null", - Source: filepath.Join(socketDir, "dgram/null"), - Type: "bind", - }) - - spec.Process.Env = append(spec.Process.Env, "TEST_UDS_TREE=/tmp/sockets") - spec.Process.Env = append(spec.Process.Env, "TEST_UDS_ATTACH_TREE=/tmp/sockets-attach") - - return cleanup, nil -} - -// runsTestCaseRunsc runs the test case in runsc. -func runTestCaseRunsc(testBin string, args []string) error { - // Run a new container with the test executable and filter for the - // given test suite and name. - spec := testutil.NewSpecWithArgs(append([]string{testBin}, args...)...) - - // Mark the root as writeable, as some tests attempt to - // write to the rootfs, and expect EACCES, not EROFS. - spec.Root.Readonly = false - - // Test spec comes with pre-defined mounts that we don't want. Reset it. - spec.Mounts = nil - testTmpDir := "/tmp" - if *useTmpfs { - // Forces '/tmp' to be mounted as tmpfs, otherwise test that rely on - // features only available in gVisor's internal tmpfs may fail. - spec.Mounts = append(spec.Mounts, specs.Mount{ - Destination: "/tmp", - Type: "tmpfs", - }) - } else { - // Use a gofer-backed directory as '/tmp'. - // - // Tests might be running in parallel, so make sure each has a - // unique test temp dir. - // - // Some tests (e.g., sticky) access this mount from other - // users, so make sure it is world-accessible. - tmpDir, err := ioutil.TempDir(testutil.TmpDir(), "") - if err != nil { - return fmt.Errorf("could not create temp dir: %v", err) - } - defer os.RemoveAll(tmpDir) - - if err := os.Chmod(tmpDir, 0777); err != nil { - return fmt.Errorf("could not chmod temp dir: %v", err) - } - - // "/tmp" is not replaced with a tmpfs mount inside the sandbox - // when it's not empty. This ensures that testTmpDir uses gofer - // in exclusive mode. - testTmpDir = tmpDir - if *fileAccess == "shared" { - // All external mounts except the root mount are shared. - spec.Mounts = append(spec.Mounts, specs.Mount{ - Type: "bind", - Destination: "/tmp", - Source: tmpDir, - }) - testTmpDir = "/tmp" - } - } - - // Set environment variables that indicate we are running in gVisor with - // the given platform, network, and filesystem stack. - env := []string{"TEST_ON_GVISOR=" + *platform, "GVISOR_NETWORK=" + *network} - env = append(env, os.Environ()...) - const vfsVar = "GVISOR_VFS" - if *vfs2 { - env = append(env, vfsVar+"=VFS2") - const fuseVar = "FUSE_ENABLED" - if *fuse { - env = append(env, fuseVar+"=TRUE") - } else { - env = append(env, fuseVar+"=FALSE") - } - } else { - env = append(env, vfsVar+"=VFS1") - } - - // Remove shard env variables so that the gunit binary does not try to - // interpret them. - env = filterEnv(env, "TEST_SHARD_INDEX", "TEST_TOTAL_SHARDS", "GTEST_SHARD_INDEX", "GTEST_TOTAL_SHARDS") - - // Set TEST_TMPDIR to /tmp, as some of the syscall tests require it to - // be backed by tmpfs. - env = filterEnv(env, "TEST_TMPDIR") - env = append(env, fmt.Sprintf("TEST_TMPDIR=%s", testTmpDir)) - - spec.Process.Env = env - - if *addUDSTree { - cleanup, err := setupUDSTree(spec) - if err != nil { - return fmt.Errorf("error creating UDS tree: %v", err) - } - defer cleanup() - } - - if err := runRunsc(spec); err != nil { - return fmt.Errorf("test failed with error %v, want nil", err) - } - return nil -} - -// filterEnv returns an environment with the excluded variables removed. -func filterEnv(env []string, exclude ...string) []string { - var out []string - for _, kv := range env { - ok := true - for _, k := range exclude { - if strings.HasPrefix(kv, k+"=") { - ok = false - break - } - } - if ok { - out = append(out, kv) - } - } - return out -} - -func fatalf(s string, args ...interface{}) { - fmt.Fprintf(os.Stderr, s+"\n", args...) - os.Exit(1) -} |