diff options
author | 2015-11-18 11:19:09 +0000 | |
---|---|---|
committer | 2015-11-18 15:32:05 +0000 | |
commit | 9e1a62ae87feafc9d623a1b036f6ec0348663b76 (patch) | |
tree | db0efeb35a4756d845a20690379c6c71f2d83e8d /src/test/java/com/google/devtools/build/lib/server | |
parent | 9b1e3a2957981ab6900dbb7d29c8c68ef9ba2f76 (diff) |
Open-source RPC tests.
--
MOS_MIGRATED_REVID=108127872
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/server')
3 files changed, 319 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/server/RPCServerTest.java b/src/test/java/com/google/devtools/build/lib/server/RPCServerTest.java new file mode 100644 index 0000000000..9f6ce729d6 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/server/RPCServerTest.java @@ -0,0 +1,126 @@ +// Copyright 2015 The Bazel Authors. All rights reserved. +// +// 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 com.google.devtools.build.lib.server; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.devtools.build.lib.testutil.Suite; +import com.google.devtools.build.lib.testutil.TestSpec; +import com.google.devtools.build.lib.util.JavaClock; +import com.google.devtools.build.lib.util.io.OutErr; +import com.google.devtools.build.lib.util.io.RecordingOutErr; +import com.google.devtools.build.lib.vfs.FileSystemUtils; +import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.build.lib.vfs.util.FsApparatus; + +import junit.framework.TestCase; + +import java.io.File; +import java.util.List; + +/** + * Run a real RPC server on localhost, and talk to it using the testing + * client. + */ +@TestSpec(size = Suite.MEDIUM_TESTS) +public class RPCServerTest extends TestCase { + + private static final long MAX_IDLE_MILLIS = 10000; + private static final long HEALTH_CHECK_MILLIS = 1000 * 3; + private static final String COMMAND_STDOUT = "Heelllloo...."; + private static final String COMMAND_STDERR = "...world!"; + + private RPCServer server; + private FsApparatus scratch = FsApparatus.newNative(); + private RecordingOutErr outErr = new RecordingOutErr(); + private Path serverDir; + private Path workspaceDir; + private RPCTestingClient client; + private Thread serverThread = new Thread(){ + @Override + public void run() { + server.serve(); + } + }; + + private static final ServerCommand helloWorldCommand = new ServerCommand() { + @Override + public int exec(List<String> args, OutErr outErr, long firstContactTime) throws Exception { + outErr.printOut(COMMAND_STDOUT); + outErr.printErr(COMMAND_STDERR); + return 42; + } + @Override + public boolean shutdown() { + return false; + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Do not use `createUnixTempDir()` here since the file name that results is longer + // than 108 characters, so cannot be used as local socket address. + File file = File.createTempFile("scratch", ".tmp", new File("/tmp")); + file.delete(); + file.mkdir(); + serverDir = this.scratch.dir(file.getAbsolutePath()); + + workspaceDir = this.scratch.createUnixTempDir(); + workspaceDir.createDirectory(); + client = new RPCTestingClient( + outErr, serverDir.getRelative("server.socket")); + RPCService service = new RPCService(helloWorldCommand); + server = new RPCServer(new JavaClock(), service, MAX_IDLE_MILLIS, HEALTH_CHECK_MILLIS, + serverDir, workspaceDir); + serverThread.start(); + } + + @Override + protected void tearDown() throws Exception { + serverThread.interrupt(); + serverThread.join(); + + FileSystemUtils.deleteTree(serverDir); + super.tearDown(); + } + + protected void testRequest(String request, int ret, String out, String err, + String control) throws Exception { + assertEquals(new ServerResponse(control, ret), client.sendRequest(request)); + assertEquals(out, outErr.outAsLatin1()); + assertThat(outErr.errAsLatin1()).contains(err); + } + + public void testUnknownCommand() throws Exception { + testRequest("unknown", 2, "", "SERVER ERROR: Unknown command: unknown\n", ""); + } + + public void testEmptyBlazeCommand() throws Exception { + testRequest("unknown", 2, "", "SERVER ERROR: Unknown command: unknown\n", ""); + } + + public void testWorkspaceDies() throws Exception { + assertTrue(serverThread.isAlive()); + testRequest("blaze", 42, COMMAND_STDOUT, COMMAND_STDERR, ""); + Thread.sleep(HEALTH_CHECK_MILLIS * 2); + assertTrue(serverThread.isAlive()); + + assertTrue(workspaceDir.delete()); + Thread.sleep(HEALTH_CHECK_MILLIS * 2); + assertFalse(serverThread.isAlive()); + } +} diff --git a/src/test/java/com/google/devtools/build/lib/server/RPCServiceTest.java b/src/test/java/com/google/devtools/build/lib/server/RPCServiceTest.java new file mode 100644 index 0000000000..42e2683af0 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/server/RPCServiceTest.java @@ -0,0 +1,115 @@ +// Copyright 2015 The Bazel Authors. All rights reserved. +// +// 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 com.google.devtools.build.lib.server; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.devtools.build.lib.server.RPCService.UnknownCommandException; +import com.google.devtools.build.lib.util.io.OutErr; +import com.google.devtools.build.lib.util.io.RecordingOutErr; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Just makes sure the RPC service understands commands. + */ +public class RPCServiceTest extends TestCase { + + private ServerCommand helloWorldCommand = new ServerCommand() { + @Override + public int exec(List<String> args, OutErr outErr, long firstContactTime) throws Exception { + outErr.printOut("Heelllloo...."); + outErr.printErr("...world!"); + return 42; + } + @Override + public boolean shutdown() { + return false; + } + }; + + private RPCService service = + new RPCService(helloWorldCommand); + + public void testUnknownCommandException() { + try { + service.executeRequest(Arrays.asList("unknown"), new RecordingOutErr(), 0); + fail(); + } catch (UnknownCommandException e) { + // success + } catch (Exception e){ + fail(); + } + } + + public void testCommandGetsExecuted() throws Exception { + RecordingOutErr outErr = new RecordingOutErr(); + int exitStatus = service.executeRequest(Arrays.asList("blaze"), outErr, 0); + + assertEquals(42, exitStatus); + assertEquals("Heelllloo....", outErr.outAsLatin1()); + assertEquals("...world!", outErr.errAsLatin1()); + } + + public void testDelimitation() throws Exception { + final List<String> savedArgs = new ArrayList<>(); + + RPCService service = + new RPCService(new ServerCommand() { + @Override + public int exec(List<String> args, OutErr outErr, long firstContactTime) + throws Exception { + savedArgs.addAll(args); + return 0; + } + @Override + public boolean shutdown() { + return false; + } + }); + + List<String> args = Arrays.asList("blaze", "", " \n", "", "", "", "foo"); + service.executeRequest(args, new RecordingOutErr(), 0); + assertEquals(args.subList(1, args.size()), + savedArgs); + } + + public void testShutdownState() throws Exception { + assertFalse(service.isShutdown()); + service.shutdown(); + assertTrue(service.isShutdown()); + service.shutdown(); + assertTrue(service.isShutdown()); + } + + public void testCommandFailsAfterShutdown() throws Exception { + RecordingOutErr outErr = new RecordingOutErr(); + service.shutdown(); + try { + service.executeRequest(Arrays.asList("blaze"), outErr, 0); + fail(); + } catch (IllegalStateException e) { + assertThat(e).hasMessage("Received request after shutdown."); + /* Make sure it does not execute the command! */ + assertThat(outErr.outAsLatin1()).isEmpty(); + assertThat(outErr.errAsLatin1()).isEmpty(); + } + } + +} diff --git a/src/test/java/com/google/devtools/build/lib/server/RPCTestingClient.java b/src/test/java/com/google/devtools/build/lib/server/RPCTestingClient.java new file mode 100644 index 0000000000..e24e0bb3ac --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/server/RPCTestingClient.java @@ -0,0 +1,78 @@ +// Copyright 2015 The Bazel Authors. All rights reserved. +// +// 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 com.google.devtools.build.lib.server; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.common.io.ByteStreams; +import com.google.devtools.build.lib.unix.LocalClientSocket; +import com.google.devtools.build.lib.unix.LocalSocketAddress; +import com.google.devtools.build.lib.util.io.RecordingOutErr; +import com.google.devtools.build.lib.util.io.StreamDemultiplexer; +import com.google.devtools.build.lib.vfs.Path; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; + +/** + * A client to test RPCServer. + */ +public class RPCTestingClient { + + private final RecordingOutErr outErr; + private final Path socketFile; + + /** + * Create a client to RPCServer. {@code socketFile} must be a file + * on disk; this will not work with the in-memory file system. + */ + public RPCTestingClient(RecordingOutErr outErr, Path socketFile) { + this.socketFile = socketFile; + this.outErr = outErr; + } + + public ServerResponse sendRequest(String command, String... params) + throws Exception { + String request = command; + for (String param : params) { + request += "\0" + param; + } + return sendRequest(request); + } + + public ServerResponse sendRequest(String request) throws Exception { + LocalClientSocket connection = new LocalClientSocket(); + connection.connect(new LocalSocketAddress(socketFile.getPathFile())); + try { + OutputStream out = connection.getOutputStream(); + out.write(request.getBytes(UTF_8)); + out.flush(); + connection.shutdownOutput(); + + OutputStream stdout = outErr.getOutputStream(); + OutputStream stderr = outErr.getErrorStream(); + ByteArrayOutputStream control = new ByteArrayOutputStream(); + StreamDemultiplexer demux = new StreamDemultiplexer((byte) '1', + stdout, stderr, control); + ByteStreams.copy(connection.getInputStream(), demux); + demux.flush(); + + return ServerResponse.parseFrom(control); + } finally { + connection.close(); + } + } + +} |