diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/runtimes/README.md | 2 | ||||
-rw-r--r-- | test/runtimes/go/Dockerfile | 5 | ||||
-rw-r--r-- | test/runtimes/java/Dockerfile | 43 | ||||
-rw-r--r-- | test/runtimes/java/proctor-java.go | 5 | ||||
-rw-r--r-- | test/runtimes/nodejs/Dockerfile | 3 | ||||
-rw-r--r-- | test/runtimes/php/Dockerfile | 3 | ||||
-rw-r--r-- | test/runtimes/python/Dockerfile | 3 | ||||
-rw-r--r-- | test/runtimes/runtimes_test.go | 34 | ||||
-rw-r--r-- | test/syscalls/BUILD | 4 | ||||
-rw-r--r-- | test/syscalls/linux/socket_inet_loopback.cc | 61 | ||||
-rw-r--r-- | test/syscalls/linux/splice.cc | 75 |
11 files changed, 197 insertions, 41 deletions
diff --git a/test/runtimes/README.md b/test/runtimes/README.md index 4e5a950bc..34d3507be 100644 --- a/test/runtimes/README.md +++ b/test/runtimes/README.md @@ -16,7 +16,7 @@ The following runtimes are currently supported: 1) [Install and configure Docker](https://docs.docker.com/install/) -2) Build each Docker container: +2) Build each Docker container from the runtimes directory: ```bash $ docker build -f $LANG/Dockerfile [-t $NAME] . diff --git a/test/runtimes/go/Dockerfile b/test/runtimes/go/Dockerfile index cd55608cd..1d5202b70 100644 --- a/test/runtimes/go/Dockerfile +++ b/test/runtimes/go/Dockerfile @@ -23,9 +23,12 @@ ENV LANG_DIR=${GOROOT} WORKDIR ${LANG_DIR}/src RUN ./make.bash +# Pre-compile the tests for faster execution +RUN ["/root/go/bin/go", "tool", "dist", "test", "-compile-only"] WORKDIR ${LANG_DIR} -COPY proctor-go.go ${LANG_DIR} +COPY common /root/go/src/gvisor.dev/gvisor/test/runtimes/common/common +COPY go/proctor-go.go ${LANG_DIR} ENTRYPOINT ["/root/go/bin/go", "run", "proctor-go.go"] diff --git a/test/runtimes/java/Dockerfile b/test/runtimes/java/Dockerfile index e162d7218..b9132b575 100644 --- a/test/runtimes/java/Dockerfile +++ b/test/runtimes/java/Dockerfile @@ -1,25 +1,16 @@ FROM ubuntu:bionic # This hash is associated with a specific JDK release and needed for ensuring # the same version is downloaded every time. -ENV LANG_HASH=af47e0398606 -ENV LANG_VER=11u-dev +ENV LANG_HASH=76072a077ee1 +ENV LANG_VER=11 ENV LANG_NAME=Java RUN apt-get update && apt-get install -y \ autoconf \ build-essential \ - curl\ - file \ - libasound2-dev \ - libcups2-dev \ - libfontconfig1-dev \ - libx11-dev \ - libxext-dev \ - libxrandr-dev \ - libxrender-dev \ - libxt-dev \ - libxtst-dev \ + curl \ make \ + openjdk-${LANG_VER}-jdk \ unzip \ zip @@ -27,26 +18,18 @@ WORKDIR /root RUN curl -o go.tar.gz https://dl.google.com/go/go1.12.6.linux-amd64.tar.gz RUN tar -zxf go.tar.gz -# Use curl instead of ADD to prevent redownload every time. -RUN curl -o jdk.tar.gz http://hg.openjdk.java.net/jdk-updates/jdk${LANG_VER}/archive/${LANG_HASH}.tar.gz -# Download Java version N-1 to be used as the Boot JDK to build Java version N. -RUN curl -o bootjdk.tar.gz https://download.java.net/openjdk/jdk10/ri/openjdk-10+44_linux-x64_bin_ri.tar.gz - -RUN tar -zxf jdk.tar.gz -RUN tar -zxf bootjdk.tar.gz - -# Specify the JDK to be used by jtreg. -ENV JT_JAVA=/root/jdk${LANG_VER}-${LANG_HASH}/build/linux-x86_64-normal-server-release/jdk -ENV LANG_DIR=/root/jdk${LANG_VER}-${LANG_HASH} - -WORKDIR ${LANG_DIR} +# Download the JDK test library. +RUN set -ex \ + && curl -fsSL --retry 10 -o /tmp/jdktests.tar.gz http://hg.openjdk.java.net/jdk/jdk${LANG_VER}/archive/${LANG_HASH}.tar.gz/test \ + && tar -xzf /tmp/jdktests.tar.gz -C /root \ + && rm -f /tmp/jdktests.tar.gz RUN curl -o jtreg.tar.gz https://ci.adoptopenjdk.net/view/Dependencies/job/jtreg/lastSuccessfulBuild/artifact/jtreg-4.2.0-tip.tar.gz RUN tar -xzf jtreg.tar.gz -RUN bash configure --with-boot-jdk=/root/jdk-10 --with-jtreg=${LANG_DIR}/jtreg -RUN make clean -RUN make images -COPY proctor-java.go ${LANG_DIR} +ENV LANG_DIR=/root + +COPY common /root/go/src/gvisor.dev/gvisor/test/runtimes/common/common +COPY java/proctor-java.go ${LANG_DIR} ENTRYPOINT ["/root/go/bin/go", "run", "proctor-java.go"] diff --git a/test/runtimes/java/proctor-java.go b/test/runtimes/java/proctor-java.go index c1e611b4b..7f6a66f4f 100644 --- a/test/runtimes/java/proctor-java.go +++ b/test/runtimes/java/proctor-java.go @@ -29,6 +29,7 @@ import ( var ( dir = os.Getenv("LANG_DIR") + hash = os.Getenv("LANG_HASH") jtreg = filepath.Join(dir, "jtreg/bin/jtreg") exclDirs = regexp.MustCompile(`(^(sun\/security)|(java\/util\/stream)|(java\/time)| )`) ) @@ -44,7 +45,7 @@ func main() { func (j javaRunner) ListTests() ([]string, error) { args := []string{ - "-dir:test/jdk", + "-dir:/root/jdk11-" + hash + "/test/jdk", "-ignore:quiet", "-a", "-listtests", @@ -69,7 +70,7 @@ func (j javaRunner) ListTests() ([]string, error) { } func (j javaRunner) RunTest(test string) error { - args := []string{"-dir:test/jdk/", test} + args := []string{"-noreport", "-dir:/root/jdk11-" + hash + "/test/jdk", test} cmd := exec.Command(jtreg, args...) cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr if err := cmd.Run(); err != nil { diff --git a/test/runtimes/nodejs/Dockerfile b/test/runtimes/nodejs/Dockerfile index b2416cce8..aba30d2ee 100644 --- a/test/runtimes/nodejs/Dockerfile +++ b/test/runtimes/nodejs/Dockerfile @@ -22,7 +22,8 @@ RUN ./configure RUN make RUN make test-build -COPY proctor-nodejs.go ${LANG_DIR} +COPY common /root/go/src/gvisor.dev/gvisor/test/runtimes/common/common +COPY nodejs/proctor-nodejs.go ${LANG_DIR} # Including dumb-init emulates the Linux "init" process, preventing the failure # of tests involving worker processes. diff --git a/test/runtimes/php/Dockerfile b/test/runtimes/php/Dockerfile index 1f8959b50..491ab902d 100644 --- a/test/runtimes/php/Dockerfile +++ b/test/runtimes/php/Dockerfile @@ -24,6 +24,7 @@ WORKDIR ${LANG_DIR} RUN ./configure RUN make -COPY proctor-php.go ${LANG_DIR} +COPY common /root/go/src/gvisor.dev/gvisor/test/runtimes/common/common +COPY php/proctor-php.go ${LANG_DIR} ENTRYPOINT ["/root/go/bin/go", "run", "proctor-php.go"] diff --git a/test/runtimes/python/Dockerfile b/test/runtimes/python/Dockerfile index 811f48f8a..710daee43 100644 --- a/test/runtimes/python/Dockerfile +++ b/test/runtimes/python/Dockerfile @@ -26,6 +26,7 @@ WORKDIR ${LANG_DIR} RUN ./configure --with-pydebug RUN make -s -j2 -COPY proctor-python.go ${LANG_DIR} +COPY common /root/go/src/gvisor.dev/gvisor/test/runtimes/common/common +COPY python/proctor-python.go ${LANG_DIR} ENTRYPOINT ["/root/go/bin/go", "run", "proctor-python.go"] diff --git a/test/runtimes/runtimes_test.go b/test/runtimes/runtimes_test.go index 6bf954e78..43dd6f5b7 100644 --- a/test/runtimes/runtimes_test.go +++ b/test/runtimes/runtimes_test.go @@ -22,8 +22,16 @@ import ( "gvisor.dev/gvisor/runsc/test/testutil" ) -func TestNodeJS(t *testing.T) { - const img = "gcr.io/gvisor-proctor/nodejs" +// Wait time for each test to run. +const timeout = 180 * time.Second + +// Helper function to execute the docker container associated with the +// language passed. Captures the output of the list function and executes +// each test individually, supplying any errors recieved. +func testLang(t *testing.T, lang string) { + t.Helper() + + img := "gcr.io/gvisor-presubmit/" + lang if err := testutil.Pull(img); err != nil { t.Fatalf("docker pull failed: %v", err) } @@ -49,7 +57,7 @@ func TestNodeJS(t *testing.T) { } defer d.CleanUp() - status, err := d.Wait(60 * time.Second) + status, err := d.Wait(timeout) if err != nil { t.Fatalf("docker test %q failed to wait: %v", tc, err) } @@ -65,3 +73,23 @@ func TestNodeJS(t *testing.T) { }) } } + +func TestGo(t *testing.T) { + testLang(t, "go") +} + +func TestJava(t *testing.T) { + testLang(t, "java") +} + +func TestNodejs(t *testing.T) { + testLang(t, "nodejs") +} + +func TestPhp(t *testing.T) { + testLang(t, "php") +} + +func TestPython(t *testing.T) { + testLang(t, "python") +} diff --git a/test/syscalls/BUILD b/test/syscalls/BUILD index a3e43cad2..aa1e33fb4 100644 --- a/test/syscalls/BUILD +++ b/test/syscalls/BUILD @@ -440,7 +440,9 @@ syscall_test( ) syscall_test( - size = "medium", + size = "large", + parallel = False, + shard_count = 10, test = "//test/syscalls/linux:socket_inet_loopback_test", ) diff --git a/test/syscalls/linux/socket_inet_loopback.cc b/test/syscalls/linux/socket_inet_loopback.cc index df31d25b5..322ee07ad 100644 --- a/test/syscalls/linux/socket_inet_loopback.cc +++ b/test/syscalls/linux/socket_inet_loopback.cc @@ -145,6 +145,67 @@ TEST_P(SocketInetLoopbackTest, TCP) { ASSERT_THAT(shutdown(conn_fd.get(), SHUT_RDWR), SyscallSucceeds()); } +TEST_P(SocketInetLoopbackTest, TCPListenClose) { + auto const& param = GetParam(); + + TestAddress const& listener = param.listener; + TestAddress const& connector = param.connector; + + // Create the listening socket. + FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE( + Socket(listener.family(), SOCK_STREAM, IPPROTO_TCP)); + sockaddr_storage listen_addr = listener.addr; + ASSERT_THAT(bind(listen_fd.get(), reinterpret_cast<sockaddr*>(&listen_addr), + listener.addr_len), + SyscallSucceeds()); + ASSERT_THAT(listen(listen_fd.get(), 1001), SyscallSucceeds()); + + // Get the port bound by the listening socket. + socklen_t addrlen = listener.addr_len; + ASSERT_THAT(getsockname(listen_fd.get(), + reinterpret_cast<sockaddr*>(&listen_addr), &addrlen), + SyscallSucceeds()); + uint16_t const port = + ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener.family(), listen_addr)); + + DisableSave ds; // Too many system calls. + sockaddr_storage conn_addr = connector.addr; + ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port)); + constexpr int kFDs = 2048; + constexpr int kThreadCount = 4; + constexpr int kFDsPerThread = kFDs / kThreadCount; + FileDescriptor clients[kFDs]; + std::unique_ptr<ScopedThread> threads[kThreadCount]; + for (int i = 0; i < kFDs; i++) { + clients[i] = ASSERT_NO_ERRNO_AND_VALUE( + Socket(connector.family(), SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP)); + } + for (int i = 0; i < kThreadCount; i++) { + threads[i] = absl::make_unique<ScopedThread>([&connector, &conn_addr, + &clients, i]() { + for (int j = 0; j < kFDsPerThread; j++) { + int k = i * kFDsPerThread + j; + int ret = + connect(clients[k].get(), reinterpret_cast<sockaddr*>(&conn_addr), + connector.addr_len); + if (ret != 0) { + EXPECT_THAT(ret, SyscallFailsWithErrno(EINPROGRESS)); + } + } + }); + } + for (int i = 0; i < kThreadCount; i++) { + threads[i]->Join(); + } + for (int i = 0; i < 32; i++) { + auto accepted = + ASSERT_NO_ERRNO_AND_VALUE(Accept(listen_fd.get(), nullptr, nullptr)); + } + // TODO(b/138400178): Fix cooperative S/R failure when ds.reset() is invoked + // before function end. + // ds.reset() +} + TEST_P(SocketInetLoopbackTest, TCPbacklog) { auto const& param = GetParam(); diff --git a/test/syscalls/linux/splice.cc b/test/syscalls/linux/splice.cc index 1875f4533..e25f264f6 100644 --- a/test/syscalls/linux/splice.cc +++ b/test/syscalls/linux/splice.cc @@ -13,6 +13,7 @@ // limitations under the License. #include <fcntl.h> +#include <sys/eventfd.h> #include <sys/sendfile.h> #include <unistd.h> @@ -135,6 +136,80 @@ TEST(SpliceTest, PipeOffsets) { SyscallFailsWithErrno(ESPIPE)); } +// Event FDs may be used with splice without an offset. +TEST(SpliceTest, FromEventFD) { + // Open the input eventfd with an initial value so that it is readable. + constexpr uint64_t kEventFDValue = 1; + int efd; + ASSERT_THAT(efd = eventfd(kEventFDValue, 0), SyscallSucceeds()); + const FileDescriptor inf(efd); + + // Create a new pipe. + int fds[2]; + ASSERT_THAT(pipe(fds), SyscallSucceeds()); + const FileDescriptor rfd(fds[0]); + const FileDescriptor wfd(fds[1]); + + // Splice 8-byte eventfd value to pipe. + constexpr int kEventFDSize = 8; + EXPECT_THAT(splice(inf.get(), nullptr, wfd.get(), nullptr, kEventFDSize, 0), + SyscallSucceedsWithValue(kEventFDSize)); + + // Contents should be equal. + std::vector<char> rbuf(kEventFDSize); + ASSERT_THAT(read(rfd.get(), rbuf.data(), rbuf.size()), + SyscallSucceedsWithValue(kEventFDSize)); + EXPECT_EQ(memcmp(rbuf.data(), &kEventFDValue, rbuf.size()), 0); +} + +// Event FDs may not be used with splice with an offset. +TEST(SpliceTest, FromEventFDOffset) { + int efd; + ASSERT_THAT(efd = eventfd(0, 0), SyscallSucceeds()); + const FileDescriptor inf(efd); + + // Create a new pipe. + int fds[2]; + ASSERT_THAT(pipe(fds), SyscallSucceeds()); + const FileDescriptor rfd(fds[0]); + const FileDescriptor wfd(fds[1]); + + // Attempt to splice 8-byte eventfd value to pipe with offset. + // + // This is not allowed because eventfd doesn't support pread. + constexpr int kEventFDSize = 8; + loff_t in_off = 0; + EXPECT_THAT(splice(inf.get(), &in_off, wfd.get(), nullptr, kEventFDSize, 0), + SyscallFailsWithErrno(EINVAL)); +} + +// Event FDs may not be used with splice with an offset. +TEST(SpliceTest, ToEventFDOffset) { + // Create a new pipe. + int fds[2]; + ASSERT_THAT(pipe(fds), SyscallSucceeds()); + const FileDescriptor rfd(fds[0]); + const FileDescriptor wfd(fds[1]); + + // Fill with a value. + constexpr int kEventFDSize = 8; + std::vector<char> buf(kEventFDSize); + buf[0] = 1; + ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()), + SyscallSucceedsWithValue(kEventFDSize)); + + int efd; + ASSERT_THAT(efd = eventfd(0, 0), SyscallSucceeds()); + const FileDescriptor outf(efd); + + // Attempt to splice 8-byte eventfd value to pipe with offset. + // + // This is not allowed because eventfd doesn't support pwrite. + loff_t out_off = 0; + EXPECT_THAT(splice(rfd.get(), nullptr, outf.get(), &out_off, kEventFDSize, 0), + SyscallFailsWithErrno(EINVAL)); +} + TEST(SpliceTest, ToPipe) { // Open the input file. const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); |