summaryrefslogtreecommitdiffhomepage
path: root/test/runner
diff options
context:
space:
mode:
Diffstat (limited to 'test/runner')
-rw-r--r--test/runner/BUILD29
-rw-r--r--test/runner/defs.bzl281
-rw-r--r--test/runner/gtest/BUILD9
-rw-r--r--test/runner/gtest/gtest.go170
-rw-r--r--test/runner/runner.go519
5 files changed, 0 insertions, 1008 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 9b5994d59..000000000
--- a/test/runner/defs.bzl
+++ /dev/null
@@ -1,281 +0,0 @@
-"""Defines a rule for syscall test targets."""
-
-load("//tools:defs.bzl", "default_platform", "loopback", "platforms")
-
-def _runner_test_impl(ctx):
- # Generate a runner binary.
- runner = ctx.actions.declare_file("%s-runner" % 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,
- shard_count,
- size,
- platform,
- use_tmpfs,
- tags,
- debug,
- network = "none",
- file_access = "exclusive",
- overlay = False,
- add_uds_tree = False,
- vfs2 = False,
- fuse = False):
- # 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 += [full_platform, "file_" + file_access]
-
- # Hash this target into one of 15 buckets. This can be used to
- # randomly split targets between different workflows.
- hash15 = hash(native.package_name() + name) % 15
- tags.append("hash15:" + str(hash15))
-
- # TODO(b/139838000): Tests using hostinet must be disabled on Guitar until
- # we figure out how to request ipv4 sockets on Guitar machines.
- if network == "host":
- tags.append("noguitar")
- tags.append("block-network")
-
- # Disable off-host networking.
- tags.append("requires-net:loopback")
-
- # 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,
- data = [loopback],
- size = size,
- tags = tags,
- shard_count = shard_count,
- )
-
-def syscall_test(
- test,
- shard_count = 5,
- size = "small",
- use_tmpfs = False,
- add_overlay = False,
- add_uds_tree = False,
- add_hostinet = False,
- vfs2 = True,
- fuse = False,
- debug = True,
- tags = None):
- """syscall_test is a macro that will create targets for all platforms.
-
- Args:
- test: the test target.
- shard_count: shards for defined tests.
- size: the defined test size.
- 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.
- tags: starting test tags.
- """
- if not tags:
- tags = []
-
- vfs2_tags = list(tags)
- if vfs2:
- # Add tag to easily run VFS2 tests with --test_tag_filters=vfs2
- vfs2_tags.append("vfs2")
- if fuse:
- vfs2_tags.append("fuse")
-
- else:
- # Don't automatically run tests tests not yet passing.
- vfs2_tags.append("manual")
- vfs2_tags.append("noguitar")
- vfs2_tags.append("notap")
-
- _syscall_test(
- test = test,
- shard_count = shard_count,
- size = size,
- platform = default_platform,
- use_tmpfs = use_tmpfs,
- add_uds_tree = add_uds_tree,
- tags = platforms[default_platform] + vfs2_tags,
- debug = debug,
- vfs2 = True,
- fuse = fuse,
- )
- if fuse:
- # Only generate *_vfs2_fuse target if fuse parameter is enabled.
- return
-
- _syscall_test(
- test = test,
- shard_count = shard_count,
- size = size,
- platform = "native",
- use_tmpfs = False,
- add_uds_tree = add_uds_tree,
- tags = list(tags),
- debug = debug,
- )
-
- for (platform, platform_tags) in platforms.items():
- _syscall_test(
- test = test,
- shard_count = shard_count,
- size = size,
- platform = platform,
- use_tmpfs = use_tmpfs,
- add_uds_tree = add_uds_tree,
- tags = platform_tags + tags,
- debug = debug,
- )
-
- if add_overlay:
- _syscall_test(
- test = test,
- shard_count = shard_count,
- size = size,
- platform = default_platform,
- use_tmpfs = use_tmpfs,
- add_uds_tree = add_uds_tree,
- tags = platforms[default_platform] + tags,
- debug = debug,
- overlay = True,
- )
-
- # TODO(gvisor.dev/issue/4407): Remove tags to enable VFS2 overlay tests.
- overlay_vfs2_tags = list(vfs2_tags)
- overlay_vfs2_tags.append("manual")
- overlay_vfs2_tags.append("noguitar")
- overlay_vfs2_tags.append("notap")
- _syscall_test(
- test = test,
- shard_count = shard_count,
- size = size,
- platform = default_platform,
- use_tmpfs = use_tmpfs,
- add_uds_tree = add_uds_tree,
- tags = platforms[default_platform] + overlay_vfs2_tags,
- debug = debug,
- overlay = True,
- vfs2 = True,
- )
-
- if add_hostinet:
- _syscall_test(
- test = test,
- shard_count = shard_count,
- size = size,
- platform = default_platform,
- use_tmpfs = use_tmpfs,
- network = "host",
- add_uds_tree = add_uds_tree,
- tags = platforms[default_platform] + tags,
- debug = debug,
- )
-
- if not use_tmpfs:
- # Also test shared gofer access.
- _syscall_test(
- test = test,
- shard_count = shard_count,
- size = size,
- platform = default_platform,
- use_tmpfs = use_tmpfs,
- add_uds_tree = add_uds_tree,
- tags = platforms[default_platform] + tags,
- debug = debug,
- file_access = "shared",
- )
- _syscall_test(
- test = test,
- shard_count = shard_count,
- size = size,
- platform = default_platform,
- use_tmpfs = use_tmpfs,
- add_uds_tree = add_uds_tree,
- tags = platforms[default_platform] + vfs2_tags,
- debug = debug,
- file_access = "shared",
- vfs2 = True,
- )
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 e4445e01b..000000000
--- a/test/runner/gtest/gtest.go
+++ /dev/null
@@ -1,170 +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"
-)
-
-// 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)
-}
-
-// Args returns arguments to be passed when invoking the test.
-func (tc TestCase) Args() []string {
- if tc.all {
- return []string{} // No arguments.
- }
- if tc.benchmark {
- return []string{
- fmt.Sprintf("%s=^%s$", filterBenchmarkFlag, tc.Name),
- fmt.Sprintf("%s=", filterTestFlag),
- }
- }
- return []string{
- fmt.Sprintf("%s=%s", filterTestFlag, tc.FullName()),
- }
-}
-
-// 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.
- return []TestCase{
- 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 22d535f8d..000000000
--- a/test/runner/runner.go
+++ /dev/null
@@ -1,519 +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"
- "testing"
- "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")
- parallel = flag.Bool("parallel", false, "run tests in parallel")
- 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")
-)
-
-// runTestCaseNative runs the test case directly on the host machine.
-func runTestCaseNative(testBin string, tc gtest.TestCase, t *testing.T) {
- // 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 {
- t.Fatalf("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 env variables that cause the gunit binary to write output
- // files, since they will stomp on eachother, and on the output files
- // from this go test.
- env = filterEnv(env, []string{"GUNIT_OUTPUT", "TEST_PREMATURE_EXIT_FILE", "XML_OUTPUT_FILE"})
-
- // Remove shard env variables so that the gunit binary does not try to
- // intepret them.
- env = filterEnv(env, []string{"TEST_SHARD_INDEX", "TEST_TOTAL_SHARDS", "GTEST_SHARD_INDEX", "GTEST_TOTAL_SHARDS"})
-
- if *addUDSTree {
- socketDir, cleanup, err := uds.CreateSocketTree("/tmp")
- if err != nil {
- t.Fatalf("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, tc.Args()...)
- cmd.Env = env
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- cmd.SysProcAttr = &syscall.SysProcAttr{}
-
- if specutils.HasCapabilities(capability.CAP_SYS_ADMIN) {
- cmd.SysProcAttr.Cloneflags |= syscall.CLONE_NEWUTS
- }
-
- if specutils.HasCapabilities(capability.CAP_NET_ADMIN) {
- cmd.SysProcAttr.Cloneflags |= syscall.CLONE_NEWNET
- }
-
- if err := cmd.Run(); err != nil {
- ws := err.(*exec.ExitError).Sys().(syscall.WaitStatus)
- t.Errorf("test %q exited with status %d, want 0", tc.FullName(), ws.ExitStatus())
- }
-}
-
-// 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(tc gtest.TestCase, 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()
-
- name := tc.FullName()
- id := testutil.RandomContainerID()
- log.Infof("Running test %q in container %q", name, 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", syscall.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")
- }
-
- testLogDir := ""
- if undeclaredOutputsDir, ok := syscall.Getenv("TEST_UNDECLARED_OUTPUTS_DIR"); ok {
- // Create log directory dedicated for this test.
- testLogDir = filepath.Join(undeclaredOutputsDir, strings.Replace(name, "/", "_", -1))
- if err := os.MkdirAll(testLogDir, 0755); err != nil {
- return fmt.Errorf("could not create test dir: %v", err)
- }
- 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)
-
- // 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 = &syscall.SysProcAttr{
- Cloneflags: syscall.CLONE_NEWUSER | syscall.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, syscall.SIGTERM)
- defer signal.Stop(sig)
- go func() {
- s, ok := <-sig
- if !ok {
- return
- }
- log.Warningf("%s: Got signal: %v", name, 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", syscall.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, tc gtest.TestCase, t *testing.T) {
- // Run a new container with the test executable and filter for the
- // given test suite and name.
- spec := testutil.NewSpecWithArgs(append([]string{testBin}, tc.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 {
- t.Fatalf("could not create temp dir: %v", err)
- }
- defer os.RemoveAll(tmpDir)
-
- if err := os.Chmod(tmpDir, 0777); err != nil {
- t.Fatalf("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.
- platformVar := "TEST_ON_GVISOR"
- networkVar := "GVISOR_NETWORK"
- env := append(os.Environ(), platformVar+"="+*platform, networkVar+"="+*network)
- vfsVar := "GVISOR_VFS"
- if *vfs2 {
- env = append(env, vfsVar+"=VFS2")
- fuseVar := "FUSE_ENABLED"
- if *fuse {
- env = append(env, fuseVar+"=TRUE")
- } else {
- env = append(env, fuseVar+"=FALSE")
- }
- } else {
- env = append(env, vfsVar+"=VFS1")
- }
-
- // Remove env variables that cause the gunit binary to write output
- // files, since they will stomp on eachother, and on the output files
- // from this go test.
- env = filterEnv(env, []string{"GUNIT_OUTPUT", "TEST_PREMATURE_EXIT_FILE", "XML_OUTPUT_FILE"})
-
- // Remove shard env variables so that the gunit binary does not try to
- // intepret them.
- env = filterEnv(env, []string{"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, []string{"TEST_TMPDIR"})
- env = append(env, fmt.Sprintf("TEST_TMPDIR=%s", testTmpDir))
-
- spec.Process.Env = env
-
- if *addUDSTree {
- cleanup, err := setupUDSTree(spec)
- if err != nil {
- t.Fatalf("error creating UDS tree: %v", err)
- }
- defer cleanup()
- }
-
- if err := runRunsc(tc, spec); err != nil {
- t.Errorf("test %q failed with error %v, want nil", tc.FullName(), err)
- }
-}
-
-// filterEnv returns an environment with the excluded variables removed.
-func filterEnv(env, 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)
-}
-
-func matchString(a, b string) (bool, error) {
- return a == b, nil
-}
-
-func main() {
- flag.Parse()
- if flag.NArg() != 1 {
- fatalf("test must be provided")
- }
- testBin := flag.Args()[0] // Only argument.
-
- 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)
- }
- }
- }
-
- // 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)
- }
-
- // Resolve the absolute path for the binary.
- testBin, err = filepath.Abs(testBin)
- if err != nil {
- fatalf("Abs() failed: %v", err)
- }
-
- // Run the tests.
- var tests []testing.InternalTest
- for _, tci := range indices {
- // Capture tc.
- tc := testCases[tci]
- tests = append(tests, testing.InternalTest{
- Name: fmt.Sprintf("%s_%s", tc.Suite, tc.Name),
- F: func(t *testing.T) {
- if *parallel {
- t.Parallel()
- }
- if *platform == "native" {
- // Run the test case on host.
- runTestCaseNative(testBin, tc, t)
- } else {
- // Run the test case in runsc.
- runTestCaseRunsc(testBin, tc, t)
- }
- },
- })
- }
-
- testing.Main(matchString, tests, nil, nil)
-}