aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Craig Tiller <ctiller@google.com>2015-12-14 21:51:38 -0800
committerGravatar Craig Tiller <ctiller@google.com>2015-12-14 21:51:38 -0800
commit1a423eff872a8a576f168bc564f9c567f292b0aa (patch)
tree49cc884bc64c083a5217a02679de93c256b6fcfa
parentb54a9ccd28ff82dd91d98ac842943549615155b4 (diff)
parentc10d68d27beaa0935918d0819cd776b98f7b8300 (diff)
Merge branch 'proxy-crash' into server_stall
-rw-r--r--include/grpc++/client_context.h11
-rw-r--r--src/core/surface/completion_queue.h3
-rw-r--r--src/core/transport/chttp2/writing.c8
-rw-r--r--src/core/transport/chttp2_transport.c51
-rw-r--r--src/cpp/client/client_context.cc23
-rw-r--r--src/python/grpcio/setup.py2
-rw-r--r--test/core/client_config/lb_policies_test.c180
-rw-r--r--test/core/httpcli/httpcli_test.c21
-rw-r--r--test/core/httpcli/httpscli_test.c21
-rwxr-xr-xtools/run_tests/run_lcov.sh2
10 files changed, 245 insertions, 77 deletions
diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h
index 1b6769dee1..8e7c3579e3 100644
--- a/include/grpc++/client_context.h
+++ b/include/grpc++/client_context.h
@@ -280,6 +280,17 @@ class ClientContext {
/// There is no guarantee the call will be cancelled.
void TryCancel();
+ /// Global Callbacks
+ ///
+ /// Can be set exactly once per application to install hooks whenever
+ /// a client context is constructed and destructed.
+ class GlobalCallbacks {
+ public:
+ virtual void DefaultConstructor(ClientContext* context) = 0;
+ virtual void Destructor(ClientContext* context) = 0;
+ };
+ static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
+
private:
// Disallow copy and assign.
ClientContext(const ClientContext&);
diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h
index d58fb1eb87..1e40c48bea 100644
--- a/src/core/surface/completion_queue.h
+++ b/src/core/surface/completion_queue.h
@@ -68,7 +68,8 @@ void grpc_cq_internal_unref(grpc_completion_queue *cc);
#endif
/* Flag that an operation is beginning: the completion channel will not finish
- shutdown until a corrensponding grpc_cq_end_* call is made */
+ shutdown until a corrensponding grpc_cq_end_* call is made.
+ \a tag is currently used only in debug builds. */
void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag);
/* Queue a GRPC_OP_COMPLETED operation; tag must correspond to the tag passed to
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
index 265448641a..b5ca42d69c 100644
--- a/src/core/transport/chttp2/writing.c
+++ b/src/core/transport/chttp2/writing.c
@@ -332,10 +332,6 @@ void grpc_chttp2_cleanup_writing(
while (grpc_chttp2_list_pop_written_stream(
transport_global, transport_writing, &stream_global, &stream_writing)) {
- if (stream_writing->sent_trailing_metadata) {
- grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
- !transport_global->is_client, 1);
- }
if (stream_writing->sent_initial_metadata) {
grpc_chttp2_complete_closure_step(
exec_ctx, &stream_global->send_initial_metadata_finished, 1);
@@ -350,6 +346,10 @@ void grpc_chttp2_cleanup_writing(
grpc_chttp2_complete_closure_step(
exec_ctx, &stream_global->send_trailing_metadata_finished, 1);
}
+ if (stream_writing->sent_trailing_metadata) {
+ grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
+ !transport_global->is_client, 1);
+ }
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
}
gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf);
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index a5bb7018e3..015c156d94 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -115,11 +115,6 @@ static void close_from_api(grpc_exec_ctx *exec_ctx,
grpc_status_code status,
gpr_slice *optional_message);
-/** Fail any outstanding ops: must be called under lock, whilst not parsing */
-static void fail_all_outstanding_ops(
- grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_stream_global *stream_global);
-
/** Add endpoint from this transport to pollset */
static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
@@ -753,33 +748,6 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
*pclosure = NULL;
}
-static void fail_all_outstanding_ops(
- grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_stream_global *stream_global) {
- grpc_chttp2_stream_parsing *stream_parsing;
- GPR_ASSERT(!TRANSPORT_FROM_GLOBAL(transport_global)->parsing_active);
- stream_parsing = &STREAM_FROM_GLOBAL(stream_global)->parsing;
- grpc_chttp2_complete_closure_step(
- exec_ctx, &stream_global->send_initial_metadata_finished, 0);
- grpc_chttp2_complete_closure_step(
- exec_ctx, &stream_global->send_trailing_metadata_finished, 0);
- grpc_chttp2_complete_closure_step(exec_ctx,
- &stream_global->send_message_finished, 0);
- grpc_chttp2_complete_closure_step(
- exec_ctx, &stream_global->recv_initial_metadata_finished, 0);
- grpc_chttp2_complete_closure_step(
- exec_ctx, &stream_global->recv_trailing_metadata_finished, 0);
- if (stream_global->recv_message_ready != NULL) {
- grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, 0);
- stream_global->recv_message_ready = 0;
- }
- if (stream_parsing->data_parser.parsing_frame != NULL) {
- grpc_chttp2_incoming_byte_stream_finished(
- exec_ctx, stream_parsing->data_parser.parsing_frame, 0, 0);
- stream_parsing->data_parser.parsing_frame = NULL;
- }
-}
-
static int contains_non_ok_status(
grpc_chttp2_transport_global *transport_global,
grpc_metadata_batch *batch) {
@@ -1054,9 +1022,6 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
exec_ctx, &stream_global->recv_trailing_metadata_finished, 1);
}
}
- if (stream_global->finished_close) {
- fail_all_outstanding_ops(exec_ctx, transport_global, stream_global);
- }
}
}
@@ -1075,6 +1040,16 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->parsing.incoming_stream = NULL;
grpc_chttp2_parsing_become_skip_parser(exec_ctx, &t->parsing);
}
+ if (s->global.recv_message_ready != NULL) {
+ grpc_exec_ctx_enqueue(exec_ctx, s->global.recv_message_ready, 0);
+ s->global.recv_message_ready = 0;
+ }
+ if (s->parsing.data_parser.parsing_frame != NULL) {
+ grpc_chttp2_incoming_byte_stream_finished(
+ exec_ctx, s->parsing.data_parser.parsing_frame, 0, 0);
+ s->parsing.data_parser.parsing_frame = NULL;
+ }
+
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
close_transport_locked(exec_ctx, t);
}
@@ -1158,6 +1133,12 @@ void grpc_chttp2_mark_stream_closed(
}
if (close_writes && !stream_global->write_closed) {
stream_global->write_closed = 1;
+ grpc_chttp2_complete_closure_step(
+ exec_ctx, &stream_global->send_initial_metadata_finished, 0);
+ grpc_chttp2_complete_closure_step(
+ exec_ctx, &stream_global->send_trailing_metadata_finished, 0);
+ grpc_chttp2_complete_closure_step(exec_ctx,
+ &stream_global->send_message_finished, 0);
}
if (stream_global->read_closed && stream_global->write_closed) {
if (stream_global->id != 0 &&
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 9bb358b233..2aa532808c 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -45,17 +45,31 @@
namespace grpc {
+class DefaultGlobalClientCallbacks GRPC_FINAL
+ : public ClientContext::GlobalCallbacks {
+ public:
+ void DefaultConstructor(ClientContext* context) GRPC_OVERRIDE {}
+ void Destructor(ClientContext* context) GRPC_OVERRIDE {}
+};
+
+static DefaultGlobalClientCallbacks g_default_client_callbacks;
+static ClientContext::GlobalCallbacks* g_client_callbacks =
+ &g_default_client_callbacks;
+
ClientContext::ClientContext()
: initial_metadata_received_(false),
call_(nullptr),
call_canceled_(false),
deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
- propagate_from_call_(nullptr) {}
+ propagate_from_call_(nullptr) {
+ g_client_callbacks->DefaultConstructor(this);
+}
ClientContext::~ClientContext() {
if (call_) {
grpc_call_destroy(call_);
}
+ g_client_callbacks->Destructor(this);
}
std::unique_ptr<ClientContext> ClientContext::FromServerContext(
@@ -124,4 +138,11 @@ grpc::string ClientContext::peer() const {
return peer;
}
+void ClientContext::SetGlobalCallbacks(GlobalCallbacks* client_callbacks) {
+ GPR_ASSERT(g_client_callbacks == &g_default_client_callbacks);
+ GPR_ASSERT(client_callbacks != NULL);
+ GPR_ASSERT(client_callbacks != &g_default_client_callbacks);
+ g_client_callbacks = client_callbacks;
+}
+
} // namespace grpc
diff --git a/src/python/grpcio/setup.py b/src/python/grpcio/setup.py
index a948ca1fac..b8a98c3d85 100644
--- a/src/python/grpcio/setup.py
+++ b/src/python/grpcio/setup.py
@@ -163,7 +163,7 @@ else:
setuptools.setup(
name='grpcio',
- version='0.11.0b2',
+ version='0.12.0b0',
ext_modules=CYTHON_EXTENSION_MODULES,
packages=list(PACKAGES),
package_dir=PACKAGE_DIRECTORIES,
diff --git a/test/core/client_config/lb_policies_test.c b/test/core/client_config/lb_policies_test.c
index 190bed0b41..9da4a4eec7 100644
--- a/test/core/client_config/lb_policies_test.c
+++ b/test/core/client_config/lb_policies_test.c
@@ -38,18 +38,19 @@
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
-#include <grpc/support/time.h>
#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/channel/client_channel.h"
+#include "src/core/client_config/lb_policies/round_robin.h"
#include "src/core/client_config/lb_policy_registry.h"
-#include "src/core/surface/channel.h"
#include "src/core/support/string.h"
+#include "src/core/surface/channel.h"
#include "src/core/surface/server.h"
-#include "test/core/util/test_config.h"
-#include "test/core/util/port.h"
#include "test/core/end2end/cq_verifier.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
typedef struct servers_fixture {
size_t num_servers;
@@ -136,8 +137,9 @@ static void kill_server(const servers_fixture *f, size_t i) {
gpr_log(GPR_INFO, "KILLING SERVER %d", i);
GPR_ASSERT(f->servers[i] != NULL);
grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000));
- GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(10000), n_millis_time(5000),
- NULL).type == GRPC_OP_COMPLETE);
+ GPR_ASSERT(
+ grpc_completion_queue_pluck(f->cq, tag(10000), n_millis_time(5000), NULL)
+ .type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->servers[i]);
f->servers[i] = NULL;
}
@@ -203,8 +205,8 @@ static void teardown_servers(servers_fixture *f) {
if (f->servers[i] == NULL) continue;
grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000));
GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(10000),
- n_millis_time(5000),
- NULL).type == GRPC_OP_COMPLETE);
+ n_millis_time(5000), NULL)
+ .type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->servers[i]);
}
grpc_completion_queue_shutdown(f->cq);
@@ -225,8 +227,8 @@ static void teardown_servers(servers_fixture *f) {
}
/** Returns connection sequence (server indices), which must be freed */
-int *perform_request(servers_fixture *f, grpc_channel *client,
- request_data *rdata, const test_spec *spec) {
+static int *perform_request(servers_fixture *f, grpc_channel *client,
+ request_data *rdata, const test_spec *spec) {
grpc_call *c;
int s_idx;
int *s_valid;
@@ -242,8 +244,6 @@ int *perform_request(servers_fixture *f, grpc_channel *client,
s_valid = gpr_malloc(sizeof(int) * f->num_servers);
connection_sequence = gpr_malloc(sizeof(int) * spec->num_iters);
- /* Send a trivial request. */
-
for (iter_num = 0; iter_num < spec->num_iters; iter_num++) {
cq_verifier *cqv = cq_verifier_create(f->cq);
rdata->details = NULL;
@@ -304,8 +304,8 @@ int *perform_request(servers_fixture *f, grpc_channel *client,
s_idx = -1;
while ((ev = grpc_completion_queue_next(
- f->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), NULL)).type !=
- GRPC_QUEUE_TIMEOUT) {
+ f->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), NULL))
+ .type != GRPC_QUEUE_TIMEOUT) {
GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
read_tag = ((int)(gpr_intptr)ev.tag);
gpr_log(GPR_DEBUG, "EVENT: success:%d, type:%d, tag:%d iter:%d",
@@ -324,8 +324,6 @@ int *perform_request(servers_fixture *f, grpc_channel *client,
}
}
- gpr_log(GPR_DEBUG, "s_idx=%d", s_idx);
-
if (s_idx >= 0) {
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -371,7 +369,7 @@ int *perform_request(servers_fixture *f, grpc_channel *client,
&rdata->call_details[s_idx],
&f->request_metadata_recv[s_idx], f->cq,
f->cq, tag(1000 + (int)s_idx)));
- } else {
+ } else { /* no response from server */
grpc_call_cancel(c, NULL);
if (!completed_client) {
cq_expect_completion(cqv, tag(1), 1);
@@ -397,6 +395,42 @@ int *perform_request(servers_fixture *f, grpc_channel *client,
return connection_sequence;
}
+static grpc_call **perform_multirequest(servers_fixture *f,
+ grpc_channel *client,
+ size_t concurrent_calls) {
+ grpc_call **calls;
+ grpc_op ops[6];
+ grpc_op *op;
+ size_t i;
+
+ calls = gpr_malloc(sizeof(grpc_call *) * concurrent_calls);
+ for (i = 0; i < f->num_servers; i++) {
+ kill_server(f, i);
+ }
+
+ op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+ op->flags = 0;
+ op->reserved = NULL;
+
+ for (i = 0; i < concurrent_calls; i++) {
+ calls[i] = grpc_channel_create_call(
+ client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq, "/foo",
+ "foo.test.google.fr", gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+ GPR_ASSERT(calls[i]);
+ GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(calls[i], ops,
+ (size_t)(op - ops), tag(1),
+ NULL));
+ }
+
+ return calls;
+}
+
static void assert_channel_connectivity(
grpc_channel *ch, size_t num_accepted_conn_states,
grpc_connectivity_state accepted_conn_state, ...) {
@@ -487,8 +521,110 @@ void run_spec(const test_spec *spec) {
gpr_free(actual_connection_sequence);
gpr_free(rdata.call_details);
+ grpc_channel_destroy(client); /* calls the LB's shutdown func */
+ teardown_servers(f);
+}
+
+static grpc_channel *create_client(const servers_fixture *f) {
+ grpc_channel *client;
+ char *client_hostport;
+ char *servers_hostports_str;
+ grpc_arg arg;
+ grpc_channel_args args;
+
+ servers_hostports_str = gpr_strjoin_sep((const char **)f->servers_hostports,
+ f->num_servers, ",", NULL);
+ gpr_asprintf(&client_hostport, "ipv4:%s?lb_policy=round_robin",
+ servers_hostports_str);
+
+ arg.type = GRPC_ARG_INTEGER;
+ arg.key = "grpc.testing.fixed_reconnect_backoff";
+ arg.value.integer = 100;
+ args.num_args = 1;
+ args.args = &arg;
+
+ client = grpc_insecure_channel_create(client_hostport, &args, NULL);
+ gpr_free(client_hostport);
+ gpr_free(servers_hostports_str);
+
+ return client;
+}
+
+static void test_ping() {
+ grpc_channel *client;
+ request_data rdata;
+ servers_fixture *f;
+ cq_verifier *cqv;
+ grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
+ const size_t num_servers = 1;
+ int i;
+
+ rdata.call_details = gpr_malloc(sizeof(grpc_call_details) * num_servers);
+ f = setup_servers("127.0.0.1", &rdata, num_servers);
+ cqv = cq_verifier_create(f->cq);
+
+ client = create_client(f);
+
+ grpc_channel_ping(client, f->cq, tag(0), NULL);
+ cq_expect_completion(cqv, tag(0), 0);
+
+ /* check that we're still in idle, and start connecting */
+ GPR_ASSERT(grpc_channel_check_connectivity_state(client, 1) ==
+ GRPC_CHANNEL_IDLE);
+ /* we'll go through some set of transitions (some might be missed), until
+ READY is reached */
+ while (state != GRPC_CHANNEL_READY) {
+ grpc_channel_watch_connectivity_state(
+ client, state, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f->cq, tag(99));
+ cq_expect_completion(cqv, tag(99), 1);
+ cq_verify(cqv);
+ state = grpc_channel_check_connectivity_state(client, 0);
+ GPR_ASSERT(state == GRPC_CHANNEL_READY ||
+ state == GRPC_CHANNEL_CONNECTING ||
+ state == GRPC_CHANNEL_TRANSIENT_FAILURE);
+ }
+
+ for (i = 1; i <= 5; i++) {
+ grpc_channel_ping(client, f->cq, tag(i), NULL);
+ cq_expect_completion(cqv, tag(i), 1);
+ cq_verify(cqv);
+ }
+ gpr_free(rdata.call_details);
+
grpc_channel_destroy(client);
teardown_servers(f);
+
+ cq_verifier_destroy(cqv);
+}
+
+static void test_pending_calls(size_t concurrent_calls) {
+ size_t i;
+ grpc_call **calls;
+ grpc_channel *client;
+ request_data rdata;
+ servers_fixture *f;
+ test_spec *spec = test_spec_create(0, 4);
+ rdata.call_details =
+ gpr_malloc(sizeof(grpc_call_details) * spec->num_servers);
+ f = setup_servers("127.0.0.1", &rdata, spec->num_servers);
+
+ client = create_client(f);
+ calls = perform_multirequest(f, client, concurrent_calls);
+ grpc_call_cancel(
+ calls[0],
+ NULL); /* exercise the cancel pick path whilst there are pending picks */
+
+ gpr_free(rdata.call_details);
+
+ grpc_channel_destroy(client); /* calls the LB's shutdown func */
+ /* destroy the calls after the channel so that they are still around for the
+ * LB's shutdown func to process */
+ for (i = 0; i < concurrent_calls; i++) {
+ grpc_call_destroy(calls[i]);
+ }
+ gpr_free(calls);
+ teardown_servers(f);
+ test_spec_destroy(spec);
}
static void print_failed_expectations(const int *expected_connection_sequence,
@@ -715,13 +851,14 @@ int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
+ grpc_lb_round_robin_trace = 1;
GPR_ASSERT(grpc_lb_policy_create("this-lb-policy-does-not-exist", NULL) ==
NULL);
GPR_ASSERT(grpc_lb_policy_create(NULL, NULL) == NULL);
- /* everything is fine, all servers stay up the whole time and life's peachy */
spec = test_spec_create(NUM_ITERS, NUM_SERVERS);
+ /* everything is fine, all servers stay up the whole time and life's peachy */
spec->verifier = verify_vanilla_round_robin;
spec->description = "test_all_server_up";
run_spec(spec);
@@ -735,7 +872,8 @@ int main(int argc, char **argv) {
}
run_spec(spec);
- /* at the start of the 2nd iteration, kill all but the first and last servers.
+ /* at the start of the 2nd iteration, kill all but the first and last
+ * servers.
* This should knock down the server bound to be selected next */
test_spec_reset(spec);
spec->verifier = verify_vanishing_floor_round_robin;
@@ -764,9 +902,11 @@ int main(int argc, char **argv) {
spec->revive_at[3][i] = 1;
}
run_spec(spec);
-
test_spec_destroy(spec);
+ test_pending_calls(4);
+ test_ping();
+
grpc_shutdown();
return 0;
}
diff --git a/test/core/httpcli/httpcli_test.c b/test/core/httpcli/httpcli_test.c
index d47774251a..fc51cb0101 100644
--- a/test/core/httpcli/httpcli_test.c
+++ b/test/core/httpcli/httpcli_test.c
@@ -142,19 +142,26 @@ int main(int argc, char **argv) {
char *me = argv[0];
char *lslash = strrchr(me, '/');
char *args[4];
- char root[1024];
int port = grpc_pick_unused_port_or_die();
- /* figure out where we are */
- if (lslash) {
- memcpy(root, me, (size_t)(lslash - me));
- root[lslash - me] = 0;
+ GPR_ASSERT(argc <= 2);
+ if (argc == 2) {
+ args[0] = gpr_strdup(argv[1]);
} else {
- strcpy(root, ".");
+ /* figure out where we are */
+ char *root;
+ if (lslash) {
+ root = gpr_malloc(lslash - me + 1);
+ memcpy(root, me, (size_t)(lslash - me));
+ root[lslash - me] = 0;
+ } else {
+ root = strdup(".");
+ }
+ gpr_asprintf(&args[0], "%s/../../test/core/httpcli/test_server.py", root);
+ gpr_free(root);
}
/* start the server */
- gpr_asprintf(&args[0], "%s/../../test/core/httpcli/test_server.py", root);
args[1] = "--port";
gpr_asprintf(&args[2], "%d", port);
server = gpr_subprocess_create(3, (const char **)args);
diff --git a/test/core/httpcli/httpscli_test.c b/test/core/httpcli/httpscli_test.c
index b1c1913cae..4cfa9e59b0 100644
--- a/test/core/httpcli/httpscli_test.c
+++ b/test/core/httpcli/httpscli_test.c
@@ -144,19 +144,26 @@ int main(int argc, char **argv) {
char *me = argv[0];
char *lslash = strrchr(me, '/');
char *args[5];
- char root[1024];
int port = grpc_pick_unused_port_or_die();
- /* figure out where we are */
- if (lslash) {
- memcpy(root, me, (size_t)(lslash - me));
- root[lslash - me] = 0;
+ GPR_ASSERT(argc <= 2);
+ if (argc == 2) {
+ args[0] = gpr_strdup(argv[1]);
} else {
- strcpy(root, ".");
+ /* figure out where we are */
+ char *root;
+ if (lslash) {
+ root = gpr_malloc(lslash - me + 1);
+ memcpy(root, me, (size_t)(lslash - me));
+ root[lslash - me] = 0;
+ } else {
+ strcpy(root, ".");
+ }
+ gpr_asprintf(&args[0], "%s/../../test/core/httpcli/test_server.py", root);
+ gpr_free(root);
}
/* start the server */
- gpr_asprintf(&args[0], "%s/../../test/core/httpcli/test_server.py", root);
args[1] = "--port";
gpr_asprintf(&args[2], "%d", port);
args[3] = "--ssl";
diff --git a/tools/run_tests/run_lcov.sh b/tools/run_tests/run_lcov.sh
index ec97ebf0a5..796a0b5ceb 100755
--- a/tools/run_tests/run_lcov.sh
+++ b/tools/run_tests/run_lcov.sh
@@ -33,7 +33,7 @@ set -ex
out=$(readlink -f ${1:-coverage})
root=$(readlink -f $(dirname $0)/../..)
-shift
+shift || true
tmp=$(mktemp)
cd $root
tools/run_tests/run_tests.py -c gcov -l c c++ $@ || true