aboutsummaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
authorGravatar Julien Boeuf <jboeuf@google.com>2016-09-23 10:42:10 -0700
committerGravatar Julien Boeuf <jboeuf@google.com>2016-09-23 10:42:10 -0700
commit5fc96200011c01f7753803b0004281ba5259de3f (patch)
tree7fe08200ac7b22aee23c0867bbb61714e7e20d34 /test
parente26ab6c5610b9cc4878f6db77700b918272dfc80 (diff)
parent942c264861dedd8020fc18d65933e8f4f57e3e46 (diff)
Merge branch 'master' of github.com:grpc/grpc into remove_call_creds_from_channel_creds
Diffstat (limited to 'test')
-rw-r--r--test/core/end2end/fixtures/h2_http_proxy.c129
-rw-r--r--test/core/end2end/fixtures/http_proxy.c481
-rw-r--r--test/core/end2end/fixtures/http_proxy.h41
-rwxr-xr-xtest/core/end2end/gen_build_yaml.py1
-rw-r--r--test/core/end2end/tests/no_logging.c17
-rw-r--r--test/core/http/parser_test.c10
-rw-r--r--test/core/http/request_fuzzer.c2
-rw-r--r--test/core/http/response_fuzzer.c2
-rw-r--r--test/cpp/qps/client.h5
-rw-r--r--test/cpp/util/grpc_tool.cc115
-rw-r--r--test/cpp/util/grpc_tool_test.cc139
-rw-r--r--test/cpp/util/service_describer.cc108
-rw-r--r--test/cpp/util/service_describer.h57
-rw-r--r--test/distrib/csharp/DistribTest/Properties/AssemblyInfo.cs35
-rwxr-xr-xtest/distrib/php/run_distrib_test.sh5
15 files changed, 1113 insertions, 34 deletions
diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c
new file mode 100644
index 0000000000..a675a11f66
--- /dev/null
+++ b/test/core/end2end/fixtures/h2_http_proxy.c
@@ -0,0 +1,129 @@
+/*
+ *
+ * Copyright 2016, 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/core/end2end/end2end_tests.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+#include "src/core/ext/client_config/client_channel.h"
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
+#include "test/core/end2end/fixtures/http_proxy.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+typedef struct fullstack_fixture_data {
+ char *server_addr;
+ grpc_end2end_http_proxy *proxy;
+} fullstack_fixture_data;
+
+static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
+ grpc_channel_args *client_args, grpc_channel_args *server_args) {
+ grpc_end2end_test_fixture f;
+ memset(&f, 0, sizeof(f));
+
+ fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data));
+ const int server_port = grpc_pick_unused_port_or_die();
+ gpr_join_host_port(&ffd->server_addr, "localhost", server_port);
+ ffd->proxy = grpc_end2end_http_proxy_create();
+
+ f.fixture_data = ffd;
+ f.cq = grpc_completion_queue_create(NULL);
+
+ return f;
+}
+
+void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
+ grpc_channel_args *client_args) {
+ fullstack_fixture_data *ffd = f->fixture_data;
+ char *proxy_uri;
+ gpr_asprintf(&proxy_uri, "http://%s",
+ grpc_end2end_http_proxy_get_proxy_name(ffd->proxy));
+ gpr_setenv("http_proxy", proxy_uri);
+ gpr_free(proxy_uri);
+ f->client = grpc_insecure_channel_create(ffd->server_addr, client_args, NULL);
+ GPR_ASSERT(f->client);
+}
+
+void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
+ grpc_channel_args *server_args) {
+ fullstack_fixture_data *ffd = f->fixture_data;
+ if (f->server) {
+ grpc_server_destroy(f->server);
+ }
+ f->server = grpc_server_create(server_args, NULL);
+ grpc_server_register_completion_queue(f->server, f->cq, NULL);
+ GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->server_addr));
+ grpc_server_start(f->server);
+}
+
+void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
+ fullstack_fixture_data *ffd = f->fixture_data;
+ gpr_free(ffd->server_addr);
+ grpc_end2end_http_proxy_destroy(ffd->proxy);
+ gpr_free(ffd);
+}
+
+/* All test configurations */
+static grpc_end2end_test_config configs[] = {
+ {"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
+ chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
+ chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
+};
+
+int main(int argc, char **argv) {
+ size_t i;
+
+ grpc_test_init(argc, argv);
+ grpc_end2end_tests_pre_init();
+ grpc_init();
+
+ for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
+ grpc_end2end_tests(argc, argv, configs[i]);
+ }
+
+ grpc_shutdown();
+
+ return 0;
+}
diff --git a/test/core/end2end/fixtures/http_proxy.c b/test/core/end2end/fixtures/http_proxy.c
new file mode 100644
index 0000000000..22533b9694
--- /dev/null
+++ b/test/core/end2end/fixtures/http_proxy.c
@@ -0,0 +1,481 @@
+/*
+ *
+ * Copyright 2016, 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/core/end2end/fixtures/http_proxy.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/http/parser.h"
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/pollset_set.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "test/core/util/port.h"
+
+struct grpc_end2end_http_proxy {
+ char* proxy_name;
+ gpr_thd_id thd;
+ grpc_tcp_server* server;
+ grpc_channel_args* channel_args;
+ gpr_mu* mu;
+ grpc_pollset* pollset;
+ gpr_atm shutdown;
+};
+
+//
+// Connection handling
+//
+
+typedef struct proxy_connection {
+ grpc_endpoint* client_endpoint;
+ grpc_endpoint* server_endpoint;
+
+ gpr_refcount refcount;
+
+ grpc_pollset_set* pollset_set;
+
+ grpc_closure on_read_request_done;
+ grpc_closure on_server_connect_done;
+ grpc_closure on_write_response_done;
+ grpc_closure on_client_read_done;
+ grpc_closure on_client_write_done;
+ grpc_closure on_server_read_done;
+ grpc_closure on_server_write_done;
+
+ gpr_slice_buffer client_read_buffer;
+ gpr_slice_buffer client_deferred_write_buffer;
+ gpr_slice_buffer client_write_buffer;
+ gpr_slice_buffer server_read_buffer;
+ gpr_slice_buffer server_deferred_write_buffer;
+ gpr_slice_buffer server_write_buffer;
+
+ grpc_http_parser http_parser;
+ grpc_http_request http_request;
+} proxy_connection;
+
+// Helper function to destroy the proxy connection.
+static void proxy_connection_unref(grpc_exec_ctx* exec_ctx,
+ proxy_connection* conn) {
+ if (gpr_unref(&conn->refcount)) {
+ grpc_endpoint_destroy(exec_ctx, conn->client_endpoint);
+ if (conn->server_endpoint != NULL)
+ grpc_endpoint_destroy(exec_ctx, conn->server_endpoint);
+ grpc_pollset_set_destroy(conn->pollset_set);
+ gpr_slice_buffer_destroy(&conn->client_read_buffer);
+ gpr_slice_buffer_destroy(&conn->client_deferred_write_buffer);
+ gpr_slice_buffer_destroy(&conn->client_write_buffer);
+ gpr_slice_buffer_destroy(&conn->server_read_buffer);
+ gpr_slice_buffer_destroy(&conn->server_deferred_write_buffer);
+ gpr_slice_buffer_destroy(&conn->server_write_buffer);
+ grpc_http_parser_destroy(&conn->http_parser);
+ grpc_http_request_destroy(&conn->http_request);
+ gpr_free(conn);
+ }
+}
+
+// Helper function to shut down the proxy connection.
+// Does NOT take ownership of a reference to error.
+static void proxy_connection_failed(grpc_exec_ctx* exec_ctx,
+ proxy_connection* conn, bool is_client,
+ const char* prefix, grpc_error* error) {
+ const char* msg = grpc_error_string(error);
+ gpr_log(GPR_INFO, "%s: %s", prefix, msg);
+ grpc_error_free_string(msg);
+ grpc_endpoint_shutdown(exec_ctx, conn->client_endpoint);
+ if (conn->server_endpoint != NULL)
+ grpc_endpoint_shutdown(exec_ctx, conn->server_endpoint);
+ proxy_connection_unref(exec_ctx, conn);
+}
+
+// Callback for writing proxy data to the client.
+static void on_client_write_done(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_error* error) {
+ proxy_connection* conn = arg;
+ if (error != GRPC_ERROR_NONE) {
+ proxy_connection_failed(exec_ctx, conn, true /* is_client */,
+ "HTTP proxy client write", error);
+ return;
+ }
+ // Clear write buffer (the data we just wrote).
+ gpr_slice_buffer_reset_and_unref(&conn->client_write_buffer);
+ // If more data was read from the server since we started this write,
+ // write that data now.
+ if (conn->client_deferred_write_buffer.length > 0) {
+ gpr_slice_buffer_move_into(&conn->client_deferred_write_buffer,
+ &conn->client_write_buffer);
+ grpc_endpoint_write(exec_ctx, conn->client_endpoint,
+ &conn->client_write_buffer,
+ &conn->on_client_write_done);
+ } else {
+ // No more writes. Unref the connection.
+ proxy_connection_unref(exec_ctx, conn);
+ }
+}
+
+// Callback for writing proxy data to the backend server.
+static void on_server_write_done(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_error* error) {
+ proxy_connection* conn = arg;
+ if (error != GRPC_ERROR_NONE) {
+ proxy_connection_failed(exec_ctx, conn, false /* is_client */,
+ "HTTP proxy server write", error);
+ return;
+ }
+ // Clear write buffer (the data we just wrote).
+ gpr_slice_buffer_reset_and_unref(&conn->server_write_buffer);
+ // If more data was read from the client since we started this write,
+ // write that data now.
+ if (conn->server_deferred_write_buffer.length > 0) {
+ gpr_slice_buffer_move_into(&conn->server_deferred_write_buffer,
+ &conn->server_write_buffer);
+ grpc_endpoint_write(exec_ctx, conn->server_endpoint,
+ &conn->server_write_buffer,
+ &conn->on_server_write_done);
+ } else {
+ // No more writes. Unref the connection.
+ proxy_connection_unref(exec_ctx, conn);
+ }
+}
+
+// Callback for reading data from the client, which will be proxied to
+// the backend server.
+static void on_client_read_done(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_error* error) {
+ proxy_connection* conn = arg;
+ if (error != GRPC_ERROR_NONE) {
+ proxy_connection_failed(exec_ctx, conn, true /* is_client */,
+ "HTTP proxy client read", error);
+ return;
+ }
+ // If there is already a pending write (i.e., server_write_buffer is
+ // not empty), then move the read data into server_deferred_write_buffer,
+ // and the next write will be requested in on_server_write_done(), when
+ // the current write is finished.
+ //
+ // Otherwise, move the read data into the write buffer and write it.
+ if (conn->server_write_buffer.length > 0) {
+ gpr_slice_buffer_move_into(&conn->client_read_buffer,
+ &conn->server_deferred_write_buffer);
+ } else {
+ gpr_slice_buffer_move_into(&conn->client_read_buffer,
+ &conn->server_write_buffer);
+ gpr_ref(&conn->refcount);
+ grpc_endpoint_write(exec_ctx, conn->server_endpoint,
+ &conn->server_write_buffer,
+ &conn->on_server_write_done);
+ }
+ // Read more data.
+ grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer,
+ &conn->on_client_read_done);
+}
+
+// Callback for reading data from the backend server, which will be
+// proxied to the client.
+static void on_server_read_done(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_error* error) {
+ proxy_connection* conn = arg;
+ if (error != GRPC_ERROR_NONE) {
+ proxy_connection_failed(exec_ctx, conn, false /* is_client */,
+ "HTTP proxy server read", error);
+ return;
+ }
+ // If there is already a pending write (i.e., client_write_buffer is
+ // not empty), then move the read data into client_deferred_write_buffer,
+ // and the next write will be requested in on_client_write_done(), when
+ // the current write is finished.
+ //
+ // Otherwise, move the read data into the write buffer and write it.
+ if (conn->client_write_buffer.length > 0) {
+ gpr_slice_buffer_move_into(&conn->server_read_buffer,
+ &conn->client_deferred_write_buffer);
+ } else {
+ gpr_slice_buffer_move_into(&conn->server_read_buffer,
+ &conn->client_write_buffer);
+ gpr_ref(&conn->refcount);
+ grpc_endpoint_write(exec_ctx, conn->client_endpoint,
+ &conn->client_write_buffer,
+ &conn->on_client_write_done);
+ }
+ // Read more data.
+ grpc_endpoint_read(exec_ctx, conn->server_endpoint, &conn->server_read_buffer,
+ &conn->on_server_read_done);
+}
+
+// Callback to write the HTTP response for the CONNECT request.
+static void on_write_response_done(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_error* error) {
+ proxy_connection* conn = arg;
+ if (error != GRPC_ERROR_NONE) {
+ proxy_connection_failed(exec_ctx, conn, true /* is_client */,
+ "HTTP proxy write response", error);
+ return;
+ }
+ // Clear write buffer.
+ gpr_slice_buffer_reset_and_unref(&conn->client_write_buffer);
+ // Start reading from both client and server. One of the read
+ // requests inherits our ref to conn, but we need to take a new ref
+ // for the other one.
+ gpr_ref(&conn->refcount);
+ grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer,
+ &conn->on_client_read_done);
+ grpc_endpoint_read(exec_ctx, conn->server_endpoint, &conn->server_read_buffer,
+ &conn->on_server_read_done);
+}
+
+// Callback to connect to the backend server specified by the HTTP
+// CONNECT request.
+static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_error* error) {
+ proxy_connection* conn = arg;
+ if (error != GRPC_ERROR_NONE) {
+ // TODO(roth): Technically, in this case, we should handle the error
+ // by returning an HTTP response to the client indicating that the
+ // connection failed. However, for the purposes of this test code,
+ // it's fine to pretend this is a client-side error, which will
+ // cause the client connection to be dropped.
+ proxy_connection_failed(exec_ctx, conn, true /* is_client */,
+ "HTTP proxy server connect", error);
+ return;
+ }
+ // We've established a connection, so send back a 200 response code to
+ // the client.
+ // The write callback inherits our reference to conn.
+ gpr_slice slice =
+ gpr_slice_from_copied_string("HTTP/1.0 200 connected\r\n\r\n");
+ gpr_slice_buffer_add(&conn->client_write_buffer, slice);
+ grpc_endpoint_write(exec_ctx, conn->client_endpoint,
+ &conn->client_write_buffer,
+ &conn->on_write_response_done);
+}
+
+// Callback to read the HTTP CONNECT request.
+// TODO(roth): Technically, for any of the failure modes handled by this
+// function, we should handle the error by returning an HTTP response to
+// the client indicating that the request failed. However, for the purposes
+// of this test code, it's fine to pretend this is a client-side error,
+// which will cause the client connection to be dropped.
+static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_error* error) {
+ proxy_connection* conn = arg;
+ if (error != GRPC_ERROR_NONE) {
+ proxy_connection_failed(exec_ctx, conn, true /* is_client */,
+ "HTTP proxy read request", error);
+ return;
+ }
+ // Read request and feed it to the parser.
+ for (size_t i = 0; i < conn->client_read_buffer.count; ++i) {
+ if (GPR_SLICE_LENGTH(conn->client_read_buffer.slices[i]) > 0) {
+ error = grpc_http_parser_parse(&conn->http_parser,
+ conn->client_read_buffer.slices[i], NULL);
+ if (error != GRPC_ERROR_NONE) {
+ proxy_connection_failed(exec_ctx, conn, true /* is_client */,
+ "HTTP proxy request parse", error);
+ GRPC_ERROR_UNREF(error);
+ return;
+ }
+ }
+ }
+ gpr_slice_buffer_reset_and_unref(&conn->client_read_buffer);
+ // If we're not done reading the request, read more data.
+ if (conn->http_parser.state != GRPC_HTTP_BODY) {
+ grpc_endpoint_read(exec_ctx, conn->client_endpoint,
+ &conn->client_read_buffer, &conn->on_read_request_done);
+ return;
+ }
+ // Make sure we got a CONNECT request.
+ if (strcmp(conn->http_request.method, "CONNECT") != 0) {
+ char* msg;
+ gpr_asprintf(&msg, "HTTP proxy got request method %s",
+ conn->http_request.method);
+ error = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ proxy_connection_failed(exec_ctx, conn, true /* is_client */,
+ "HTTP proxy read request", error);
+ GRPC_ERROR_UNREF(error);
+ return;
+ }
+ // Resolve address.
+ grpc_resolved_addresses* resolved_addresses = NULL;
+ error = grpc_blocking_resolve_address(conn->http_request.path, "80",
+ &resolved_addresses);
+ if (error != GRPC_ERROR_NONE) {
+ proxy_connection_failed(exec_ctx, conn, true /* is_client */,
+ "HTTP proxy DNS lookup", error);
+ GRPC_ERROR_UNREF(error);
+ return;
+ }
+ GPR_ASSERT(resolved_addresses->naddrs >= 1);
+ // Connect to requested address.
+ // The connection callback inherits our reference to conn.
+ const gpr_timespec deadline = gpr_time_add(
+ gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(10, GPR_TIMESPAN));
+ grpc_tcp_client_connect(exec_ctx, &conn->on_server_connect_done,
+ &conn->server_endpoint, conn->pollset_set,
+ (struct sockaddr*)&resolved_addresses->addrs[0].addr,
+ resolved_addresses->addrs[0].len, deadline);
+ grpc_resolved_addresses_destroy(resolved_addresses);
+}
+
+static void on_accept(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_endpoint* endpoint, grpc_pollset* accepting_pollset,
+ grpc_tcp_server_acceptor* acceptor) {
+ grpc_end2end_http_proxy* proxy = arg;
+ // Instantiate proxy_connection.
+ proxy_connection* conn = gpr_malloc(sizeof(*conn));
+ memset(conn, 0, sizeof(*conn));
+ conn->client_endpoint = endpoint;
+ gpr_ref_init(&conn->refcount, 1);
+ conn->pollset_set = grpc_pollset_set_create();
+ grpc_pollset_set_add_pollset(exec_ctx, conn->pollset_set, proxy->pollset);
+ grpc_closure_init(&conn->on_read_request_done, on_read_request_done, conn);
+ grpc_closure_init(&conn->on_server_connect_done, on_server_connect_done,
+ conn);
+ grpc_closure_init(&conn->on_write_response_done, on_write_response_done,
+ conn);
+ grpc_closure_init(&conn->on_client_read_done, on_client_read_done, conn);
+ grpc_closure_init(&conn->on_client_write_done, on_client_write_done, conn);
+ grpc_closure_init(&conn->on_server_read_done, on_server_read_done, conn);
+ grpc_closure_init(&conn->on_server_write_done, on_server_write_done, conn);
+ gpr_slice_buffer_init(&conn->client_read_buffer);
+ gpr_slice_buffer_init(&conn->client_deferred_write_buffer);
+ gpr_slice_buffer_init(&conn->client_write_buffer);
+ gpr_slice_buffer_init(&conn->server_read_buffer);
+ gpr_slice_buffer_init(&conn->server_deferred_write_buffer);
+ gpr_slice_buffer_init(&conn->server_write_buffer);
+ grpc_http_parser_init(&conn->http_parser, GRPC_HTTP_REQUEST,
+ &conn->http_request);
+ grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer,
+ &conn->on_read_request_done);
+}
+
+//
+// Proxy class
+//
+
+static void thread_main(void* arg) {
+ grpc_end2end_http_proxy* proxy = arg;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ do {
+ const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+ const gpr_timespec deadline =
+ gpr_time_add(now, gpr_time_from_seconds(1, GPR_TIMESPAN));
+ grpc_pollset_worker* worker = NULL;
+ gpr_mu_lock(proxy->mu);
+ GRPC_LOG_IF_ERROR(
+ "grpc_pollset_work",
+ grpc_pollset_work(&exec_ctx, proxy->pollset, &worker, now, deadline));
+ gpr_mu_unlock(proxy->mu);
+ grpc_exec_ctx_flush(&exec_ctx);
+ } while (!gpr_atm_acq_load(&proxy->shutdown));
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+grpc_end2end_http_proxy* grpc_end2end_http_proxy_create() {
+ grpc_end2end_http_proxy* proxy = gpr_malloc(sizeof(*proxy));
+ memset(proxy, 0, sizeof(*proxy));
+ // Construct proxy address.
+ const int proxy_port = grpc_pick_unused_port_or_die();
+ gpr_join_host_port(&proxy->proxy_name, "localhost", proxy_port);
+ gpr_log(GPR_INFO, "Proxy address: %s", proxy->proxy_name);
+ // Create TCP server.
+ proxy->channel_args = grpc_channel_args_copy(NULL);
+ grpc_error* error =
+ grpc_tcp_server_create(NULL, proxy->channel_args, &proxy->server);
+ GPR_ASSERT(error == GRPC_ERROR_NONE);
+ // Bind to port.
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ grpc_sockaddr_set_port((struct sockaddr*)&addr, proxy_port);
+ int port;
+ error = grpc_tcp_server_add_port(proxy->server, (struct sockaddr*)&addr,
+ sizeof(addr), &port);
+ GPR_ASSERT(error == GRPC_ERROR_NONE);
+ GPR_ASSERT(port == proxy_port);
+ // Start server.
+ proxy->pollset = gpr_malloc(grpc_pollset_size());
+ grpc_pollset_init(proxy->pollset, &proxy->mu);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_tcp_server_start(&exec_ctx, proxy->server, &proxy->pollset, 1, on_accept,
+ proxy);
+ grpc_exec_ctx_finish(&exec_ctx);
+ // Start proxy thread.
+ gpr_thd_options opt = gpr_thd_options_default();
+ gpr_thd_options_set_joinable(&opt);
+ GPR_ASSERT(gpr_thd_new(&proxy->thd, thread_main, proxy, &opt));
+ return proxy;
+}
+
+static void destroy_pollset(grpc_exec_ctx* exec_ctx, void* arg,
+ grpc_error* error) {
+ grpc_pollset* pollset = arg;
+ grpc_pollset_destroy(pollset);
+ gpr_free(pollset);
+}
+
+void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) {
+ gpr_atm_rel_store(&proxy->shutdown, 1); // Signal proxy thread to shutdown.
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ gpr_thd_join(proxy->thd);
+ grpc_tcp_server_shutdown_listeners(&exec_ctx, proxy->server);
+ grpc_tcp_server_unref(&exec_ctx, proxy->server);
+ gpr_free(proxy->proxy_name);
+ grpc_channel_args_destroy(proxy->channel_args);
+ grpc_closure destroyed;
+ grpc_closure_init(&destroyed, destroy_pollset, proxy->pollset);
+ grpc_pollset_shutdown(&exec_ctx, proxy->pollset, &destroyed);
+ gpr_free(proxy);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+const char* grpc_end2end_http_proxy_get_proxy_name(
+ grpc_end2end_http_proxy* proxy) {
+ return proxy->proxy_name;
+}
diff --git a/test/core/end2end/fixtures/http_proxy.h b/test/core/end2end/fixtures/http_proxy.h
new file mode 100644
index 0000000000..cd47b432af
--- /dev/null
+++ b/test/core/end2end/fixtures/http_proxy.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2016, 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.
+ *
+ */
+
+typedef struct grpc_end2end_http_proxy grpc_end2end_http_proxy;
+
+grpc_end2end_http_proxy* grpc_end2end_http_proxy_create();
+
+void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy);
+
+const char* grpc_end2end_http_proxy_get_proxy_name(
+ grpc_end2end_http_proxy* proxy);
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index fe0f7baf2c..78b37efd37 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -60,6 +60,7 @@ END2END_FIXTURES = {
'h2_full+pipe': default_unsecure_fixture_options._replace(
platforms=['linux']),
'h2_full+trace': default_unsecure_fixture_options._replace(tracing=True),
+ 'h2_http_proxy': default_unsecure_fixture_options._replace(ci_mac=False),
'h2_oauth2': default_secure_fixture_options._replace(ci_mac=False),
'h2_proxy': default_unsecure_fixture_options._replace(includes_proxy=True,
ci_mac=False),
diff --git a/test/core/end2end/tests/no_logging.c b/test/core/end2end/tests/no_logging.c
index 3c40e5dbac..430bfdc797 100644
--- a/test/core/end2end/tests/no_logging.c
+++ b/test/core/end2end/tests/no_logging.c
@@ -68,6 +68,13 @@ static void test_no_error_log(gpr_log_func_args *args) {
}
}
+static gpr_atm g_log_func = (gpr_atm)gpr_default_log;
+
+static void log_dispatcher_func(gpr_log_func_args *args) {
+ gpr_log_func log_func = (gpr_log_func)gpr_atm_no_barrier_load(&g_log_func);
+ log_func(args);
+}
+
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char *test_name,
grpc_channel_args *client_args,
@@ -263,12 +270,12 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
static void test_no_error_logging_in_entire_process(
grpc_end2end_test_config config) {
int i;
- gpr_set_log_function(test_no_error_log);
+ gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)test_no_error_log);
for (i = 0; i < 10; i++) {
test_invoke_simple_request(config);
}
test_invoke_10_simple_requests(config);
- gpr_set_log_function(gpr_default_log);
+ gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)gpr_default_log);
}
static void test_no_logging_in_one_request(grpc_end2end_test_config config) {
@@ -278,16 +285,18 @@ static void test_no_logging_in_one_request(grpc_end2end_test_config config) {
for (i = 0; i < 10; i++) {
simple_request_body(f);
}
- gpr_set_log_function(test_no_log);
+ gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)test_no_log);
simple_request_body(f);
- gpr_set_log_function(gpr_default_log);
+ gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)gpr_default_log);
end_test(&f);
config.tear_down_data(&f);
}
void no_logging(grpc_end2end_test_config config) {
+ gpr_set_log_function(log_dispatcher_func);
test_no_logging_in_one_request(config);
test_no_error_logging_in_entire_process(config);
+ gpr_set_log_function(gpr_default_log);
}
void no_logging_pre_init(void) {}
diff --git a/test/core/http/parser_test.c b/test/core/http/parser_test.c
index d645d2879c..2fc354d9ee 100644
--- a/test/core/http/parser_test.c
+++ b/test/core/http/parser_test.c
@@ -62,7 +62,8 @@ static void test_request_succeeds(grpc_slice_split_mode split_mode,
grpc_http_parser_init(&parser, GRPC_HTTP_REQUEST, &request);
for (i = 0; i < num_slices; i++) {
- GPR_ASSERT(grpc_http_parser_parse(&parser, slices[i]) == GRPC_ERROR_NONE);
+ GPR_ASSERT(grpc_http_parser_parse(&parser, slices[i], NULL) ==
+ GRPC_ERROR_NONE);
gpr_slice_unref(slices[i]);
}
GPR_ASSERT(grpc_http_parser_eof(&parser) == GRPC_ERROR_NONE);
@@ -118,7 +119,8 @@ static void test_succeeds(grpc_slice_split_mode split_mode, char *response_text,
grpc_http_parser_init(&parser, GRPC_HTTP_RESPONSE, &response);
for (i = 0; i < num_slices; i++) {
- GPR_ASSERT(grpc_http_parser_parse(&parser, slices[i]) == GRPC_ERROR_NONE);
+ GPR_ASSERT(grpc_http_parser_parse(&parser, slices[i], NULL) ==
+ GRPC_ERROR_NONE);
gpr_slice_unref(slices[i]);
}
GPR_ASSERT(grpc_http_parser_eof(&parser) == GRPC_ERROR_NONE);
@@ -171,7 +173,7 @@ static void test_fails(grpc_slice_split_mode split_mode, char *response_text) {
for (i = 0; i < num_slices; i++) {
if (GRPC_ERROR_NONE == error) {
- error = grpc_http_parser_parse(&parser, slices[i]);
+ error = grpc_http_parser_parse(&parser, slices[i], NULL);
}
gpr_slice_unref(slices[i]);
}
@@ -204,7 +206,7 @@ static void test_request_fails(grpc_slice_split_mode split_mode,
for (i = 0; i < num_slices; i++) {
if (error == GRPC_ERROR_NONE) {
- error = grpc_http_parser_parse(&parser, slices[i]);
+ error = grpc_http_parser_parse(&parser, slices[i], NULL);
}
gpr_slice_unref(slices[i]);
}
diff --git a/test/core/http/request_fuzzer.c b/test/core/http/request_fuzzer.c
index 5941401867..bb6cb92c0c 100644
--- a/test/core/http/request_fuzzer.c
+++ b/test/core/http/request_fuzzer.c
@@ -48,7 +48,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
memset(&request, 0, sizeof(request));
grpc_http_parser_init(&parser, GRPC_HTTP_REQUEST, &request);
gpr_slice slice = gpr_slice_from_copied_buffer((const char *)data, size);
- GRPC_ERROR_UNREF(grpc_http_parser_parse(&parser, slice));
+ GRPC_ERROR_UNREF(grpc_http_parser_parse(&parser, slice, NULL));
GRPC_ERROR_UNREF(grpc_http_parser_eof(&parser));
gpr_slice_unref(slice);
grpc_http_parser_destroy(&parser);
diff --git a/test/core/http/response_fuzzer.c b/test/core/http/response_fuzzer.c
index acde7c80a4..4393840484 100644
--- a/test/core/http/response_fuzzer.c
+++ b/test/core/http/response_fuzzer.c
@@ -47,7 +47,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
memset(&response, 0, sizeof(response));
grpc_http_parser_init(&parser, GRPC_HTTP_RESPONSE, &response);
gpr_slice slice = gpr_slice_from_copied_buffer((const char *)data, size);
- GRPC_ERROR_UNREF(grpc_http_parser_parse(&parser, slice));
+ GRPC_ERROR_UNREF(grpc_http_parser_parse(&parser, slice, NULL));
GRPC_ERROR_UNREF(grpc_http_parser_eof(&parser));
gpr_slice_unref(slice);
grpc_http_parser_destroy(&parser);
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index c8809cbc5b..5fb87b2782 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -129,7 +129,10 @@ class HistogramEntry GRPC_FINAL {
class Client {
public:
- Client() : timer_(new UsageTimer), interarrival_timer_() {
+ Client()
+ : timer_(new UsageTimer),
+ interarrival_timer_(),
+ started_requests_(false) {
gpr_event_init(&start_requests_);
}
virtual ~Client() {}
diff --git a/test/cpp/util/grpc_tool.cc b/test/cpp/util/grpc_tool.cc
index 3458a423d8..8fb325cf76 100644
--- a/test/cpp/util/grpc_tool.cc
+++ b/test/cpp/util/grpc_tool.cc
@@ -51,8 +51,13 @@
#include "test/cpp/util/cli_call.h"
#include "test/cpp/util/proto_file_parser.h"
#include "test/cpp/util/proto_reflection_descriptor_database.h"
+#include "test/cpp/util/service_describer.h"
#include "test/cpp/util/test_config.h"
+namespace grpc {
+namespace testing {
+
+DEFINE_bool(l, false, "Use a long listing format");
DEFINE_bool(remotedb, true, "Use server types to parse and format messages");
DEFINE_string(metadata, "",
"Metadata to send to server, in the form of key1:val1:key2:val2");
@@ -62,8 +67,6 @@ DEFINE_bool(binary_input, false, "Input in binary format");
DEFINE_bool(binary_output, false, "Output in binary format");
DEFINE_string(infile, "", "Input file (default is stdin)");
-namespace grpc {
-namespace testing {
namespace {
class GrpcTool {
@@ -75,6 +78,8 @@ class GrpcTool {
GrpcToolOutputCallback callback);
bool CallMethod(int argc, const char** argv, const CliCredentials& cred,
GrpcToolOutputCallback callback);
+ bool ListServices(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
bool PrintType(int argc, const char** argv, const CliCredentials& cred,
GrpcToolOutputCallback callback);
// TODO(zyc): implement the following methods
@@ -165,8 +170,8 @@ struct Command {
const Command ops[] = {
{"help", BindWith5Args(&GrpcTool::Help), 0, INT_MAX},
- // {"ls", BindWith5Args(&GrpcTool::ListServices), 1, 3},
- // {"list", BindWith5Args(&GrpcTool::ListServices), 1, 3},
+ {"ls", BindWith5Args(&GrpcTool::ListServices), 1, 3},
+ {"list", BindWith5Args(&GrpcTool::ListServices), 1, 3},
{"call", BindWith5Args(&GrpcTool::CallMethod), 2, 3},
{"type", BindWith5Args(&GrpcTool::PrintType), 2, 2},
// {"parse", BindWith5Args(&GrpcTool::ParseMessage), 2, 3},
@@ -178,7 +183,7 @@ void Usage(const grpc::string& msg) {
fprintf(
stderr,
"%s\n"
- // " grpc_cli ls ... ; List services\n"
+ " grpc_cli ls ... ; List services\n"
" grpc_cli call ... ; Call method\n"
" grpc_cli type ... ; Print type\n"
// " grpc_cli parse ... ; Parse message\n"
@@ -257,6 +262,106 @@ bool GrpcTool::Help(int argc, const char** argv, const CliCredentials& cred,
return true;
}
+bool GrpcTool::ListServices(int argc, const char** argv,
+ const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ CommandUsage(
+ "List services\n"
+ " grpc_cli ls <address> [<service>[/<method>]]\n"
+ " <address> ; host:port\n"
+ " <service> ; Exported service name\n"
+ " <method> ; Method name\n"
+ " --l ; Use a long listing format\n"
+ " --outfile ; Output filename (defaults to stdout)\n" +
+ cred.GetCredentialUsage());
+
+ grpc::string server_address(argv[0]);
+ std::shared_ptr<grpc::Channel> channel =
+ grpc::CreateChannel(server_address, cred.GetCredentials());
+ grpc::ProtoReflectionDescriptorDatabase desc_db(channel);
+ grpc::protobuf::DescriptorPool desc_pool(&desc_db);
+
+ std::vector<grpc::string> service_list;
+ if (!desc_db.GetServices(&service_list)) {
+ return false;
+ }
+
+ // If no service is specified, dump the list of services.
+ grpc::string output;
+ if (argc < 2) {
+ // List all services, if --l is passed, then include full description,
+ // otherwise include a summarized list only.
+ if (FLAGS_l) {
+ output = DescribeServiceList(service_list, desc_pool);
+ } else {
+ for (auto it = service_list.begin(); it != service_list.end(); it++) {
+ auto const& service = *it;
+ output.append(service);
+ output.append("\n");
+ }
+ }
+ } else {
+ grpc::string service_name;
+ grpc::string method_name;
+ std::stringstream ss(argv[1]);
+
+ // Remove leading slashes.
+ while (ss.peek() == '/') {
+ ss.get();
+ }
+
+ // Parse service and method names. Support the following patterns:
+ // Service
+ // Service Method
+ // Service.Method
+ // Service/Method
+ if (argc == 3) {
+ std::getline(ss, service_name, '/');
+ method_name = argv[2];
+ } else {
+ if (std::getline(ss, service_name, '/')) {
+ std::getline(ss, method_name);
+ }
+ }
+
+ const grpc::protobuf::ServiceDescriptor* service =
+ desc_pool.FindServiceByName(service_name);
+ if (service != nullptr) {
+ if (method_name.empty()) {
+ output = FLAGS_l ? DescribeService(service) : SummarizeService(service);
+ } else {
+ method_name.insert(0, 1, '.');
+ method_name.insert(0, service_name);
+ const grpc::protobuf::MethodDescriptor* method =
+ desc_pool.FindMethodByName(method_name);
+ if (method != nullptr) {
+ output = FLAGS_l ? DescribeMethod(method) : SummarizeMethod(method);
+ } else {
+ fprintf(stderr, "Method %s not found in service %s.\n",
+ method_name.c_str(), service_name.c_str());
+ return false;
+ }
+ }
+ } else {
+ if (!method_name.empty()) {
+ fprintf(stderr, "Service %s not found.\n", service_name.c_str());
+ return false;
+ } else {
+ const grpc::protobuf::MethodDescriptor* method =
+ desc_pool.FindMethodByName(service_name);
+ if (method != nullptr) {
+ output = FLAGS_l ? DescribeMethod(method) : SummarizeMethod(method);
+ } else {
+ fprintf(stderr, "Service or method %s not found.\n",
+ service_name.c_str());
+ return false;
+ }
+ }
+ }
+ }
+ return callback(output);
+}
+
bool GrpcTool::PrintType(int argc, const char** argv,
const CliCredentials& cred,
GrpcToolOutputCallback callback) {
diff --git a/test/cpp/util/grpc_tool_test.cc b/test/cpp/util/grpc_tool_test.cc
index edb66b72d8..bad1579f11 100644
--- a/test/cpp/util/grpc_tool_test.cc
+++ b/test/cpp/util/grpc_tool_test.cc
@@ -35,6 +35,7 @@
#include <sstream>
+#include <gflags/gflags.h>
#include <grpc++/channel.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
@@ -55,8 +56,41 @@
using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse;
+#define USAGE_REGEX "( grpc_cli .+\n){2,10}"
+
+#define ECHO_TEST_SERVICE_SUMMARY \
+ "Echo\n" \
+ "RequestStream\n" \
+ "ResponseStream\n" \
+ "BidiStream\n" \
+ "Unimplemented\n"
+
+#define ECHO_TEST_SERVICE_DESCRIPTION \
+ "filename: src/proto/grpc/testing/echo.proto\n" \
+ "package: grpc.testing;\n" \
+ "service EchoTestService {\n" \
+ " rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
+ "{}\n" \
+ " rpc RequestStream(stream grpc.testing.EchoRequest) returns " \
+ "(grpc.testing.EchoResponse) {}\n" \
+ " rpc ResponseStream(grpc.testing.EchoRequest) returns (stream " \
+ "grpc.testing.EchoResponse) {}\n" \
+ " rpc BidiStream(stream grpc.testing.EchoRequest) returns (stream " \
+ "grpc.testing.EchoResponse) {}\n" \
+ " rpc Unimplemented(grpc.testing.EchoRequest) returns " \
+ "(grpc.testing.EchoResponse) {}\n" \
+ "}\n" \
+ "\n"
+
+#define ECHO_METHOD_DESCRIPTION \
+ " rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
+ "{}\n"
+
namespace grpc {
namespace testing {
+
+DECLARE_bool(l);
+
namespace {
class TestCliCredentials GRPC_FINAL : public grpc::testing::CliCredentials {
@@ -68,6 +102,17 @@ class TestCliCredentials GRPC_FINAL : public grpc::testing::CliCredentials {
const grpc::string GetCredentialUsage() const GRPC_OVERRIDE { return ""; }
};
+bool PrintStream(std::stringstream* ss, const grpc::string& output) {
+ (*ss) << output;
+ return true;
+}
+
+template <typename T>
+size_t ArraySize(T& a) {
+ return ((sizeof(a) / sizeof(*(a))) /
+ static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
+}
+
} // namespame
class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
@@ -122,19 +167,6 @@ class GrpcToolTest : public ::testing::Test {
reflection::ProtoServerReflectionPlugin plugin_;
};
-static bool PrintStream(std::stringstream* ss, const grpc::string& output) {
- (*ss) << output;
- return true;
-}
-
-template <typename T>
-static size_t ArraySize(T& a) {
- return ((sizeof(a) / sizeof(*(a))) /
- static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
-}
-
-#define USAGE_REGEX "( grpc_cli .+\n){2,10}"
-
TEST_F(GrpcToolTest, NoCommand) {
// Test input "grpc_cli"
std::stringstream output_stream;
@@ -176,6 +208,54 @@ TEST_F(GrpcToolTest, HelpCommand) {
EXPECT_TRUE(0 == output_stream.tellp());
}
+TEST_F(GrpcToolTest, ListCommand) {
+ // Test input "grpc_cli list localhost:<port>"
+ std::stringstream output_stream;
+
+ const grpc::string server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
+
+ FLAGS_l = false;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ "grpc.testing.EchoTestService\n"
+ "grpc.reflection.v1alpha.ServerReflection\n"));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, ListOneService) {
+ // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
+ std::stringstream output_stream;
+
+ const grpc::string server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
+ "grpc.testing.EchoTestService"};
+ // without -l flag
+ FLAGS_l = false;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: ECHO_TEST_SERVICE_SUMMARY
+ EXPECT_TRUE(0 ==
+ strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_SUMMARY));
+
+ // with -l flag
+ output_stream.str(grpc::string());
+ output_stream.clear();
+ FLAGS_l = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: ECHO_TEST_SERVICE_DESCRIPTION
+ EXPECT_TRUE(
+ 0 == strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_DESCRIPTION));
+
+ ShutdownServer();
+}
+
TEST_F(GrpcToolTest, TypeCommand) {
// Test input "grpc_cli type localhost:<port> grpc.testing.EchoRequest"
std::stringstream output_stream;
@@ -197,6 +277,35 @@ TEST_F(GrpcToolTest, TypeCommand) {
ShutdownServer();
}
+TEST_F(GrpcToolTest, ListOneMethod) {
+ // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
+ std::stringstream output_stream;
+
+ const grpc::string server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
+ "grpc.testing.EchoTestService.Echo"};
+ // without -l flag
+ FLAGS_l = false;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: "Echo"
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), "Echo\n"));
+
+ // with -l flag
+ output_stream.str(grpc::string());
+ output_stream.clear();
+ FLAGS_l = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: ECHO_METHOD_DESCRIPTION
+ EXPECT_TRUE(0 ==
+ strcmp(output_stream.str().c_str(), ECHO_METHOD_DESCRIPTION));
+
+ ShutdownServer();
+}
+
TEST_F(GrpcToolTest, TypeNotFound) {
// Test input "grpc_cli type localhost:<port> grpc.testing.DummyRequest"
std::stringstream output_stream;
@@ -214,7 +323,7 @@ TEST_F(GrpcToolTest, TypeNotFound) {
}
TEST_F(GrpcToolTest, CallCommand) {
- // Test input "grpc_cli call Echo"
+ // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
std::stringstream output_stream;
const grpc::string server_address = SetUpServer();
@@ -231,7 +340,7 @@ TEST_F(GrpcToolTest, CallCommand) {
}
TEST_F(GrpcToolTest, TooFewArguments) {
- // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
+ // Test input "grpc_cli call Echo"
std::stringstream output_stream;
const char* argv[] = {"grpc_cli", "call", "Echo"};
diff --git a/test/cpp/util/service_describer.cc b/test/cpp/util/service_describer.cc
new file mode 100644
index 0000000000..4fe4a74805
--- /dev/null
+++ b/test/cpp/util/service_describer.cc
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright 2016, 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/service_describer.h"
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace grpc {
+namespace testing {
+
+grpc::string DescribeServiceList(std::vector<grpc::string> service_list,
+ grpc::protobuf::DescriptorPool& desc_pool) {
+ std::stringstream result;
+ for (auto it = service_list.begin(); it != service_list.end(); it++) {
+ auto const& service = *it;
+ const grpc::protobuf::ServiceDescriptor* service_desc =
+ desc_pool.FindServiceByName(service);
+ if (service_desc != nullptr) {
+ result << DescribeService(service_desc);
+ }
+ }
+ return result.str();
+}
+
+grpc::string DescribeService(const grpc::protobuf::ServiceDescriptor* service) {
+ grpc::string result;
+ if (service->options().deprecated()) {
+ result.append("DEPRECATED\n");
+ }
+ result.append("filename: " + service->file()->name() + "\n");
+
+ grpc::string package = service->full_name();
+ size_t pos = package.rfind("." + service->name());
+ if (pos != grpc::string::npos) {
+ package.erase(pos);
+ result.append("package: " + package + ";\n");
+ }
+ result.append("service " + service->name() + " {\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ result.append(DescribeMethod(service->method(i)));
+ }
+ result.append("}\n\n");
+ return result;
+}
+
+grpc::string DescribeMethod(const grpc::protobuf::MethodDescriptor* method) {
+ std::stringstream result;
+ result << " rpc " << method->name()
+ << (method->client_streaming() ? "(stream " : "(")
+ << method->input_type()->full_name() << ") returns "
+ << (method->server_streaming() ? "(stream " : "(")
+ << method->output_type()->full_name() << ") {}\n";
+ if (method->options().deprecated()) {
+ result << " DEPRECATED";
+ }
+ return result.str();
+}
+
+grpc::string SummarizeService(
+ const grpc::protobuf::ServiceDescriptor* service) {
+ grpc::string result;
+ for (int i = 0; i < service->method_count(); ++i) {
+ result.append(SummarizeMethod(service->method(i)));
+ }
+ return result;
+}
+
+grpc::string SummarizeMethod(const grpc::protobuf::MethodDescriptor* method) {
+ grpc::string result = method->name();
+ result.append("\n");
+ return result;
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/test/cpp/util/service_describer.h b/test/cpp/util/service_describer.h
new file mode 100644
index 0000000000..02c58e84c4
--- /dev/null
+++ b/test/cpp/util/service_describer.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2016, 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_SERVICE_DESCRIBER_H
+#define GRPC_TEST_CPP_UTIL_SERVICE_DESCRIBER_H
+
+#include <grpc++/support/config.h>
+#include "test/cpp/util/config_grpc_cli.h"
+
+namespace grpc {
+namespace testing {
+
+grpc::string DescribeServiceList(std::vector<grpc::string> service_list,
+ grpc::protobuf::DescriptorPool& desc_pool);
+
+grpc::string DescribeService(const grpc::protobuf::ServiceDescriptor* service);
+
+grpc::string DescribeMethod(const grpc::protobuf::MethodDescriptor* method);
+
+grpc::string SummarizeService(const grpc::protobuf::ServiceDescriptor* service);
+
+grpc::string SummarizeMethod(const grpc::protobuf::MethodDescriptor* method);
+
+} // namespase testing
+} // namespace grpc
+
+#endif // GRPC_TEST_CPP_UTIL_SERVICE_DESCRIBER_H
diff --git a/test/distrib/csharp/DistribTest/Properties/AssemblyInfo.cs b/test/distrib/csharp/DistribTest/Properties/AssemblyInfo.cs
index bc25b263ca..eacc41ee3c 100644
--- a/test/distrib/csharp/DistribTest/Properties/AssemblyInfo.cs
+++ b/test/distrib/csharp/DistribTest/Properties/AssemblyInfo.cs
@@ -1,4 +1,37 @@
-using System.Reflection;
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/test/distrib/php/run_distrib_test.sh b/test/distrib/php/run_distrib_test.sh
index 5c86283282..9ce3e05cd4 100755
--- a/test/distrib/php/run_distrib_test.sh
+++ b/test/distrib/php/run_distrib_test.sh
@@ -32,8 +32,9 @@ set -ex
cd $(dirname $0)
-cp -r $EXTERNAL_GIT_ROOT/input_artifacts/grpc-php.tgz .
+cp -r $EXTERNAL_GIT_ROOT/input_artifacts/grpc-*.tgz .
-pecl install grpc-php.tgz
+find . -regextype sed -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
+ xargs pecl install
php -d extension=grpc.so -d max_execution_time=300 distribtest.php