Crash handling test

pull/1625/head
Craig Tiller 10 years ago
parent 685f1e6255
commit fbac5f17b7
  1. 88
      Makefile
  2. 36
      build.json
  3. 10
      include/grpc/support/subprocess.h
  4. 6
      src/core/support/subprocess_posix.c
  5. 9
      src/core/surface/call.c
  6. 4
      test/core/fling/fling_test.c
  7. 159
      test/cpp/end2end/crash_test.cc
  8. 95
      test/cpp/end2end/crash_test_server.cc
  9. 66
      test/cpp/util/subprocess.cc
  10. 61
      test/cpp/util/subprocess.h
  11. 9
      tools/run_tests/tests.json

File diff suppressed because one or more lines are too long

@ -542,7 +542,8 @@
"test/cpp/util/echo.proto",
"test/cpp/util/echo_duplicate.proto",
"test/cpp/util/cli_call.cc",
"test/cpp/util/create_test_channel.cc"
"test/cpp/util/create_test_channel.cc",
"test/cpp/util/subprocess.cc"
]
},
{
@ -1874,6 +1875,39 @@
"gpr"
]
},
{
"name": "crash_test",
"build": "test",
"language": "c++",
"src": [
"test/cpp/end2end/crash_test.cc"
],
"deps": [
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "crash_test_server",
"build": "test",
"run": false,
"language": "c++",
"src": [
"test/cpp/end2end/crash_test_server.cc"
],
"deps": [
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "credentials_test",
"build": "test",

@ -34,16 +34,24 @@
#ifndef GRPC_SUPPORT_SUBPROCESS_H
#define GRPC_SUPPORT_SUBPROCESS_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct gpr_subprocess gpr_subprocess;
/* .exe on windows, empty on unices */
char *gpr_subprocess_binary_extension();
gpr_subprocess *gpr_subprocess_create(int argc, char **argv);
gpr_subprocess *gpr_subprocess_create(int argc, const char **argv);
/* if subprocess has not been joined, kill it */
void gpr_subprocess_destroy(gpr_subprocess *p);
/* returns exit status; can be called at most once */
int gpr_subprocess_join(gpr_subprocess *p);
void gpr_subprocess_interrupt(gpr_subprocess *p);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

@ -57,7 +57,7 @@ struct gpr_subprocess {
char *gpr_subprocess_binary_extension() { return ""; }
gpr_subprocess *gpr_subprocess_create(int argc, char **argv) {
gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) {
gpr_subprocess *r;
int pid;
char **exec_args;
@ -92,7 +92,11 @@ void gpr_subprocess_destroy(gpr_subprocess *p) {
int gpr_subprocess_join(gpr_subprocess *p) {
int status;
retry:
if (waitpid(p->pid, &status, 0) == -1) {
if (errno == EINTR) {
goto retry;
}
gpr_log(GPR_ERROR, "waitpid failed: %s", strerror(errno));
return -1;
}

@ -1175,6 +1175,10 @@ static void set_cancelled_value(grpc_status_code status, void *dest) {
}
static void finish_batch(grpc_call *call, int success, void *tag) {
grpc_cq_end_op(call->cq, tag, call, success);
}
static void finish_batch_with_close(grpc_call *call, int success, void *tag) {
grpc_cq_end_op(call->cq, tag, call, 1);
}
@ -1185,6 +1189,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
size_t out;
const grpc_op *op;
grpc_ioreq *req;
void (*finish_func)(grpc_call *, int, void *) = finish_batch;
GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
@ -1268,6 +1273,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
op->data.recv_status_on_client.trailing_metadata;
req = &reqs[out++];
req->op = GRPC_IOREQ_RECV_CLOSE;
finish_func = finish_batch_with_close;
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
req = &reqs[out++];
@ -1277,13 +1283,14 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
op->data.recv_close_on_server.cancelled;
req = &reqs[out++];
req->op = GRPC_IOREQ_RECV_CLOSE;
finish_func = finish_batch_with_close;
break;
}
}
grpc_cq_begin_op(call->cq, call);
return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_batch,
return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_func,
tag);
}

@ -60,7 +60,7 @@ int main(int argc, char **argv) {
args[1] = "--bind";
gpr_join_host_port(&args[2], "::", port);
args[3] = "--no-secure";
svr = gpr_subprocess_create(4, args);
svr = gpr_subprocess_create(4, (const char**)args);
gpr_free(args[0]);
gpr_free(args[2]);
@ -71,7 +71,7 @@ int main(int argc, char **argv) {
args[3] = "--scenario=ping-pong-request";
args[4] = "--no-secure";
args[5] = 0;
cli = gpr_subprocess_create(6, args);
cli = gpr_subprocess_create(6, (const char**)args);
gpr_free(args[0]);
gpr_free(args[2]);

@ -0,0 +1,159 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* 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.
*
*/
#include <thread>
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include "test/cpp/util/echo_duplicate.grpc.pb.h"
#include "test/cpp/util/echo.grpc.pb.h"
#include "src/cpp/server/thread_pool.h"
#include <grpc++/channel_arguments.h>
#include <grpc++/channel_interface.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/credentials.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/server_credentials.h>
#include <grpc++/status.h>
#include <grpc++/stream.h>
#include <grpc++/time.h>
#include <gtest/gtest.h>
#include <grpc/grpc.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
#include "test/cpp/util/subprocess.h"
using grpc::cpp::test::util::EchoRequest;
using grpc::cpp::test::util::EchoResponse;
using std::chrono::system_clock;
static std::string g_root;
namespace grpc {
namespace testing {
namespace {
class CrashTest : public ::testing::Test {
protected:
CrashTest() {}
std::unique_ptr<grpc::cpp::test::util::TestService::Stub> CreateServerAndStub() {
auto port = grpc_pick_unused_port_or_die();
auto addr = (std::ostringstream() << "localhost:" << port).str();
server_.reset(new SubProcess({
(std::ostringstream() << g_root << "/crash_test_server").str(),
(std::ostringstream() << "--address=" << addr).str(),
}));
GPR_ASSERT(server_);
return grpc::cpp::test::util::TestService::NewStub(CreateChannel(addr, InsecureCredentials(), ChannelArguments()));
}
void KillServer() {
server_.reset();
}
private:
std::unique_ptr<SubProcess> server_;
};
TEST_F(CrashTest, KillAfterWrite) {
auto stub = CreateServerAndStub();
EchoRequest request;
EchoResponse response;
ClientContext context;
auto stream = stub->BidiStream(&context);
request.set_message("Hello");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->Read(&response));
EXPECT_EQ(response.message(), request.message());
request.set_message("I'm going to kill you");
EXPECT_TRUE(stream->Write(request));
KillServer();
EXPECT_FALSE(stream->Read(&response));
EXPECT_FALSE(stream->Finish().IsOk());
}
TEST_F(CrashTest, KillBeforeWrite) {
auto stub = CreateServerAndStub();
EchoRequest request;
EchoResponse response;
ClientContext context;
auto stream = stub->BidiStream(&context);
request.set_message("Hello");
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->Read(&response));
EXPECT_EQ(response.message(), request.message());
KillServer();
request.set_message("You should be dead");
EXPECT_FALSE(stream->Write(request));
EXPECT_FALSE(stream->Read(&response));
EXPECT_FALSE(stream->Finish().IsOk());
}
} // namespace
} // namespace testing
} // namespace grpc
int main(int argc, char** argv) {
std::string me = argv[0];
auto lslash = me.rfind('/');
if (lslash != std::string::npos) {
g_root = me.substr(0, lslash);
} else {
g_root = ".";
}
grpc_test_init(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -0,0 +1,95 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* 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.
*
*/
#include <iostream>
#include <memory>
#include <string>
#include <gflags/gflags.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/server_credentials.h>
#include <grpc++/status.h>
#include "test/cpp/util/echo.grpc.pb.h"
DEFINE_string(address, "", "Address to bind to");
using grpc::cpp::test::util::EchoRequest;
using grpc::cpp::test::util::EchoResponse;
// In some distros, gflags is in the namespace google, and in some others,
// in gflags. This hack is enabling us to find both.
namespace google {}
namespace gflags {}
using namespace google;
using namespace gflags;
namespace grpc {
namespace testing {
class ServiceImpl final : public grpc::cpp::test::util::TestService::Service {
Status BidiStream(ServerContext* context,
ServerReaderWriter<EchoResponse, EchoRequest>* stream)
GRPC_OVERRIDE {
EchoRequest request;
EchoResponse response;
while (stream->Read(&request)) {
gpr_log(GPR_INFO, "recv msg %s", request.message().c_str());
response.set_message(request.message());
stream->Write(response);
}
return Status::OK;
}
};
void RunServer() {
ServiceImpl service;
ServerBuilder builder;
builder.AddListeningPort(FLAGS_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << FLAGS_address << std::endl;
server->Wait();
}
}
}
int main(int argc, char** argv) {
ParseCommandLineFlags(&argc, &argv, true);
grpc::testing::RunServer();
return 0;
}

@ -0,0 +1,66 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* 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.
*
*/
#include "test/cpp/util/subprocess.h"
#include <vector>
#include <grpc/support/subprocess.h>
namespace grpc {
static gpr_subprocess *MakeProcess(std::initializer_list<std::string> args) {
std::vector<const char *> vargs;
for (auto it = args.begin(); it != args.end(); ++it) {
vargs.push_back(it->c_str());
}
return gpr_subprocess_create(vargs.size(), &vargs[0]);
}
SubProcess::SubProcess(std::initializer_list<std::string> args)
: subprocess_(MakeProcess(args)) {
}
SubProcess::~SubProcess() {
gpr_subprocess_destroy(subprocess_);
}
int SubProcess::Join() {
return gpr_subprocess_join(subprocess_);
}
void SubProcess::Interrupt() {
gpr_subprocess_interrupt(subprocess_);
}
} // namespace grpc

@ -0,0 +1,61 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* 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.
*
*/
#ifndef GRPC_TEST_CPP_UTIL_SUBPROCESS_H
#define GRPC_TEST_CPP_UTIL_SUBPROCESS_H
#include <initializer_list>
#include <string>
struct gpr_subprocess;
namespace grpc {
class SubProcess {
public:
SubProcess(std::initializer_list<std::string> args);
~SubProcess();
int Join();
void Interrupt();
private:
SubProcess(const SubProcess& other);
SubProcess& operator=(const SubProcess& other);
gpr_subprocess *const subprocess_;
};
} // namespace grpc
#endif // GRPC_TEST_CPP_UTIL_SUBPROCESS_H

@ -614,6 +614,15 @@
"posix"
]
},
{
"flaky": false,
"language": "c++",
"name": "crash_test",
"platforms": [
"windows",
"posix"
]
},
{
"flaky": false,
"language": "c++",

Loading…
Cancel
Save