diff options
Diffstat (limited to 'third_party/protobuf/conformance/conformance_test_runner.cc')
-rw-r--r-- | third_party/protobuf/conformance/conformance_test_runner.cc | 326 |
1 files changed, 0 insertions, 326 deletions
diff --git a/third_party/protobuf/conformance/conformance_test_runner.cc b/third_party/protobuf/conformance/conformance_test_runner.cc deleted file mode 100644 index 7e91d388b0..0000000000 --- a/third_party/protobuf/conformance/conformance_test_runner.cc +++ /dev/null @@ -1,326 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This file contains a program for running the test suite in a separate -// process. The other alternative is to run the suite in-process. See -// conformance.proto for pros/cons of these two options. -// -// This program will fork the process under test and communicate with it over -// its stdin/stdout: -// -// +--------+ pipe +----------+ -// | tester | <------> | testee | -// | | | | -// | C++ | | any lang | -// +--------+ +----------+ -// -// The tester contains all of the test cases and their expected output. -// The testee is a simple program written in the target language that reads -// each test case and attempts to produce acceptable output for it. -// -// Every test consists of a ConformanceRequest/ConformanceResponse -// request/reply pair. The protocol on the pipe is simply: -// -// 1. tester sends 4-byte length N (little endian) -// 2. tester sends N bytes representing a ConformanceRequest proto -// 3. testee sends 4-byte length M (little endian) -// 4. testee sends M bytes representing a ConformanceResponse proto - -#include <algorithm> -#include <errno.h> -#include <fstream> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#include <vector> - -#include <google/protobuf/stubs/stringprintf.h> - -#include "conformance.pb.h" -#include "conformance_test.h" - -using conformance::ConformanceRequest; -using conformance::ConformanceResponse; -using google::protobuf::internal::scoped_array; -using google::protobuf::StringAppendF; -using std::string; -using std::vector; - -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) -#define CHECK_SYSCALL(call) \ - if (call < 0) { \ - perror(#call " " __FILE__ ":" TOSTRING(__LINE__)); \ - exit(1); \ - } - -// Test runner that spawns the process being tested and communicates with it -// over a pipe. -class ForkPipeRunner : public google::protobuf::ConformanceTestRunner { - public: - ForkPipeRunner(const std::string &executable) - : child_pid_(-1), executable_(executable) {} - - virtual ~ForkPipeRunner() {} - - void RunTest(const std::string& test_name, - const std::string& request, - std::string* response) { - if (child_pid_ < 0) { - SpawnTestProgram(); - } - - current_test_name_ = test_name; - - uint32_t len = request.size(); - CheckedWrite(write_fd_, &len, sizeof(uint32_t)); - CheckedWrite(write_fd_, request.c_str(), request.size()); - - if (!TryRead(read_fd_, &len, sizeof(uint32_t))) { - // We failed to read from the child, assume a crash and try to reap. - GOOGLE_LOG(INFO) << "Trying to reap child, pid=" << child_pid_; - - int status; - waitpid(child_pid_, &status, WEXITED); - - string error_msg; - if (WIFEXITED(status)) { - StringAppendF(&error_msg, - "child exited, status=%d", WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - StringAppendF(&error_msg, - "child killed by signal %d", WTERMSIG(status)); - } - GOOGLE_LOG(INFO) << error_msg; - child_pid_ = -1; - - conformance::ConformanceResponse response_obj; - response_obj.set_runtime_error(error_msg); - response_obj.SerializeToString(response); - return; - } - - response->resize(len); - CheckedRead(read_fd_, (void*)response->c_str(), len); - } - - private: - // TODO(haberman): make this work on Windows, instead of using these - // UNIX-specific APIs. - // - // There is a platform-agnostic API in - // src/google/protobuf/compiler/subprocess.h - // - // However that API only supports sending a single message to the subprocess. - // We really want to be able to send messages and receive responses one at a - // time: - // - // 1. Spawning a new process for each test would take way too long for thousands - // of tests and subprocesses like java that can take 100ms or more to start - // up. - // - // 2. Sending all the tests in one big message and receiving all results in one - // big message would take away our visibility about which test(s) caused a - // crash or other fatal error. It would also give us only a single failure - // instead of all of them. - void SpawnTestProgram() { - int toproc_pipe_fd[2]; - int fromproc_pipe_fd[2]; - if (pipe(toproc_pipe_fd) < 0 || pipe(fromproc_pipe_fd) < 0) { - perror("pipe"); - exit(1); - } - - pid_t pid = fork(); - if (pid < 0) { - perror("fork"); - exit(1); - } - - if (pid) { - // Parent. - CHECK_SYSCALL(close(toproc_pipe_fd[0])); - CHECK_SYSCALL(close(fromproc_pipe_fd[1])); - write_fd_ = toproc_pipe_fd[1]; - read_fd_ = fromproc_pipe_fd[0]; - child_pid_ = pid; - } else { - // Child. - CHECK_SYSCALL(close(STDIN_FILENO)); - CHECK_SYSCALL(close(STDOUT_FILENO)); - CHECK_SYSCALL(dup2(toproc_pipe_fd[0], STDIN_FILENO)); - CHECK_SYSCALL(dup2(fromproc_pipe_fd[1], STDOUT_FILENO)); - - CHECK_SYSCALL(close(toproc_pipe_fd[0])); - CHECK_SYSCALL(close(fromproc_pipe_fd[1])); - CHECK_SYSCALL(close(toproc_pipe_fd[1])); - CHECK_SYSCALL(close(fromproc_pipe_fd[0])); - - scoped_array<char> executable(new char[executable_.size() + 1]); - memcpy(executable.get(), executable_.c_str(), executable_.size()); - executable[executable_.size()] = '\0'; - - char *const argv[] = {executable.get(), NULL}; - CHECK_SYSCALL(execv(executable.get(), argv)); // Never returns. - } - } - - void CheckedWrite(int fd, const void *buf, size_t len) { - if (write(fd, buf, len) != len) { - GOOGLE_LOG(FATAL) << current_test_name_ - << ": error writing to test program: " - << strerror(errno); - } - } - - bool TryRead(int fd, void *buf, size_t len) { - size_t ofs = 0; - while (len > 0) { - ssize_t bytes_read = read(fd, (char*)buf + ofs, len); - - if (bytes_read == 0) { - GOOGLE_LOG(ERROR) << current_test_name_ - << ": unexpected EOF from test program"; - return false; - } else if (bytes_read < 0) { - GOOGLE_LOG(ERROR) << current_test_name_ - << ": error reading from test program: " - << strerror(errno); - return false; - } - - len -= bytes_read; - ofs += bytes_read; - } - - return true; - } - - void CheckedRead(int fd, void *buf, size_t len) { - if (!TryRead(fd, buf, len)) { - GOOGLE_LOG(FATAL) << current_test_name_ - << ": error reading from test program: " - << strerror(errno); - } - } - - int write_fd_; - int read_fd_; - pid_t child_pid_; - std::string executable_; - std::string current_test_name_; -}; - -void UsageError() { - fprintf(stderr, - "Usage: conformance-test-runner [options] <test-program>\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Options:\n"); - fprintf(stderr, - " --failure_list <filename> Use to specify list of tests\n"); - fprintf(stderr, - " that are expected to fail. File\n"); - fprintf(stderr, - " should contain one test name per\n"); - fprintf(stderr, - " line. Use '#' for comments.\n"); - fprintf(stderr, - " --enforce_recommended Enforce that recommended test\n"); - fprintf(stderr, - " cases are also passing. Specify\n"); - fprintf(stderr, - " this flag if you want to be\n"); - fprintf(stderr, - " strictly conforming to protobuf\n"); - fprintf(stderr, - " spec.\n"); - exit(1); -} - -void ParseFailureList(const char *filename, vector<string>* failure_list) { - std::ifstream infile(filename); - - if (!infile.is_open()) { - fprintf(stderr, "Couldn't open failure list file: %s\n", filename); - exit(1); - } - - for (string line; getline(infile, line);) { - // Remove whitespace. - line.erase(std::remove_if(line.begin(), line.end(), ::isspace), - line.end()); - - // Remove comments. - line = line.substr(0, line.find("#")); - - if (!line.empty()) { - failure_list->push_back(line); - } - } -} - -int main(int argc, char *argv[]) { - char *program; - google::protobuf::ConformanceTestSuite suite; - - string failure_list_filename; - vector<string> failure_list; - - for (int arg = 1; arg < argc; ++arg) { - if (strcmp(argv[arg], "--failure_list") == 0) { - if (++arg == argc) UsageError(); - failure_list_filename = argv[arg]; - ParseFailureList(argv[arg], &failure_list); - } else if (strcmp(argv[arg], "--verbose") == 0) { - suite.SetVerbose(true); - } else if (strcmp(argv[arg], "--enforce_recommended") == 0) { - suite.SetEnforceRecommended(true); - } else if (argv[arg][0] == '-') { - fprintf(stderr, "Unknown option: %s\n", argv[arg]); - UsageError(); - } else { - if (arg != argc - 1) { - fprintf(stderr, "Too many arguments.\n"); - UsageError(); - } - program = argv[arg]; - } - } - - suite.SetFailureList(failure_list_filename, failure_list); - ForkPipeRunner runner(program); - - std::string output; - bool ok = suite.RunSuite(&runner, &output); - - fwrite(output.c_str(), 1, output.size(), stderr); - - return ok ? EXIT_SUCCESS : EXIT_FAILURE; -} |