merge with head
This commit is contained in:
commit
3ff9727a37
34
build.yaml
34
build.yaml
|
|
@ -1914,6 +1914,20 @@ targets:
|
|||
- mac
|
||||
- linux
|
||||
- posix
|
||||
- name: metrics_client
|
||||
build: test
|
||||
run: false
|
||||
language: c++
|
||||
headers:
|
||||
- test/cpp/util/metrics_server.h
|
||||
src:
|
||||
- test/proto/metrics.proto
|
||||
- test/cpp/interop/metrics_client.cc
|
||||
deps:
|
||||
- grpc++
|
||||
- grpc
|
||||
- gpr
|
||||
- grpc++_test_config
|
||||
- name: mock_test
|
||||
build: test
|
||||
language: c++
|
||||
|
|
@ -2155,13 +2169,16 @@ targets:
|
|||
- test/cpp/interop/client_helper.h
|
||||
- test/cpp/interop/interop_client.h
|
||||
- test/cpp/interop/stress_interop_client.h
|
||||
- test/cpp/util/metrics_server.h
|
||||
src:
|
||||
- test/proto/empty.proto
|
||||
- test/proto/messages.proto
|
||||
- test/proto/metrics.proto
|
||||
- test/proto/test.proto
|
||||
- test/cpp/interop/interop_client.cc
|
||||
- test/cpp/interop/stress_interop_client.cc
|
||||
- test/cpp/interop/stress_test.cc
|
||||
- test/cpp/util/metrics_server.cc
|
||||
deps:
|
||||
- grpc++_test_util
|
||||
- grpc_test_util
|
||||
|
|
@ -2256,6 +2273,23 @@ node_modules:
|
|||
- deps:
|
||||
- grpc
|
||||
- gpr
|
||||
headers:
|
||||
- src/node/ext/byte_buffer.h
|
||||
- src/node/ext/call.h
|
||||
- src/node/ext/call_credentials.h
|
||||
- src/node/ext/channel.h
|
||||
- src/node/ext/channel_credentials.h
|
||||
- src/node/ext/completion_queue_async_worker.h
|
||||
- src/node/ext/server.h
|
||||
- src/node/ext/server_credentials.h
|
||||
- src/node/ext/timeval.h
|
||||
js:
|
||||
- src/node/index.js
|
||||
- src/node/src/client.js
|
||||
- src/node/src/common.js
|
||||
- src/node/src/credentials.js
|
||||
- src/node/src/metadata.js
|
||||
- src/node/src/server.js
|
||||
name: grpc_node
|
||||
src:
|
||||
- src/node/ext/byte_buffer.cc
|
||||
|
|
|
|||
|
|
@ -186,9 +186,8 @@ std::shared_ptr<CallCredentials> GoogleIAMCredentials(
|
|||
/// Combines a channel credentials and a call credentials into a composite
|
||||
/// channel credentials.
|
||||
std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
|
||||
const std::shared_ptr<ChannelCredentials>& channel_creds,
|
||||
const std::shared_ptr<CallCredentials>& call_creds);
|
||||
|
||||
const std::shared_ptr<ChannelCredentials>& channel_creds,
|
||||
const std::shared_ptr<CallCredentials>& call_creds);
|
||||
|
||||
/// Combines two call credentials objects into a composite call credentials.
|
||||
std::shared_ptr<CallCredentials> CompositeCallCredentials(
|
||||
|
|
|
|||
|
|
@ -127,6 +127,12 @@ typedef struct {
|
|||
/** Initial sequence number for http2 transports */
|
||||
#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
|
||||
"grpc.http2.initial_sequence_number"
|
||||
/** How much memory to use for hpack decoding */
|
||||
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER \
|
||||
"grpc.http2.hpack_table_size.decoder"
|
||||
/** How much memory to use for hpack encoding */
|
||||
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \
|
||||
"grpc.http2.hpack_table_size.encoder"
|
||||
/** Default authority to pass if none specified on call construction */
|
||||
#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"
|
||||
/** Primary user agent: goes at the start of the user-agent metadata
|
||||
|
|
|
|||
|
|
@ -0,0 +1,141 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head><title>Interop Test Result</title></head>
|
||||
<body>
|
||||
|
||||
<%def name="fill_one_test_result(shortname, resultset)">
|
||||
% if shortname in resultset:
|
||||
## Because interop tests does not have runs_per_test flag, each test is
|
||||
## run once. So there should only be one element for each result.
|
||||
<% result = resultset[shortname][0] %>
|
||||
% if result.state == 'PASSED':
|
||||
<td bgcolor="green">PASS</td>
|
||||
% else:
|
||||
<%
|
||||
tooltip = ''
|
||||
if result.returncode > 0 or result.message:
|
||||
if result.returncode > 0:
|
||||
tooltip = 'returncode: %d ' % result.returncode
|
||||
if result.message:
|
||||
tooltip = '%smessage: %s' % (tooltip, result.message)
|
||||
%>
|
||||
% if result.state == 'FAILED':
|
||||
<td bgcolor="red">
|
||||
% if tooltip:
|
||||
<a href="#" data-toggle="tooltip" data-placement="auto" title="${tooltip | h}">FAIL</a></td>
|
||||
% else:
|
||||
FAIL</td>
|
||||
% endif
|
||||
% elif result.state == 'TIMEOUT':
|
||||
<td bgcolor="yellow">
|
||||
% if tooltip:
|
||||
<a href="#" data-toggle="tooltip" data-placement="auto" title="${tooltip | h}">TIMEOUT</a></td>
|
||||
% else:
|
||||
TIMEOUT</td>
|
||||
% endif
|
||||
% endif
|
||||
% endif
|
||||
% else:
|
||||
<td bgcolor="magenta">Not implemented</td>
|
||||
% endif
|
||||
</%def>
|
||||
|
||||
% if num_failures > 1:
|
||||
<p><h2><font color="red">${num_failures} tests failed!</font></h2></p>
|
||||
% elif num_failures:
|
||||
<p><h2><font color="red">${num_failures} test failed!</font></h2></p>
|
||||
% else:
|
||||
<p><h2><font color="green">All tests passed!</font></h2></p>
|
||||
% endif
|
||||
|
||||
% if cloud_to_prod:
|
||||
## Each column header is the client language.
|
||||
<h2>Cloud to Prod</h2>
|
||||
<table style="width:100%" border="1">
|
||||
<tr bgcolor="#00BFFF">
|
||||
<th>Client languages ►<br/>Test Cases ▼</th>
|
||||
% for client_lang in client_langs:
|
||||
<th>${client_lang}</th>
|
||||
% endfor
|
||||
</tr>
|
||||
% for test_case in test_cases + auth_test_cases:
|
||||
<tr><td><b>${test_case}</b></td>
|
||||
% for client_lang in client_langs:
|
||||
<%
|
||||
if test_case in auth_test_cases:
|
||||
shortname = 'cloud_to_prod_auth:%s:%s' % (client_lang, test_case)
|
||||
else:
|
||||
shortname = 'cloud_to_prod:%s:%s' % (client_lang, test_case)
|
||||
%>
|
||||
${fill_one_test_result(shortname, resultset)}
|
||||
% endfor
|
||||
</tr>
|
||||
% endfor
|
||||
</table>
|
||||
% endif
|
||||
|
||||
% if http2_interop:
|
||||
## Each column header is the server language.
|
||||
<h2>HTTP/2 Interop</h2>
|
||||
<table style="width:100%" border="1">
|
||||
<tr bgcolor="#00BFFF">
|
||||
<th>Servers ►<br/>Test Cases ▼</th>
|
||||
% for server_lang in server_langs:
|
||||
<th>${server_lang}</th>
|
||||
% endfor
|
||||
% if cloud_to_prod:
|
||||
<th>prod</th>
|
||||
% endif
|
||||
</tr>
|
||||
% for test_case in http2_cases:
|
||||
<tr><td><b>${test_case}</b></td>
|
||||
## Fill up the cells with test result.
|
||||
% for server_lang in server_langs:
|
||||
<%
|
||||
shortname = 'cloud_to_cloud:http2:%s_server:%s' % (
|
||||
server_lang, test_case)
|
||||
%>
|
||||
${fill_one_test_result(shortname, resultset)}
|
||||
% endfor
|
||||
% if cloud_to_prod:
|
||||
<% shortname = 'cloud_to_prod:http2:%s' % test_case %>
|
||||
${fill_one_test_result(shortname, resultset)}
|
||||
% endif
|
||||
</tr>
|
||||
% endfor
|
||||
</table>
|
||||
% endif
|
||||
|
||||
% if server_langs:
|
||||
% for test_case in test_cases:
|
||||
## Each column header is the client language.
|
||||
<h2>${test_case}</h2>
|
||||
<table style="width:100%" border="1">
|
||||
<tr bgcolor="#00BFFF">
|
||||
<th>Client languages ►<br/>Server languages ▼</th>
|
||||
% for client_lang in client_langs:
|
||||
<th>${client_lang}</th>
|
||||
% endfor
|
||||
</tr>
|
||||
## Each row head is the server language.
|
||||
% for server_lang in server_langs:
|
||||
<tr>
|
||||
<td><b>${server_lang}</b></td>
|
||||
% for client_lang in client_langs:
|
||||
<%
|
||||
shortname = 'cloud_to_cloud:%s:%s_server:%s' % (
|
||||
client_lang, server_lang, test_case)
|
||||
%>
|
||||
${fill_one_test_result(shortname, resultset)}
|
||||
% endfor
|
||||
</tr>
|
||||
% endfor
|
||||
</table>
|
||||
% endfor
|
||||
% endif
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){$('[data-toggle="tooltip"]').tooltip();});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -77,10 +77,10 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
|
|||
|
||||
/** construct a subchannel call (possibly asynchronously).
|
||||
*
|
||||
* If the returned status is 1, the call will return immediately and \a target
|
||||
* will point to a connected \a subchannel_call instance. Note that \a notify
|
||||
* If the returned status is 1, the call will return immediately and \a target
|
||||
* will point to a connected \a subchannel_call instance. Note that \a notify
|
||||
* will \em not be invoked in this case.
|
||||
* Otherwise, if the returned status is 0, the subchannel call will be created
|
||||
* Otherwise, if the returned status is 0, the subchannel call will be created
|
||||
* asynchronously, invoking the \a notify callback upon completion. */
|
||||
int grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx,
|
||||
grpc_subchannel *subchannel,
|
||||
|
|
|
|||
|
|
@ -126,7 +126,8 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {}
|
|||
|
||||
void grpc_pollset_reset(grpc_pollset *pollset) {
|
||||
GPR_ASSERT(pollset->shutting_down);
|
||||
GPR_ASSERT(!has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET));
|
||||
GPR_ASSERT(
|
||||
!has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET));
|
||||
pollset->shutting_down = 0;
|
||||
pollset->is_iocp_worker = 0;
|
||||
pollset->kicked_without_pollers = 0;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@
|
|||
/* Forward decl of grpc_tcp_server */
|
||||
typedef struct grpc_tcp_server grpc_tcp_server;
|
||||
|
||||
/* Forward decl of grpc_tcp_listener */
|
||||
typedef struct grpc_tcp_listener grpc_tcp_listener;
|
||||
|
||||
/* Called for newly connected TCP connections. */
|
||||
typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg,
|
||||
grpc_endpoint *ep);
|
||||
|
|
@ -51,19 +54,17 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server,
|
|||
grpc_pollset **pollsets, size_t pollset_count,
|
||||
grpc_tcp_server_cb on_accept_cb, void *cb_arg);
|
||||
|
||||
/* Add a port to the server, returning port number on success, or negative
|
||||
on failure.
|
||||
/* Add a port to the server, returning the newly created listener on success,
|
||||
or a null pointer on failure.
|
||||
|
||||
The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
|
||||
both IPv4 and IPv6 connections, but :: is the preferred style. This usually
|
||||
creates one socket, but possibly two on systems which support IPv6,
|
||||
but not dualstack sockets.
|
||||
|
||||
For raw access to the underlying sockets, see grpc_tcp_server_get_fd(). */
|
||||
but not dualstack sockets. */
|
||||
/* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle
|
||||
all of the multiple socket port matching logic in one place */
|
||||
int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
|
||||
size_t addr_len);
|
||||
grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
|
||||
const void *addr, size_t addr_len);
|
||||
|
||||
/* Returns the file descriptor of the Nth listening socket on this server,
|
||||
or -1 if the index is out of bounds.
|
||||
|
|
@ -75,4 +76,8 @@ int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned index);
|
|||
void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server,
|
||||
grpc_closure *closure);
|
||||
|
||||
int grpc_tcp_listener_get_port(grpc_tcp_listener *listener);
|
||||
void grpc_tcp_listener_ref(grpc_tcp_listener *listener);
|
||||
void grpc_tcp_listener_unref(grpc_tcp_listener *listener);
|
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */
|
||||
|
|
|
|||
|
|
@ -67,14 +67,13 @@
|
|||
#include <grpc/support/sync.h>
|
||||
#include <grpc/support/time.h>
|
||||
|
||||
#define INIT_PORT_CAP 2
|
||||
#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
|
||||
|
||||
static gpr_once s_init_max_accept_queue_size;
|
||||
static int s_max_accept_queue_size;
|
||||
|
||||
/* one listening port */
|
||||
typedef struct {
|
||||
struct grpc_tcp_listener {
|
||||
int fd;
|
||||
grpc_fd *emfd;
|
||||
grpc_tcp_server *server;
|
||||
|
|
@ -84,9 +83,18 @@ typedef struct {
|
|||
struct sockaddr_un un;
|
||||
} addr;
|
||||
size_t addr_len;
|
||||
int port;
|
||||
grpc_closure read_closure;
|
||||
grpc_closure destroyed_closure;
|
||||
} server_port;
|
||||
gpr_refcount refs;
|
||||
struct grpc_tcp_listener *next;
|
||||
/* When we add a listener, more than one can be created, mainly because of
|
||||
IPv6. A sibling will still be in the normal list, but will be flagged
|
||||
as such. Any action, such as ref or unref, will affect all of the
|
||||
siblings in the list. */
|
||||
struct grpc_tcp_listener *sibling;
|
||||
int is_sibling;
|
||||
};
|
||||
|
||||
static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
|
||||
struct stat st;
|
||||
|
|
@ -112,10 +120,9 @@ struct grpc_tcp_server {
|
|||
/* is this server shutting down? (boolean) */
|
||||
int shutdown;
|
||||
|
||||
/* all listening ports */
|
||||
server_port *ports;
|
||||
size_t nports;
|
||||
size_t port_capacity;
|
||||
/* linked list of server ports */
|
||||
grpc_tcp_listener *head;
|
||||
unsigned nports;
|
||||
|
||||
/* shutdown callback */
|
||||
grpc_closure *shutdown_complete;
|
||||
|
|
@ -134,9 +141,8 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
|
|||
s->shutdown = 0;
|
||||
s->on_accept_cb = NULL;
|
||||
s->on_accept_cb_arg = NULL;
|
||||
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
|
||||
s->head = NULL;
|
||||
s->nports = 0;
|
||||
s->port_capacity = INIT_PORT_CAP;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +151,12 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
|
|||
|
||||
gpr_mu_destroy(&s->mu);
|
||||
|
||||
gpr_free(s->ports);
|
||||
while (s->head) {
|
||||
grpc_tcp_listener *sp = s->head;
|
||||
s->head = sp->next;
|
||||
grpc_tcp_listener_unref(sp);
|
||||
}
|
||||
|
||||
gpr_free(s);
|
||||
}
|
||||
|
||||
|
|
@ -166,8 +177,6 @@ static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server, int success) {
|
|||
events will be received on them - at this point it's safe to destroy
|
||||
things */
|
||||
static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
|
||||
size_t i;
|
||||
|
||||
/* delete ALL the things */
|
||||
gpr_mu_lock(&s->mu);
|
||||
|
||||
|
|
@ -176,9 +185,9 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (s->nports) {
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
server_port *sp = &s->ports[i];
|
||||
if (s->head) {
|
||||
grpc_tcp_listener *sp;
|
||||
for (sp = s->head; sp; sp = sp->next) {
|
||||
if (sp->addr.sockaddr.sa_family == AF_UNIX) {
|
||||
unlink_if_unix_domain_socket(&sp->addr.un);
|
||||
}
|
||||
|
|
@ -196,7 +205,6 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
|
|||
|
||||
void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
|
||||
grpc_closure *closure) {
|
||||
size_t i;
|
||||
gpr_mu_lock(&s->mu);
|
||||
|
||||
GPR_ASSERT(!s->shutdown);
|
||||
|
|
@ -206,8 +214,9 @@ void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
|
|||
|
||||
/* shutdown all fd's */
|
||||
if (s->active_ports) {
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
grpc_fd_shutdown(exec_ctx, s->ports[i].emfd);
|
||||
grpc_tcp_listener *sp;
|
||||
for (sp = s->head; sp; sp = sp->next) {
|
||||
grpc_fd_shutdown(exec_ctx, sp->emfd);
|
||||
}
|
||||
gpr_mu_unlock(&s->mu);
|
||||
} else {
|
||||
|
|
@ -298,7 +307,7 @@ error:
|
|||
|
||||
/* event manager callback when reads are ready */
|
||||
static void on_read(grpc_exec_ctx *exec_ctx, void *arg, int success) {
|
||||
server_port *sp = arg;
|
||||
grpc_tcp_listener *sp = arg;
|
||||
grpc_fd *fdobj;
|
||||
size_t i;
|
||||
|
||||
|
|
@ -364,9 +373,10 @@ error:
|
|||
}
|
||||
}
|
||||
|
||||
static int add_socket_to_server(grpc_tcp_server *s, int fd,
|
||||
const struct sockaddr *addr, size_t addr_len) {
|
||||
server_port *sp;
|
||||
static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd,
|
||||
const struct sockaddr *addr,
|
||||
size_t addr_len) {
|
||||
grpc_tcp_listener *sp = NULL;
|
||||
int port;
|
||||
char *addr_str;
|
||||
char *name;
|
||||
|
|
@ -376,32 +386,34 @@ static int add_socket_to_server(grpc_tcp_server *s, int fd,
|
|||
grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
|
||||
gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
|
||||
gpr_mu_lock(&s->mu);
|
||||
s->nports++;
|
||||
GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
|
||||
/* append it to the list under a lock */
|
||||
if (s->nports == s->port_capacity) {
|
||||
s->port_capacity *= 2;
|
||||
s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
|
||||
}
|
||||
sp = &s->ports[s->nports++];
|
||||
sp = gpr_malloc(sizeof(grpc_tcp_listener));
|
||||
sp->next = s->head;
|
||||
s->head = sp;
|
||||
sp->server = s;
|
||||
sp->fd = fd;
|
||||
sp->emfd = grpc_fd_create(fd, name);
|
||||
memcpy(sp->addr.untyped, addr, addr_len);
|
||||
sp->addr_len = addr_len;
|
||||
sp->port = port;
|
||||
sp->is_sibling = 0;
|
||||
sp->sibling = NULL;
|
||||
gpr_ref_init(&sp->refs, 1);
|
||||
GPR_ASSERT(sp->emfd);
|
||||
gpr_mu_unlock(&s->mu);
|
||||
gpr_free(addr_str);
|
||||
gpr_free(name);
|
||||
}
|
||||
|
||||
return port;
|
||||
return sp;
|
||||
}
|
||||
|
||||
int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
|
||||
size_t addr_len) {
|
||||
int allocated_port1 = -1;
|
||||
int allocated_port2 = -1;
|
||||
unsigned i;
|
||||
grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
|
||||
const void *addr, size_t addr_len) {
|
||||
int allocated_port = -1;
|
||||
grpc_tcp_listener *sp;
|
||||
grpc_tcp_listener *sp2 = NULL;
|
||||
int fd;
|
||||
grpc_dualstack_mode dsmode;
|
||||
struct sockaddr_in6 addr6_v4mapped;
|
||||
|
|
@ -420,9 +432,9 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
|
|||
/* Check if this is a wildcard port, and if so, try to keep the port the same
|
||||
as some previously created listener. */
|
||||
if (grpc_sockaddr_get_port(addr) == 0) {
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
for (sp = s->head; sp; sp = sp->next) {
|
||||
sockname_len = sizeof(sockname_temp);
|
||||
if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp,
|
||||
if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp,
|
||||
&sockname_len)) {
|
||||
port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
|
||||
if (port > 0) {
|
||||
|
|
@ -436,6 +448,8 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
|
|||
}
|
||||
}
|
||||
|
||||
sp = NULL;
|
||||
|
||||
if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
|
||||
addr = (const struct sockaddr *)&addr6_v4mapped;
|
||||
addr_len = sizeof(addr6_v4mapped);
|
||||
|
|
@ -449,14 +463,16 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
|
|||
addr = (struct sockaddr *)&wild6;
|
||||
addr_len = sizeof(wild6);
|
||||
fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
|
||||
allocated_port1 = add_socket_to_server(s, fd, addr, addr_len);
|
||||
sp = add_socket_to_server(s, fd, addr, addr_len);
|
||||
allocated_port = sp->port;
|
||||
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
|
||||
if (port == 0 && allocated_port1 > 0) {
|
||||
grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1);
|
||||
if (port == 0 && allocated_port > 0) {
|
||||
grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port);
|
||||
sp2 = sp;
|
||||
}
|
||||
addr = (struct sockaddr *)&wild4;
|
||||
addr_len = sizeof(wild4);
|
||||
|
|
@ -471,22 +487,32 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
|
|||
addr = (struct sockaddr *)&addr4_copy;
|
||||
addr_len = sizeof(addr4_copy);
|
||||
}
|
||||
allocated_port2 = add_socket_to_server(s, fd, addr, addr_len);
|
||||
sp = add_socket_to_server(s, fd, addr, addr_len);
|
||||
sp->sibling = sp2;
|
||||
if (sp2) sp2->is_sibling = 1;
|
||||
|
||||
done:
|
||||
gpr_free(allocated_addr);
|
||||
return allocated_port1 >= 0 ? allocated_port1 : allocated_port2;
|
||||
return sp;
|
||||
}
|
||||
|
||||
int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned port_index) {
|
||||
return (port_index < s->nports) ? s->ports[port_index].fd : -1;
|
||||
grpc_tcp_listener *sp;
|
||||
for (sp = s->head; sp && port_index != 0; sp = sp->next, port_index--)
|
||||
;
|
||||
if (port_index == 0 && sp) {
|
||||
return sp->fd;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
|
||||
grpc_pollset **pollsets, size_t pollset_count,
|
||||
grpc_tcp_server_cb on_accept_cb,
|
||||
void *on_accept_cb_arg) {
|
||||
size_t i, j;
|
||||
size_t i;
|
||||
grpc_tcp_listener *sp;
|
||||
GPR_ASSERT(on_accept_cb);
|
||||
gpr_mu_lock(&s->mu);
|
||||
GPR_ASSERT(!s->on_accept_cb);
|
||||
|
|
@ -495,17 +521,40 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
|
|||
s->on_accept_cb_arg = on_accept_cb_arg;
|
||||
s->pollsets = pollsets;
|
||||
s->pollset_count = pollset_count;
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
for (j = 0; j < pollset_count; j++) {
|
||||
grpc_pollset_add_fd(exec_ctx, pollsets[j], s->ports[i].emfd);
|
||||
for (sp = s->head; sp; sp = sp->next) {
|
||||
for (i = 0; i < pollset_count; i++) {
|
||||
grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
|
||||
}
|
||||
s->ports[i].read_closure.cb = on_read;
|
||||
s->ports[i].read_closure.cb_arg = &s->ports[i];
|
||||
grpc_fd_notify_on_read(exec_ctx, s->ports[i].emfd,
|
||||
&s->ports[i].read_closure);
|
||||
sp->read_closure.cb = on_read;
|
||||
sp->read_closure.cb_arg = sp;
|
||||
grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
|
||||
s->active_ports++;
|
||||
}
|
||||
gpr_mu_unlock(&s->mu);
|
||||
}
|
||||
|
||||
int grpc_tcp_listener_get_port(grpc_tcp_listener *listener) {
|
||||
grpc_tcp_listener *sp = listener;
|
||||
return sp->port;
|
||||
}
|
||||
|
||||
void grpc_tcp_listener_ref(grpc_tcp_listener *listener) {
|
||||
grpc_tcp_listener *sp = listener;
|
||||
gpr_ref(&sp->refs);
|
||||
}
|
||||
|
||||
void grpc_tcp_listener_unref(grpc_tcp_listener *listener) {
|
||||
grpc_tcp_listener *sp = listener;
|
||||
if (sp->is_sibling) return;
|
||||
if (gpr_unref(&sp->refs)) {
|
||||
grpc_tcp_listener *sibling = sp->sibling;
|
||||
while (sibling) {
|
||||
sp = sibling;
|
||||
sibling = sp->sibling;
|
||||
gpr_free(sp);
|
||||
}
|
||||
gpr_free(listener);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@
|
|||
|
||||
#ifdef GPR_WINSOCK_SOCKET
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <io.h>
|
||||
|
||||
#include "src/core/iomgr/sockaddr_utils.h"
|
||||
|
||||
#include <grpc/support/alloc.h>
|
||||
|
|
@ -51,25 +52,29 @@
|
|||
#include "src/core/iomgr/tcp_server.h"
|
||||
#include "src/core/iomgr/tcp_windows.h"
|
||||
|
||||
#define INIT_PORT_CAP 2
|
||||
#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
|
||||
|
||||
/* one listening port */
|
||||
typedef struct server_port {
|
||||
struct grpc_tcp_listener {
|
||||
/* This seemingly magic number comes from AcceptEx's documentation. each
|
||||
address buffer needs to have at least 16 more bytes at their end. */
|
||||
gpr_uint8 addresses[(sizeof(struct sockaddr_in6) + 16) * 2];
|
||||
/* This will hold the socket for the next accept. */
|
||||
SOCKET new_socket;
|
||||
/* The listener winsocked. */
|
||||
/* The listener winsocket. */
|
||||
grpc_winsocket *socket;
|
||||
/* The actual TCP port number. */
|
||||
int port;
|
||||
grpc_tcp_server *server;
|
||||
/* The cached AcceptEx for that port. */
|
||||
LPFN_ACCEPTEX AcceptEx;
|
||||
int shutting_down;
|
||||
/* closure for socket notification of accept being ready */
|
||||
grpc_closure on_accept;
|
||||
} server_port;
|
||||
gpr_refcount refs;
|
||||
/* linked list */
|
||||
struct grpc_tcp_listener *next;
|
||||
};
|
||||
|
||||
/* the overall server */
|
||||
struct grpc_tcp_server {
|
||||
|
|
@ -82,10 +87,8 @@ struct grpc_tcp_server {
|
|||
/* active port count: how many ports are actually still listening */
|
||||
int active_ports;
|
||||
|
||||
/* all listening ports */
|
||||
server_port *ports;
|
||||
size_t nports;
|
||||
size_t port_capacity;
|
||||
/* linked list of server ports */
|
||||
grpc_tcp_listener *head;
|
||||
|
||||
/* shutdown callback */
|
||||
grpc_closure *shutdown_complete;
|
||||
|
|
@ -99,9 +102,7 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
|
|||
s->active_ports = 0;
|
||||
s->on_accept_cb = NULL;
|
||||
s->on_accept_cb_arg = NULL;
|
||||
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
|
||||
s->nports = 0;
|
||||
s->port_capacity = INIT_PORT_CAP;
|
||||
s->head = NULL;
|
||||
s->shutdown_complete = NULL;
|
||||
return s;
|
||||
}
|
||||
|
|
@ -109,26 +110,26 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
|
|||
static void dont_care_about_shutdown_completion(void *arg) {}
|
||||
|
||||
static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
|
||||
size_t i;
|
||||
|
||||
grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1);
|
||||
|
||||
/* Now that the accepts have been aborted, we can destroy the sockets.
|
||||
The IOCP won't get notified on these, so we can flag them as already
|
||||
closed by the system. */
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
server_port *sp = &s->ports[i];
|
||||
while (s->head) {
|
||||
grpc_tcp_listener *sp = s->head;
|
||||
s->head = sp->next;
|
||||
sp->next = NULL;
|
||||
grpc_winsocket_destroy(sp->socket);
|
||||
grpc_tcp_listener_unref(sp);
|
||||
}
|
||||
gpr_free(s->ports);
|
||||
gpr_free(s);
|
||||
}
|
||||
|
||||
/* Public function. Stops and destroys a grpc_tcp_server. */
|
||||
void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
|
||||
grpc_closure *shutdown_complete) {
|
||||
size_t i;
|
||||
int immediately_done = 0;
|
||||
grpc_tcp_listener *sp;
|
||||
gpr_mu_lock(&s->mu);
|
||||
|
||||
s->shutdown_complete = shutdown_complete;
|
||||
|
|
@ -138,8 +139,7 @@ void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
|
|||
if (s->active_ports == 0) {
|
||||
immediately_done = 1;
|
||||
}
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
server_port *sp = &s->ports[i];
|
||||
for (sp = s->head; sp; sp = sp->next) {
|
||||
sp->shutting_down = 1;
|
||||
grpc_winsocket_shutdown(sp->socket);
|
||||
}
|
||||
|
|
@ -199,7 +199,7 @@ error:
|
|||
}
|
||||
|
||||
static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
|
||||
server_port *sp) {
|
||||
grpc_tcp_listener *sp) {
|
||||
int notify = 0;
|
||||
sp->shutting_down = 0;
|
||||
gpr_mu_lock(&sp->server->mu);
|
||||
|
|
@ -216,7 +216,7 @@ static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
|
|||
|
||||
/* In order to do an async accept, we need to create a socket first which
|
||||
will be the one assigned to the new incoming connection. */
|
||||
static void start_accept(grpc_exec_ctx *exec_ctx, server_port *port) {
|
||||
static void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) {
|
||||
SOCKET sock = INVALID_SOCKET;
|
||||
char *message;
|
||||
char *utf8_message;
|
||||
|
|
@ -276,7 +276,7 @@ failure:
|
|||
|
||||
/* Event manager callback when reads are ready. */
|
||||
static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) {
|
||||
server_port *sp = arg;
|
||||
grpc_tcp_listener *sp = arg;
|
||||
SOCKET sock = sp->new_socket;
|
||||
grpc_winsocket_callback_info *info = &sp->socket->read_info;
|
||||
grpc_endpoint *ep = NULL;
|
||||
|
|
@ -351,16 +351,17 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) {
|
|||
start_accept(exec_ctx, sp);
|
||||
}
|
||||
|
||||
static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
|
||||
const struct sockaddr *addr, size_t addr_len) {
|
||||
server_port *sp;
|
||||
static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
|
||||
const struct sockaddr *addr,
|
||||
size_t addr_len) {
|
||||
grpc_tcp_listener *sp = NULL;
|
||||
int port;
|
||||
int status;
|
||||
GUID guid = WSAID_ACCEPTEX;
|
||||
DWORD ioctl_num_bytes;
|
||||
LPFN_ACCEPTEX AcceptEx;
|
||||
|
||||
if (sock == INVALID_SOCKET) return -1;
|
||||
if (sock == INVALID_SOCKET) return NULL;
|
||||
|
||||
/* We need to grab the AcceptEx pointer for that port, as it may be
|
||||
interface-dependent. We'll cache it to avoid doing that again. */
|
||||
|
|
@ -373,37 +374,34 @@ static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
|
|||
gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
|
||||
gpr_free(utf8_message);
|
||||
closesocket(sock);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
port = prepare_socket(sock, addr, addr_len);
|
||||
if (port >= 0) {
|
||||
gpr_mu_lock(&s->mu);
|
||||
GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
|
||||
/* append it to the list under a lock */
|
||||
if (s->nports == s->port_capacity) {
|
||||
/* too many ports, and we need to store their address in a closure */
|
||||
/* TODO(ctiller): make server_port a linked list */
|
||||
abort();
|
||||
}
|
||||
sp = &s->ports[s->nports++];
|
||||
sp = gpr_malloc(sizeof(grpc_tcp_listener));
|
||||
sp->next = s->head;
|
||||
s->head = sp;
|
||||
sp->server = s;
|
||||
sp->socket = grpc_winsocket_create(sock, "listener");
|
||||
sp->shutting_down = 0;
|
||||
sp->AcceptEx = AcceptEx;
|
||||
sp->new_socket = INVALID_SOCKET;
|
||||
sp->port = port;
|
||||
gpr_ref_init(&sp->refs, 1);
|
||||
grpc_closure_init(&sp->on_accept, on_accept, sp);
|
||||
GPR_ASSERT(sp->socket);
|
||||
gpr_mu_unlock(&s->mu);
|
||||
}
|
||||
|
||||
return port;
|
||||
return sp;
|
||||
}
|
||||
|
||||
int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
|
||||
size_t addr_len) {
|
||||
int allocated_port = -1;
|
||||
unsigned i;
|
||||
grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
|
||||
const void *addr, size_t addr_len) {
|
||||
grpc_tcp_listener *sp;
|
||||
SOCKET sock;
|
||||
struct sockaddr_in6 addr6_v4mapped;
|
||||
struct sockaddr_in6 wildcard;
|
||||
|
|
@ -415,9 +413,9 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
|
|||
/* Check if this is a wildcard port, and if so, try to keep the port the same
|
||||
as some previously created listener. */
|
||||
if (grpc_sockaddr_get_port(addr) == 0) {
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
for (sp = s->head; sp; sp = sp->next) {
|
||||
sockname_len = sizeof(sockname_temp);
|
||||
if (0 == getsockname(s->ports[i].socket->socket,
|
||||
if (0 == getsockname(sp->socket->socket,
|
||||
(struct sockaddr *)&sockname_temp, &sockname_len)) {
|
||||
port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
|
||||
if (port > 0) {
|
||||
|
|
@ -452,33 +450,56 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
|
|||
gpr_free(utf8_message);
|
||||
}
|
||||
|
||||
allocated_port = add_socket_to_server(s, sock, addr, addr_len);
|
||||
sp = add_socket_to_server(s, sock, addr, addr_len);
|
||||
gpr_free(allocated_addr);
|
||||
|
||||
return allocated_port;
|
||||
return sp;
|
||||
}
|
||||
|
||||
SOCKET
|
||||
grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) {
|
||||
return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET;
|
||||
int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned port_index) {
|
||||
grpc_tcp_listener *sp;
|
||||
for (sp = s->head; sp && port_index != 0; sp = sp->next, port_index--)
|
||||
;
|
||||
if (port_index == 0 && sp) {
|
||||
return _open_osfhandle(sp->socket->socket, 0);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
|
||||
grpc_pollset **pollset, size_t pollset_count,
|
||||
grpc_tcp_server_cb on_accept_cb,
|
||||
void *on_accept_cb_arg) {
|
||||
size_t i;
|
||||
grpc_tcp_listener *sp;
|
||||
GPR_ASSERT(on_accept_cb);
|
||||
gpr_mu_lock(&s->mu);
|
||||
GPR_ASSERT(!s->on_accept_cb);
|
||||
GPR_ASSERT(s->active_ports == 0);
|
||||
s->on_accept_cb = on_accept_cb;
|
||||
s->on_accept_cb_arg = on_accept_cb_arg;
|
||||
for (i = 0; i < s->nports; i++) {
|
||||
start_accept(exec_ctx, s->ports + i);
|
||||
for (sp = s->head; sp; sp = sp->next) {
|
||||
start_accept(exec_ctx, sp);
|
||||
s->active_ports++;
|
||||
}
|
||||
gpr_mu_unlock(&s->mu);
|
||||
}
|
||||
|
||||
int grpc_tcp_listener_get_port(grpc_tcp_listener *listener) {
|
||||
grpc_tcp_listener *sp = listener;
|
||||
return sp->port;
|
||||
}
|
||||
|
||||
void grpc_tcp_listener_ref(grpc_tcp_listener *listener) {
|
||||
grpc_tcp_listener *sp = listener;
|
||||
gpr_ref(&sp->refs);
|
||||
}
|
||||
|
||||
void grpc_tcp_listener_unref(grpc_tcp_listener *listener) {
|
||||
grpc_tcp_listener *sp = listener;
|
||||
if (gpr_unref(&sp->refs)) {
|
||||
gpr_free(listener);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* GPR_WINSOCK_SOCKET */
|
||||
|
|
|
|||
|
|
@ -116,9 +116,12 @@ void grpc_call_credentials_release(grpc_call_credentials *creds) {
|
|||
grpc_call_credentials_unref(creds);
|
||||
}
|
||||
|
||||
void grpc_call_credentials_get_request_metadata(
|
||||
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
|
||||
const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
|
||||
void grpc_call_credentials_get_request_metadata(grpc_exec_ctx *exec_ctx,
|
||||
grpc_call_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data) {
|
||||
if (creds == NULL || creds->vtable->get_request_metadata == NULL) {
|
||||
if (cb != NULL) {
|
||||
cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
|
||||
|
|
@ -423,9 +426,12 @@ static void jwt_destruct(grpc_call_credentials *creds) {
|
|||
gpr_mu_destroy(&c->cache_mu);
|
||||
}
|
||||
|
||||
static void jwt_get_request_metadata(
|
||||
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
|
||||
const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
|
||||
static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx,
|
||||
grpc_call_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data) {
|
||||
grpc_service_account_jwt_access_credentials *c =
|
||||
(grpc_service_account_jwt_access_credentials *)creds;
|
||||
gpr_timespec refresh_threshold = gpr_time_from_seconds(
|
||||
|
|
@ -798,9 +804,12 @@ static void on_simulated_token_fetch_done(void *user_data) {
|
|||
grpc_exec_ctx_finish(&exec_ctx);
|
||||
}
|
||||
|
||||
static void md_only_test_get_request_metadata(
|
||||
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
|
||||
const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
|
||||
static void md_only_test_get_request_metadata(grpc_exec_ctx *exec_ctx,
|
||||
grpc_call_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data) {
|
||||
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
|
||||
|
||||
if (c->is_async) {
|
||||
|
|
@ -837,9 +846,12 @@ static void access_token_destruct(grpc_call_credentials *creds) {
|
|||
grpc_credentials_md_store_unref(c->access_token_md);
|
||||
}
|
||||
|
||||
static void access_token_get_request_metadata(
|
||||
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
|
||||
const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
|
||||
static void access_token_get_request_metadata(grpc_exec_ctx *exec_ctx,
|
||||
grpc_call_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data) {
|
||||
grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
|
||||
cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
|
||||
}
|
||||
|
|
@ -978,9 +990,12 @@ static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
|
|||
composite_call_md_context_destroy(ctx);
|
||||
}
|
||||
|
||||
static void composite_call_get_request_metadata(
|
||||
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
|
||||
const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
|
||||
static void composite_call_get_request_metadata(grpc_exec_ctx *exec_ctx,
|
||||
grpc_call_credentials *creds,
|
||||
grpc_pollset *pollset,
|
||||
const char *service_url,
|
||||
grpc_credentials_metadata_cb cb,
|
||||
void *user_data) {
|
||||
grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
|
||||
grpc_composite_call_credentials_metadata_context *ctx;
|
||||
|
||||
|
|
@ -1097,7 +1112,7 @@ static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx,
|
|||
}
|
||||
|
||||
static grpc_call_credentials_vtable iam_vtable = {iam_destruct,
|
||||
iam_get_request_metadata};
|
||||
iam_get_request_metadata};
|
||||
|
||||
grpc_call_credentials *grpc_google_iam_credentials_create(
|
||||
const char *token, const char *authority_selector, void *reserved) {
|
||||
|
|
@ -1265,4 +1280,3 @@ grpc_channel_credentials *grpc_composite_channel_credentials_create(
|
|||
c->call_creds = grpc_call_credentials_ref(call_creds);
|
||||
return &c->base;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,7 +187,8 @@ typedef struct {
|
|||
size_t num_creds;
|
||||
} grpc_call_credentials_array;
|
||||
|
||||
const grpc_call_credentials_array *grpc_composite_call_credentials_get_credentials(
|
||||
const grpc_call_credentials_array *
|
||||
grpc_composite_call_credentials_get_credentials(
|
||||
grpc_call_credentials *composite_creds);
|
||||
|
||||
/* Returns creds if creds is of the specified type or the inner creds of the
|
||||
|
|
|
|||
|
|
@ -214,7 +214,8 @@ grpc_channel_credentials *grpc_google_default_credentials_create(void) {
|
|||
end:
|
||||
if (result == NULL) {
|
||||
if (call_creds != NULL) {
|
||||
/* Blend with default ssl credentials and add a global reference so that it
|
||||
/* Blend with default ssl credentials and add a global reference so that
|
||||
it
|
||||
can be cached and re-served. */
|
||||
grpc_channel_credentials *ssl_creds =
|
||||
grpc_ssl_credentials_create(NULL, NULL, NULL);
|
||||
|
|
|
|||
|
|
@ -571,9 +571,9 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
|
|||
}
|
||||
|
||||
grpc_security_status grpc_ssl_channel_security_connector_create(
|
||||
grpc_call_credentials *request_metadata_creds, const grpc_ssl_config *config,
|
||||
const char *target_name, const char *overridden_target_name,
|
||||
grpc_channel_security_connector **sc) {
|
||||
grpc_call_credentials *request_metadata_creds,
|
||||
const grpc_ssl_config *config, const char *target_name,
|
||||
const char *overridden_target_name, grpc_channel_security_connector **sc) {
|
||||
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
|
||||
const unsigned char **alpn_protocol_strings =
|
||||
gpr_malloc(sizeof(const char *) * num_alpn_protocols);
|
||||
|
|
|
|||
|
|
@ -249,9 +249,11 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
|
|||
}
|
||||
|
||||
for (i = 0; i < resolved->naddrs; i++) {
|
||||
port_temp = grpc_tcp_server_add_port(
|
||||
grpc_tcp_listener *listener;
|
||||
listener = grpc_tcp_server_add_port(
|
||||
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
|
||||
resolved->addrs[i].len);
|
||||
port_temp = grpc_tcp_listener_get_port(listener);
|
||||
if (port_temp >= 0) {
|
||||
if (port_num == -1) {
|
||||
port_num = port_temp;
|
||||
|
|
|
|||
|
|
@ -121,4 +121,3 @@ gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) {
|
|||
}
|
||||
return out_slice;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -922,7 +922,8 @@ static batch_control *allocate_batch_control(grpc_call *call) {
|
|||
size_t i;
|
||||
for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) {
|
||||
if ((call->used_batches & (1 << i)) == 0) {
|
||||
call->used_batches |= (gpr_uint8)(1 << i);
|
||||
call->used_batches =
|
||||
(gpr_uint8)(call->used_batches | (gpr_uint8)(1 << i));
|
||||
return &call->active_batches[i];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,9 +107,11 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
|
|||
}
|
||||
|
||||
for (i = 0; i < resolved->naddrs; i++) {
|
||||
port_temp = grpc_tcp_server_add_port(
|
||||
grpc_tcp_listener *listener;
|
||||
listener = grpc_tcp_server_add_port(
|
||||
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
|
||||
resolved->addrs[i].len);
|
||||
port_temp = grpc_tcp_listener_get_port(listener);
|
||||
if (port_temp >= 0) {
|
||||
if (port_num == -1) {
|
||||
port_num = port_temp;
|
||||
|
|
|
|||
|
|
@ -36,8 +36,10 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/useful.h>
|
||||
|
||||
#include "src/core/transport/chttp2/bin_encoder.h"
|
||||
#include "src/core/transport/chttp2/hpack_table.h"
|
||||
#include "src/core/transport/chttp2/timeout_encoding.h"
|
||||
|
|
@ -154,6 +156,18 @@ static gpr_uint8 *add_tiny_header_data(framer_state *st, size_t len) {
|
|||
return gpr_slice_buffer_tiny_add(st->output, len);
|
||||
}
|
||||
|
||||
static void evict_entry(grpc_chttp2_hpack_compressor *c) {
|
||||
c->tail_remote_index++;
|
||||
GPR_ASSERT(c->tail_remote_index > 0);
|
||||
GPR_ASSERT(c->table_size >=
|
||||
c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
|
||||
GPR_ASSERT(c->table_elems > 0);
|
||||
c->table_size = (gpr_uint16)(
|
||||
c->table_size -
|
||||
c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
|
||||
c->table_elems--;
|
||||
}
|
||||
|
||||
/* add an element to the decoder table */
|
||||
static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
|
||||
gpr_uint32 key_hash = elem->key->hash;
|
||||
|
|
@ -164,26 +178,21 @@ static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
|
|||
|
||||
GPR_ASSERT(elem_size < 65536);
|
||||
|
||||
if (elem_size > c->max_table_size) {
|
||||
while (c->table_size > 0) {
|
||||
evict_entry(c);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reserve space for this element in the remote table: if this overflows
|
||||
the current table, drop elements until it fits, matching the decompressor
|
||||
algorithm */
|
||||
/* TODO(ctiller): constant */
|
||||
while (c->table_size + elem_size > 4096) {
|
||||
c->tail_remote_index++;
|
||||
GPR_ASSERT(c->tail_remote_index > 0);
|
||||
GPR_ASSERT(c->table_size >=
|
||||
c->table_elem_size[c->tail_remote_index %
|
||||
GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]);
|
||||
GPR_ASSERT(c->table_elems > 0);
|
||||
c->table_size =
|
||||
(gpr_uint16)(c->table_size -
|
||||
c->table_elem_size[c->tail_remote_index %
|
||||
GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]);
|
||||
c->table_elems--;
|
||||
while (c->table_size + elem_size > c->max_table_size) {
|
||||
evict_entry(c);
|
||||
}
|
||||
GPR_ASSERT(c->table_elems < GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS);
|
||||
c->table_elem_size[new_index % GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS] =
|
||||
(gpr_uint16)elem_size;
|
||||
GPR_ASSERT(c->table_elems < c->max_table_size);
|
||||
c->table_elem_size[new_index % c->cap_table_elems] = (gpr_uint16)elem_size;
|
||||
c->table_size = (gpr_uint16)(c->table_size + elem_size);
|
||||
c->table_elems++;
|
||||
|
||||
|
|
@ -329,6 +338,14 @@ static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
|
|||
add_header_data(st, gpr_slice_ref(value_slice));
|
||||
}
|
||||
|
||||
static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
|
||||
framer_state *st) {
|
||||
gpr_uint32 len = GRPC_CHTTP2_VARINT_LENGTH(c->max_table_size, 3);
|
||||
GRPC_CHTTP2_WRITE_VARINT(c->max_table_size, 3, 0x20,
|
||||
add_tiny_header_data(st, len), len);
|
||||
c->advertise_table_size_change = 0;
|
||||
}
|
||||
|
||||
static gpr_uint32 dynidx(grpc_chttp2_hpack_compressor *c,
|
||||
gpr_uint32 elem_index) {
|
||||
return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index +
|
||||
|
|
@ -447,11 +464,23 @@ gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) {
|
|||
return slice;
|
||||
}
|
||||
|
||||
static gpr_uint32 elems_for_bytes(gpr_uint32 bytes) {
|
||||
return (bytes + 31) / 32;
|
||||
}
|
||||
|
||||
void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
|
||||
grpc_mdctx *ctx) {
|
||||
memset(c, 0, sizeof(*c));
|
||||
c->mdctx = ctx;
|
||||
c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout");
|
||||
c->max_table_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
|
||||
c->cap_table_elems = elems_for_bytes(c->max_table_size);
|
||||
c->max_table_elems = c->cap_table_elems;
|
||||
c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
|
||||
c->table_elem_size =
|
||||
gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems);
|
||||
memset(c->table_elem_size, 0,
|
||||
sizeof(*c->table_elem_size) * c->cap_table_elems);
|
||||
}
|
||||
|
||||
void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
|
||||
|
|
@ -461,6 +490,55 @@ void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
|
|||
if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]);
|
||||
}
|
||||
GRPC_MDSTR_UNREF(c->timeout_key_str);
|
||||
gpr_free(c->table_elem_size);
|
||||
}
|
||||
|
||||
void grpc_chttp2_hpack_compressor_set_max_usable_size(
|
||||
grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size) {
|
||||
c->max_usable_size = max_table_size;
|
||||
grpc_chttp2_hpack_compressor_set_max_table_size(
|
||||
c, GPR_MIN(c->max_table_size, max_table_size));
|
||||
}
|
||||
|
||||
static void rebuild_elems(grpc_chttp2_hpack_compressor *c, gpr_uint32 new_cap) {
|
||||
gpr_uint16 *table_elem_size = gpr_malloc(sizeof(*table_elem_size) * new_cap);
|
||||
gpr_uint32 i;
|
||||
|
||||
memset(table_elem_size, 0, sizeof(*table_elem_size) * new_cap);
|
||||
GPR_ASSERT(c->table_elems <= new_cap);
|
||||
|
||||
for (i = 0; i < c->table_elems; i++) {
|
||||
gpr_uint32 ofs = c->tail_remote_index + i + 1;
|
||||
table_elem_size[ofs % new_cap] =
|
||||
c->table_elem_size[ofs % c->cap_table_elems];
|
||||
}
|
||||
|
||||
c->cap_table_elems = new_cap;
|
||||
gpr_free(c->table_elem_size);
|
||||
c->table_elem_size = table_elem_size;
|
||||
}
|
||||
|
||||
void grpc_chttp2_hpack_compressor_set_max_table_size(
|
||||
grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size) {
|
||||
max_table_size = GPR_MIN(max_table_size, c->max_usable_size);
|
||||
if (max_table_size == c->max_table_size) {
|
||||
return;
|
||||
}
|
||||
while (c->table_size > 0 && c->table_size > max_table_size) {
|
||||
evict_entry(c);
|
||||
}
|
||||
c->max_table_size = max_table_size;
|
||||
c->max_table_elems = elems_for_bytes(max_table_size);
|
||||
if (c->max_table_elems > c->cap_table_elems) {
|
||||
rebuild_elems(c, GPR_MAX(c->max_table_elems, 2 * c->cap_table_elems));
|
||||
} else if (c->max_table_elems < c->cap_table_elems / 3) {
|
||||
gpr_uint32 new_cap = GPR_MAX(c->max_table_elems, 16);
|
||||
if (new_cap != c->cap_table_elems) {
|
||||
rebuild_elems(c, new_cap);
|
||||
}
|
||||
}
|
||||
c->advertise_table_size_change = 1;
|
||||
gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size);
|
||||
}
|
||||
|
||||
void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
|
||||
|
|
@ -483,6 +561,9 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
|
|||
slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got
|
||||
updated). After this loop, we'll do a batch unref of elements. */
|
||||
begin_frame(&st);
|
||||
if (c->advertise_table_size_change != 0) {
|
||||
emit_advertise_table_size_change(c, &st);
|
||||
}
|
||||
grpc_metadata_batch_assert_ok(metadata);
|
||||
for (l = metadata->list.head; l; l = l->next) {
|
||||
hpack_enc(c, l->md, &st);
|
||||
|
|
|
|||
|
|
@ -43,14 +43,26 @@
|
|||
|
||||
#define GRPC_CHTTP2_HPACKC_NUM_FILTERS 256
|
||||
#define GRPC_CHTTP2_HPACKC_NUM_VALUES 256
|
||||
#define GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS (4096 / 32)
|
||||
/* initial table size, per spec */
|
||||
#define GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE 4096
|
||||
/* maximum table size we'll actually use */
|
||||
#define GRPC_CHTTP2_HPACKC_MAX_TABLE_SIZE (1024 * 1024)
|
||||
|
||||
typedef struct {
|
||||
gpr_uint32 filter_elems_sum;
|
||||
gpr_uint32 max_table_size;
|
||||
gpr_uint32 max_table_elems;
|
||||
gpr_uint32 cap_table_elems;
|
||||
/** if non-zero, advertise to the decoder that we'll start using a table
|
||||
of this size */
|
||||
gpr_uint8 advertise_table_size_change;
|
||||
/** maximum number of bytes we'll use for the decode table (to guard against
|
||||
peers ooming us by setting decode table size high) */
|
||||
gpr_uint32 max_usable_size;
|
||||
/* one before the lowest usable table index */
|
||||
gpr_uint32 tail_remote_index;
|
||||
gpr_uint16 table_size;
|
||||
gpr_uint16 table_elems;
|
||||
gpr_uint32 table_size;
|
||||
gpr_uint32 table_elems;
|
||||
|
||||
/* filter tables for elems: this tables provides an approximate
|
||||
popularity count for particular hashes, and are used to determine whether
|
||||
|
|
@ -71,12 +83,16 @@ typedef struct {
|
|||
gpr_uint32 indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
|
||||
gpr_uint32 indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
|
||||
|
||||
gpr_uint16 table_elem_size[GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS];
|
||||
gpr_uint16 *table_elem_size;
|
||||
} grpc_chttp2_hpack_compressor;
|
||||
|
||||
void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
|
||||
grpc_mdctx *mdctx);
|
||||
void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c);
|
||||
void grpc_chttp2_hpack_compressor_set_max_table_size(
|
||||
grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size);
|
||||
void grpc_chttp2_hpack_compressor_set_max_usable_size(
|
||||
grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size);
|
||||
|
||||
void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, gpr_uint32 id,
|
||||
grpc_metadata_batch *metadata, int is_eof,
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ static int parse_begin(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
|
|||
const gpr_uint8 *end);
|
||||
static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
|
||||
const gpr_uint8 *end);
|
||||
static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
|
||||
const gpr_uint8 *end);
|
||||
|
||||
static int parse_string_prefix(grpc_chttp2_hpack_parser *p,
|
||||
const gpr_uint8 *cur, const gpr_uint8 *end);
|
||||
|
|
@ -156,7 +158,7 @@ static const grpc_chttp2_hpack_parser_state first_byte_action[] = {
|
|||
parse_lithdr_incidx_x, parse_lithdr_incidx_v, parse_lithdr_notidx,
|
||||
parse_lithdr_notidx_x, parse_lithdr_notidx_v, parse_lithdr_nvridx,
|
||||
parse_lithdr_nvridx_x, parse_lithdr_nvridx_v, parse_max_tbl_size,
|
||||
parse_max_tbl_size_x, parse_error};
|
||||
parse_max_tbl_size_x, parse_illegal_op};
|
||||
|
||||
/* indexes the first byte to a parse state function - generated by
|
||||
gen_hpack_tables.c */
|
||||
|
|
@ -169,7 +171,7 @@ static const gpr_uint8 first_byte_lut[256] = {
|
|||
LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
|
||||
LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
|
||||
LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX_X,
|
||||
ILLEGAL, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
|
||||
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
|
||||
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
|
||||
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
|
||||
MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE,
|
||||
|
|
@ -622,13 +624,15 @@ static const gpr_uint8 inverse_base64[256] = {
|
|||
};
|
||||
|
||||
/* emission helpers */
|
||||
static void on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
|
||||
int add_to_table) {
|
||||
static int on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
|
||||
int add_to_table) {
|
||||
if (add_to_table) {
|
||||
GRPC_MDELEM_REF(md);
|
||||
grpc_chttp2_hptbl_add(&p->table, md);
|
||||
if (!grpc_chttp2_hptbl_add(&p->table, md)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
p->on_header(p->on_header_user_data, md);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
|
||||
|
|
@ -714,9 +718,12 @@ static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
|
|||
static int finish_indexed_field(grpc_chttp2_hpack_parser *p,
|
||||
const gpr_uint8 *cur, const gpr_uint8 *end) {
|
||||
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
|
||||
if (md == NULL) {
|
||||
gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
|
||||
return 0;
|
||||
}
|
||||
GRPC_MDELEM_REF(md);
|
||||
on_hdr(p, md, 0);
|
||||
return parse_begin(p, cur, end);
|
||||
return on_hdr(p, md, 0) && parse_begin(p, cur, end);
|
||||
}
|
||||
|
||||
/* parse an indexed field with index < 127 */
|
||||
|
|
@ -742,21 +749,21 @@ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
|
|||
static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p,
|
||||
const gpr_uint8 *cur, const gpr_uint8 *end) {
|
||||
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
|
||||
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
GRPC_MDSTR_REF(md->key),
|
||||
take_string(p, &p->value)),
|
||||
1);
|
||||
return parse_begin(p, cur, end);
|
||||
return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
GRPC_MDSTR_REF(md->key),
|
||||
take_string(p, &p->value)),
|
||||
1) &&
|
||||
parse_begin(p, cur, end);
|
||||
}
|
||||
|
||||
/* finish a literal header with incremental indexing with no index */
|
||||
static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
|
||||
const gpr_uint8 *cur, const gpr_uint8 *end) {
|
||||
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
take_string(p, &p->key),
|
||||
take_string(p, &p->value)),
|
||||
1);
|
||||
return parse_begin(p, cur, end);
|
||||
return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
take_string(p, &p->key),
|
||||
take_string(p, &p->value)),
|
||||
1) &&
|
||||
parse_begin(p, cur, end);
|
||||
}
|
||||
|
||||
/* parse a literal header with incremental indexing; index < 63 */
|
||||
|
|
@ -795,21 +802,21 @@ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
|
|||
static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p,
|
||||
const gpr_uint8 *cur, const gpr_uint8 *end) {
|
||||
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
|
||||
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
GRPC_MDSTR_REF(md->key),
|
||||
take_string(p, &p->value)),
|
||||
0);
|
||||
return parse_begin(p, cur, end);
|
||||
return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
GRPC_MDSTR_REF(md->key),
|
||||
take_string(p, &p->value)),
|
||||
0) &&
|
||||
parse_begin(p, cur, end);
|
||||
}
|
||||
|
||||
/* finish a literal header without incremental indexing with index = 0 */
|
||||
static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
|
||||
const gpr_uint8 *cur, const gpr_uint8 *end) {
|
||||
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
take_string(p, &p->key),
|
||||
take_string(p, &p->value)),
|
||||
0);
|
||||
return parse_begin(p, cur, end);
|
||||
return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
take_string(p, &p->key),
|
||||
take_string(p, &p->value)),
|
||||
0) &&
|
||||
parse_begin(p, cur, end);
|
||||
}
|
||||
|
||||
/* parse a literal header without incremental indexing; index < 15 */
|
||||
|
|
@ -848,21 +855,21 @@ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
|
|||
static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
|
||||
const gpr_uint8 *cur, const gpr_uint8 *end) {
|
||||
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
|
||||
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
GRPC_MDSTR_REF(md->key),
|
||||
take_string(p, &p->value)),
|
||||
0);
|
||||
return parse_begin(p, cur, end);
|
||||
return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
GRPC_MDSTR_REF(md->key),
|
||||
take_string(p, &p->value)),
|
||||
0) &&
|
||||
parse_begin(p, cur, end);
|
||||
}
|
||||
|
||||
/* finish a literal header that is never indexed with an extra value */
|
||||
static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
|
||||
const gpr_uint8 *cur, const gpr_uint8 *end) {
|
||||
on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
take_string(p, &p->key),
|
||||
take_string(p, &p->value)),
|
||||
0);
|
||||
return parse_begin(p, cur, end);
|
||||
return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
|
||||
take_string(p, &p->key),
|
||||
take_string(p, &p->value)),
|
||||
0) &&
|
||||
parse_begin(p, cur, end);
|
||||
}
|
||||
|
||||
/* parse a literal header that is never indexed; index < 15 */
|
||||
|
|
@ -901,14 +908,14 @@ static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
|
|||
static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p,
|
||||
const gpr_uint8 *cur, const gpr_uint8 *end) {
|
||||
gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
|
||||
abort(); /* not implemented */
|
||||
return parse_begin(p, cur, end);
|
||||
return grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index) &&
|
||||
parse_begin(p, cur, end);
|
||||
}
|
||||
|
||||
/* parse a max table size change, max size < 15 */
|
||||
static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
|
||||
const gpr_uint8 *end) {
|
||||
p->index = (*cur) & 0xf;
|
||||
p->index = (*cur) & 0x1f;
|
||||
return finish_max_tbl_size(p, cur + 1, end);
|
||||
}
|
||||
|
||||
|
|
@ -918,7 +925,7 @@ static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
|
|||
static const grpc_chttp2_hpack_parser_state and_then[] = {
|
||||
finish_max_tbl_size};
|
||||
p->next_state = and_then;
|
||||
p->index = 0xf;
|
||||
p->index = 0x1f;
|
||||
p->parsing.value = &p->index;
|
||||
return parse_value0(p, cur + 1, end);
|
||||
}
|
||||
|
|
@ -930,6 +937,13 @@ static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
|
||||
const gpr_uint8 *end) {
|
||||
GPR_ASSERT(cur != end);
|
||||
gpr_log(GPR_DEBUG, "Illegal hpack op code %d", *cur);
|
||||
return parse_error(p, cur, end);
|
||||
}
|
||||
|
||||
/* parse the 1st byte of a varint into p->parsing.value
|
||||
no overflow is possible */
|
||||
static int parse_value0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
|
||||
#include "src/core/support/murmur_hash.h"
|
||||
|
||||
static struct {
|
||||
|
|
@ -169,12 +171,22 @@ static struct {
|
|||
{"www-authenticate", ""},
|
||||
};
|
||||
|
||||
static gpr_uint32 entries_for_bytes(gpr_uint32 bytes) {
|
||||
return (bytes + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) /
|
||||
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
|
||||
}
|
||||
|
||||
void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx) {
|
||||
size_t i;
|
||||
|
||||
memset(tbl, 0, sizeof(*tbl));
|
||||
tbl->mdctx = mdctx;
|
||||
tbl->max_bytes = GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
|
||||
tbl->current_table_bytes = tbl->max_bytes =
|
||||
GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
|
||||
tbl->max_entries = tbl->cap_entries =
|
||||
entries_for_bytes(tbl->current_table_bytes);
|
||||
tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries);
|
||||
memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries);
|
||||
for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
|
||||
tbl->static_ents[i - 1] = grpc_mdelem_from_strings(
|
||||
mdctx, static_table[i].key, static_table[i].value);
|
||||
|
|
@ -187,9 +199,9 @@ void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) {
|
|||
GRPC_MDELEM_UNREF(tbl->static_ents[i]);
|
||||
}
|
||||
for (i = 0; i < tbl->num_ents; i++) {
|
||||
GRPC_MDELEM_UNREF(
|
||||
tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]);
|
||||
GRPC_MDELEM_UNREF(tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]);
|
||||
}
|
||||
gpr_free(tbl->ents);
|
||||
}
|
||||
|
||||
grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
|
||||
|
|
@ -201,8 +213,8 @@ grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
|
|||
/* Otherwise, find the value in the list of valid entries */
|
||||
tbl_index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1);
|
||||
if (tbl_index < tbl->num_ents) {
|
||||
gpr_uint32 offset = (tbl->num_ents - 1u - tbl_index + tbl->first_ent) %
|
||||
GRPC_CHTTP2_MAX_TABLE_COUNT;
|
||||
gpr_uint32 offset =
|
||||
(tbl->num_ents - 1u - tbl_index + tbl->first_ent) % tbl->cap_entries;
|
||||
return tbl->ents[offset];
|
||||
}
|
||||
/* Invalid entry: return error */
|
||||
|
|
@ -216,21 +228,81 @@ static void evict1(grpc_chttp2_hptbl *tbl) {
|
|||
GPR_SLICE_LENGTH(first_ent->value->slice) +
|
||||
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
|
||||
GPR_ASSERT(elem_bytes <= tbl->mem_used);
|
||||
tbl->mem_used = (gpr_uint16)(tbl->mem_used - elem_bytes);
|
||||
tbl->first_ent =
|
||||
(gpr_uint16)((tbl->first_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT);
|
||||
tbl->mem_used -= (gpr_uint32)elem_bytes;
|
||||
tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries);
|
||||
tbl->num_ents--;
|
||||
GRPC_MDELEM_UNREF(first_ent);
|
||||
}
|
||||
|
||||
void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
|
||||
static void rebuild_ents(grpc_chttp2_hptbl *tbl, gpr_uint32 new_cap) {
|
||||
grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap);
|
||||
gpr_uint32 i;
|
||||
|
||||
for (i = 0; i < tbl->num_ents; i++) {
|
||||
ents[i] = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
|
||||
}
|
||||
gpr_free(tbl->ents);
|
||||
tbl->ents = ents;
|
||||
tbl->cap_entries = new_cap;
|
||||
tbl->first_ent = 0;
|
||||
}
|
||||
|
||||
void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
|
||||
gpr_uint32 max_bytes) {
|
||||
if (tbl->max_bytes == max_bytes) {
|
||||
return;
|
||||
}
|
||||
gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes);
|
||||
while (tbl->mem_used > max_bytes) {
|
||||
evict1(tbl);
|
||||
}
|
||||
tbl->max_bytes = max_bytes;
|
||||
}
|
||||
|
||||
int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
|
||||
gpr_uint32 bytes) {
|
||||
if (tbl->current_table_bytes == bytes) {
|
||||
return 1;
|
||||
}
|
||||
if (bytes > tbl->max_bytes) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"Attempt to make hpack table %d bytes when max is %d bytes", bytes,
|
||||
tbl->max_bytes);
|
||||
return 0;
|
||||
}
|
||||
gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
|
||||
while (tbl->mem_used > bytes) {
|
||||
evict1(tbl);
|
||||
}
|
||||
tbl->current_table_bytes = bytes;
|
||||
tbl->max_entries = entries_for_bytes(bytes);
|
||||
if (tbl->max_entries > tbl->cap_entries) {
|
||||
rebuild_ents(tbl, GPR_MAX(tbl->max_entries, 2 * tbl->cap_entries));
|
||||
} else if (tbl->max_entries < tbl->cap_entries / 3) {
|
||||
gpr_uint32 new_cap = GPR_MAX(tbl->max_entries, 16u);
|
||||
if (new_cap != tbl->cap_entries) {
|
||||
rebuild_ents(tbl, new_cap);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
|
||||
/* determine how many bytes of buffer this entry represents */
|
||||
size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
|
||||
GPR_SLICE_LENGTH(md->value->slice) +
|
||||
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
|
||||
|
||||
if (tbl->current_table_bytes > tbl->max_bytes) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"HPACK max table size reduced to %d but not reflected by hpack "
|
||||
"stream (still at %d)",
|
||||
tbl->max_bytes, tbl->current_table_bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we can't add elements bigger than the max table size */
|
||||
if (elem_bytes > tbl->max_bytes) {
|
||||
if (elem_bytes > tbl->current_table_bytes) {
|
||||
/* HPACK draft 10 section 4.4 states:
|
||||
* If the size of the new entry is less than or equal to the maximum
|
||||
* size, that entry is added to the table. It is not an error to
|
||||
|
|
@ -243,44 +315,43 @@ void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
|
|||
while (tbl->num_ents) {
|
||||
evict1(tbl);
|
||||
}
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* evict entries to ensure no overflow */
|
||||
while (elem_bytes > (size_t)tbl->max_bytes - tbl->mem_used) {
|
||||
while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) {
|
||||
evict1(tbl);
|
||||
}
|
||||
|
||||
/* copy the finalized entry in */
|
||||
tbl->ents[tbl->last_ent] = md;
|
||||
tbl->ents[(tbl->first_ent + tbl->num_ents) % tbl->cap_entries] =
|
||||
GRPC_MDELEM_REF(md);
|
||||
|
||||
/* update accounting values */
|
||||
tbl->last_ent =
|
||||
(gpr_uint16)((tbl->last_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT);
|
||||
tbl->num_ents++;
|
||||
tbl->mem_used = (gpr_uint16)(tbl->mem_used + elem_bytes);
|
||||
tbl->mem_used += (gpr_uint32)elem_bytes;
|
||||
return 1;
|
||||
}
|
||||
|
||||
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
|
||||
const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
|
||||
grpc_chttp2_hptbl_find_result r = {0, 0};
|
||||
gpr_uint16 i;
|
||||
gpr_uint32 i;
|
||||
|
||||
/* See if the string is in the static table */
|
||||
for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
|
||||
grpc_mdelem *ent = tbl->static_ents[i];
|
||||
if (md->key != ent->key) continue;
|
||||
r.index = (gpr_uint16)(i + 1);
|
||||
r.index = i + 1u;
|
||||
r.has_value = md->value == ent->value;
|
||||
if (r.has_value) return r;
|
||||
}
|
||||
|
||||
/* Scan the dynamic table */
|
||||
for (i = 0; i < tbl->num_ents; i++) {
|
||||
gpr_uint16 idx =
|
||||
(gpr_uint16)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
|
||||
grpc_mdelem *ent =
|
||||
tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT];
|
||||
gpr_uint32 idx =
|
||||
(gpr_uint32)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
|
||||
grpc_mdelem *ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
|
||||
if (md->key != ent->key) continue;
|
||||
r.index = idx;
|
||||
r.has_value = md->value == ent->value;
|
||||
|
|
|
|||
|
|
@ -49,47 +49,59 @@
|
|||
#define GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE
|
||||
/* Per entry overhead bytes as per the spec */
|
||||
#define GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD 32
|
||||
#if 0
|
||||
/* Maximum number of entries we could possibly fit in the table, given defined
|
||||
overheads */
|
||||
#define GRPC_CHTTP2_MAX_TABLE_COUNT \
|
||||
((GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / \
|
||||
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD)
|
||||
#endif
|
||||
|
||||
/* hpack decoder table */
|
||||
typedef struct {
|
||||
grpc_mdctx *mdctx;
|
||||
/* the first used entry in ents */
|
||||
gpr_uint16 first_ent;
|
||||
/* the last used entry in ents */
|
||||
gpr_uint16 last_ent;
|
||||
gpr_uint32 first_ent;
|
||||
/* how many entries are in the table */
|
||||
gpr_uint16 num_ents;
|
||||
gpr_uint32 num_ents;
|
||||
/* the amount of memory used by the table, according to the hpack algorithm */
|
||||
gpr_uint16 mem_used;
|
||||
gpr_uint32 mem_used;
|
||||
/* the max memory allowed to be used by the table, according to the hpack
|
||||
algorithm */
|
||||
gpr_uint16 max_bytes;
|
||||
gpr_uint32 max_bytes;
|
||||
/* the currently agreed size of the table, according to the hpack algorithm */
|
||||
gpr_uint32 current_table_bytes;
|
||||
/* Maximum number of entries we could possibly fit in the table, given defined
|
||||
overheads */
|
||||
gpr_uint32 max_entries;
|
||||
/* Number of entries allocated in ents */
|
||||
gpr_uint32 cap_entries;
|
||||
/* a circular buffer of headers - this is stored in the opposite order to
|
||||
what hpack specifies, in order to simplify table management a little...
|
||||
meaning lookups need to SUBTRACT from the end position */
|
||||
grpc_mdelem *ents[GRPC_CHTTP2_MAX_TABLE_COUNT];
|
||||
grpc_mdelem **ents;
|
||||
grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY];
|
||||
} grpc_chttp2_hptbl;
|
||||
|
||||
/* initialize a hpack table */
|
||||
void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx);
|
||||
void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl);
|
||||
void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
|
||||
gpr_uint32 max_bytes);
|
||||
int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
|
||||
gpr_uint32 bytes);
|
||||
|
||||
/* lookup a table entry based on its hpack index */
|
||||
grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
|
||||
gpr_uint32 index);
|
||||
/* add a table entry to the index */
|
||||
void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md);
|
||||
int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
|
||||
grpc_mdelem *md) GRPC_MUST_USE_RESULT;
|
||||
/* Find a key/value pair in the table... returns the index in the table of the
|
||||
most similar entry, or 0 if the value was not found */
|
||||
typedef struct {
|
||||
gpr_uint16 index;
|
||||
gpr_uint8 has_value;
|
||||
gpr_uint32 index;
|
||||
int has_value;
|
||||
} grpc_chttp2_hptbl_find_result;
|
||||
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
|
||||
const grpc_chttp2_hptbl *tbl, grpc_mdelem *md);
|
||||
|
|
|
|||
|
|
@ -227,6 +227,9 @@ struct grpc_chttp2_transport_parsing {
|
|||
/** was a goaway frame received? */
|
||||
gpr_uint8 goaway_received;
|
||||
|
||||
/** the last sent max_table_size setting */
|
||||
gpr_uint32 last_sent_max_table_size;
|
||||
|
||||
/** initial window change */
|
||||
gpr_int64 initial_window_update;
|
||||
|
||||
|
|
@ -483,7 +486,8 @@ struct grpc_chttp2_stream {
|
|||
/** Someone is unlocking the transport mutex: check to see if writes
|
||||
are required, and schedule them if so */
|
||||
int grpc_chttp2_unlocking_check_writes(grpc_chttp2_transport_global *global,
|
||||
grpc_chttp2_transport_writing *writing);
|
||||
grpc_chttp2_transport_writing *writing,
|
||||
int is_parsing);
|
||||
void grpc_chttp2_perform_writes(
|
||||
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
|
||||
grpc_endpoint *endpoint);
|
||||
|
|
|
|||
|
|
@ -78,6 +78,9 @@ void grpc_chttp2_prepare_to_read(
|
|||
GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0);
|
||||
|
||||
transport_parsing->next_stream_id = transport_global->next_stream_id;
|
||||
transport_parsing->last_sent_max_table_size =
|
||||
transport_global->settings[GRPC_SENT_SETTINGS]
|
||||
[GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE];
|
||||
|
||||
/* update the parsing view of incoming window */
|
||||
while (grpc_chttp2_list_pop_unannounced_incoming_window_available(
|
||||
|
|
@ -127,6 +130,7 @@ void grpc_chttp2_publish_reads(
|
|||
transport_global->settings[GRPC_SENT_SETTINGS],
|
||||
GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
|
||||
transport_parsing->settings_ack_received = 0;
|
||||
transport_global->sent_local_settings = 0;
|
||||
}
|
||||
|
||||
/* move goaway to the global state if we received one (it will be
|
||||
|
|
@ -819,6 +823,9 @@ static int init_settings_frame_parser(
|
|||
}
|
||||
if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
|
||||
transport_parsing->settings_ack_received = 1;
|
||||
grpc_chttp2_hptbl_set_max_bytes(
|
||||
&transport_parsing->hpack_parser.table,
|
||||
transport_parsing->last_sent_max_table_size);
|
||||
}
|
||||
transport_parsing->parser = grpc_chttp2_settings_parser_parse;
|
||||
transport_parsing->parser_data = &transport_parsing->simple.settings;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
|
|||
|
||||
int grpc_chttp2_unlocking_check_writes(
|
||||
grpc_chttp2_transport_global *transport_global,
|
||||
grpc_chttp2_transport_writing *transport_writing) {
|
||||
grpc_chttp2_transport_writing *transport_writing, int is_parsing) {
|
||||
grpc_chttp2_stream_global *stream_global;
|
||||
grpc_chttp2_stream_writing *stream_writing;
|
||||
|
||||
|
|
@ -55,8 +55,13 @@ int grpc_chttp2_unlocking_check_writes(
|
|||
gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
|
||||
GPR_ASSERT(transport_global->qbuf.count == 0);
|
||||
|
||||
grpc_chttp2_hpack_compressor_set_max_table_size(
|
||||
&transport_writing->hpack_compressor,
|
||||
transport_global->settings[GRPC_PEER_SETTINGS]
|
||||
[GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
|
||||
|
||||
if (transport_global->dirtied_local_settings &&
|
||||
!transport_global->sent_local_settings) {
|
||||
!transport_global->sent_local_settings && !is_parsing) {
|
||||
gpr_slice_buffer_add(
|
||||
&transport_writing->outbuf,
|
||||
grpc_chttp2_settings_create(
|
||||
|
|
|
|||
|
|
@ -338,6 +338,31 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
|
|||
t->global.next_stream_id =
|
||||
(gpr_uint32)channel_args->args[i].value.integer;
|
||||
}
|
||||
} else if (0 == strcmp(channel_args->args[i].key,
|
||||
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) {
|
||||
if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
|
||||
gpr_log(GPR_ERROR, "%s: must be an integer",
|
||||
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
|
||||
} else if (channel_args->args[i].value.integer < 0) {
|
||||
gpr_log(GPR_DEBUG, "%s: must be non-negative",
|
||||
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
|
||||
} else {
|
||||
push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
|
||||
(gpr_uint32)channel_args->args[i].value.integer);
|
||||
}
|
||||
} else if (0 == strcmp(channel_args->args[i].key,
|
||||
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) {
|
||||
if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
|
||||
gpr_log(GPR_ERROR, "%s: must be an integer",
|
||||
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
|
||||
} else if (channel_args->args[i].value.integer < 0) {
|
||||
gpr_log(GPR_DEBUG, "%s: must be non-negative",
|
||||
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
|
||||
} else {
|
||||
grpc_chttp2_hpack_compressor_set_max_usable_size(
|
||||
&t->writing.hpack_compressor,
|
||||
(gpr_uint32)channel_args->args[i].value.integer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -563,7 +588,8 @@ static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
|
|||
static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
|
||||
GPR_TIMER_BEGIN("unlock", 0);
|
||||
if (!t->writing_active && !t->closed &&
|
||||
grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) {
|
||||
grpc_chttp2_unlocking_check_writes(&t->global, &t->writing,
|
||||
t->parsing_active)) {
|
||||
t->writing_active = 1;
|
||||
REF_TRANSPORT(t, "writing");
|
||||
grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, 1);
|
||||
|
|
@ -735,6 +761,8 @@ static int contains_non_ok_status(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, int success) {}
|
||||
|
||||
static void perform_stream_op_locked(
|
||||
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
|
||||
grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
|
||||
|
|
@ -743,6 +771,9 @@ static void perform_stream_op_locked(
|
|||
GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
|
||||
|
||||
on_complete = op->on_complete;
|
||||
if (on_complete == NULL) {
|
||||
on_complete = grpc_closure_create(do_nothing, NULL);
|
||||
}
|
||||
/* use final_data as a barrier until enqueue time; the inital counter is
|
||||
dropped at the end of this function */
|
||||
on_complete->final_data = 2;
|
||||
|
|
@ -806,7 +837,7 @@ static void perform_stream_op_locked(
|
|||
}
|
||||
if (stream_global->write_closed) {
|
||||
grpc_chttp2_complete_closure_step(
|
||||
exec_ctx, &stream_global->send_trailing_metadata_finished,
|
||||
exec_ctx, &stream_global->send_trailing_metadata_finished,
|
||||
grpc_metadata_batch_is_empty(op->send_trailing_metadata));
|
||||
} else if (stream_global->id != 0) {
|
||||
/* TODO(ctiller): check if there's flow control for any outstanding
|
||||
|
|
@ -1033,7 +1064,8 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
|
|||
to the upper layers - drop what we've got, and then publish
|
||||
what we want - which is safe because we haven't told anyone
|
||||
about the metadata yet */
|
||||
if (!stream_global->published_trailing_metadata || stream_global->recv_trailing_metadata_finished != NULL) {
|
||||
if (!stream_global->published_trailing_metadata ||
|
||||
stream_global->recv_trailing_metadata_finished != NULL) {
|
||||
grpc_mdctx *mdctx =
|
||||
TRANSPORT_FROM_GLOBAL(transport_global)->metadata_context;
|
||||
char status_string[GPR_LTOA_MIN_BUFSIZE];
|
||||
|
|
|
|||
|
|
@ -54,7 +54,9 @@ class InsecureChannelCredentialsImpl GRPC_FINAL : public ChannelCredentials {
|
|||
grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr));
|
||||
}
|
||||
|
||||
SecureChannelCredentials* AsSecureCredentials() GRPC_OVERRIDE { return nullptr; }
|
||||
SecureChannelCredentials* AsSecureCredentials() GRPC_OVERRIDE {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ class SecureCallCredentials GRPC_FINAL : public CallCredentials {
|
|||
grpc_call_credentials* const c_creds_;
|
||||
};
|
||||
|
||||
|
||||
class MetadataCredentialsPluginWrapper GRPC_FINAL {
|
||||
public:
|
||||
static void Destroy(void* wrapper);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ namespace Grpc.Core.Profiling
|
|||
internal interface IProfiler
|
||||
{
|
||||
void Begin(string tag);
|
||||
|
||||
void End(string tag);
|
||||
|
||||
void Mark(string tag);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ namespace Grpc.Core.Profiling
|
|||
{
|
||||
internal struct ProfilerEntry
|
||||
{
|
||||
public enum Type {
|
||||
public enum Type
|
||||
{
|
||||
BEGIN,
|
||||
END,
|
||||
MARK
|
||||
|
|
|
|||
|
|
@ -40,12 +40,12 @@ namespace Grpc.Core.Profiling
|
|||
{
|
||||
internal static class Profilers
|
||||
{
|
||||
static readonly NopProfiler defaultProfiler = new NopProfiler();
|
||||
static readonly NopProfiler DefaultProfiler = new NopProfiler();
|
||||
static readonly ThreadLocal<IProfiler> profilers = new ThreadLocal<IProfiler>();
|
||||
|
||||
public static IProfiler ForCurrentThread()
|
||||
{
|
||||
return profilers.Value ?? defaultProfiler;
|
||||
return profilers.Value ?? DefaultProfiler;
|
||||
}
|
||||
|
||||
public static void SetForCurrentThread(IProfiler profiler)
|
||||
|
|
@ -89,15 +89,18 @@ namespace Grpc.Core.Profiling
|
|||
this.entries = new ProfilerEntry[capacity];
|
||||
}
|
||||
|
||||
public void Begin(string tag) {
|
||||
public void Begin(string tag)
|
||||
{
|
||||
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.BEGIN, tag));
|
||||
}
|
||||
|
||||
public void End(string tag) {
|
||||
public void End(string tag)
|
||||
{
|
||||
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.END, tag));
|
||||
}
|
||||
|
||||
public void Mark(string tag) {
|
||||
public void Mark(string tag)
|
||||
{
|
||||
AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.MARK, tag));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
bin
|
||||
obj
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Grpc.IntegrationTesting.QpsWorker</RootNamespace>
|
||||
<AssemblyName>Grpc.IntegrationTesting.QpsWorker</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\ReleaseSigned</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Grpc.Core\Version.cs">
|
||||
<Link>Version.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
|
||||
<Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
|
||||
<Name>Grpc.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj">
|
||||
<Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
|
||||
<Name>Grpc.IntegrationTesting</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#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;
|
||||
using Grpc.IntegrationTesting;
|
||||
|
||||
namespace Grpc.IntegrationTesting
|
||||
{
|
||||
class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
QpsWorker.Run(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyTitle("Grpc.IntegrationTesting.QpsWorker")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
|
||||
namespace Grpc.Testing
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of BenchmarkService server
|
||||
/// </summary>
|
||||
public class BenchmarkServiceImpl : BenchmarkService.IBenchmarkService
|
||||
{
|
||||
private readonly int responseSize;
|
||||
|
||||
public BenchmarkServiceImpl(int responseSize)
|
||||
{
|
||||
this.responseSize = responseSize;
|
||||
}
|
||||
|
||||
public Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
|
||||
{
|
||||
var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
|
||||
public async Task StreamingCall(IAsyncStreamReader<SimpleRequest> requestStream, IServerStreamWriter<SimpleResponse> responseStream, ServerCallContext context)
|
||||
{
|
||||
await requestStream.ForEachAsync(async request =>
|
||||
{
|
||||
var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
|
||||
await responseStream.WriteAsync(response);
|
||||
});
|
||||
}
|
||||
|
||||
private static Payload CreateZerosPayload(int size)
|
||||
{
|
||||
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
using NUnit.Framework;
|
||||
using Grpc.Testing;
|
||||
|
||||
namespace Grpc.IntegrationTesting
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper methods to start client runners for performance testing.
|
||||
/// </summary>
|
||||
public static class ClientRunners
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a started client runner.
|
||||
/// </summary>
|
||||
public static IClientRunner CreateStarted(ClientConfig config)
|
||||
{
|
||||
string target = config.ServerTargets.Single();
|
||||
Grpc.Core.Utils.Preconditions.CheckArgument(config.LoadParams.LoadCase == LoadParams.LoadOneofCase.ClosedLoop);
|
||||
|
||||
var credentials = config.SecurityParams != null ? TestCredentials.CreateSslCredentials() : ChannelCredentials.Insecure;
|
||||
var channel = new Channel(target, credentials);
|
||||
|
||||
switch (config.RpcType)
|
||||
{
|
||||
case RpcType.UNARY:
|
||||
return new SyncUnaryClientRunner(channel,
|
||||
config.PayloadConfig.SimpleParams.ReqSize,
|
||||
config.HistogramParams);
|
||||
|
||||
case RpcType.STREAMING:
|
||||
default:
|
||||
throw new ArgumentException("Unsupported RpcType.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Client that starts synchronous unary calls in a closed loop.
|
||||
/// </summary>
|
||||
public class SyncUnaryClientRunner : IClientRunner
|
||||
{
|
||||
const double SecondsToNanos = 1e9;
|
||||
|
||||
readonly Channel channel;
|
||||
readonly int payloadSize;
|
||||
readonly Histogram histogram;
|
||||
|
||||
readonly BenchmarkService.IBenchmarkServiceClient client;
|
||||
readonly Task runnerTask;
|
||||
readonly CancellationTokenSource stoppedCts;
|
||||
readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
|
||||
|
||||
public SyncUnaryClientRunner(Channel channel, int payloadSize, HistogramParams histogramParams)
|
||||
{
|
||||
this.channel = Grpc.Core.Utils.Preconditions.CheckNotNull(channel);
|
||||
this.payloadSize = payloadSize;
|
||||
this.histogram = new Histogram(histogramParams.Resolution, histogramParams.MaxPossible);
|
||||
|
||||
this.stoppedCts = new CancellationTokenSource();
|
||||
this.client = BenchmarkService.NewClient(channel);
|
||||
this.runnerTask = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
public ClientStats GetStats(bool reset)
|
||||
{
|
||||
var histogramData = histogram.GetSnapshot(reset);
|
||||
var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds;
|
||||
|
||||
// TODO: populate user time and system time
|
||||
return new ClientStats
|
||||
{
|
||||
Latencies = histogramData,
|
||||
TimeElapsed = secondsElapsed,
|
||||
TimeUser = 0,
|
||||
TimeSystem = 0
|
||||
};
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
{
|
||||
stoppedCts.Cancel();
|
||||
await runnerTask;
|
||||
await channel.ShutdownAsync();
|
||||
}
|
||||
|
||||
private void Run()
|
||||
{
|
||||
var request = new SimpleRequest
|
||||
{
|
||||
Payload = CreateZerosPayload(payloadSize)
|
||||
};
|
||||
var stopwatch = new Stopwatch();
|
||||
|
||||
while (!stoppedCts.Token.IsCancellationRequested)
|
||||
{
|
||||
stopwatch.Restart();
|
||||
client.UnaryCall(request);
|
||||
stopwatch.Stop();
|
||||
|
||||
// spec requires data point in nanoseconds.
|
||||
histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
|
||||
}
|
||||
}
|
||||
|
||||
private static Payload CreateZerosPayload(int size)
|
||||
{
|
||||
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -38,45 +38,9 @@
|
|||
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CommandLine">
|
||||
<HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework">
|
||||
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
|
||||
</Reference>
|
||||
|
|
@ -87,6 +51,33 @@
|
|||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
<Reference Include="BouncyCastle.Crypto">
|
||||
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Google.Apis.Auth">
|
||||
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Google.Apis.Auth.PlatformServices">
|
||||
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Google.Apis.Core">
|
||||
<HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Google.Protobuf">
|
||||
<HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks">
|
||||
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks.Extensions">
|
||||
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
|
||||
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Grpc.Core\Version.cs">
|
||||
|
|
@ -104,6 +95,22 @@
|
|||
<Compile Include="TestGrpc.cs" />
|
||||
<Compile Include="SslCredentialsTest.cs" />
|
||||
<Compile Include="Test.cs" />
|
||||
<Compile Include="IClientRunner.cs" />
|
||||
<Compile Include="ClientRunners.cs" />
|
||||
<Compile Include="IServerRunner.cs" />
|
||||
<Compile Include="ServerRunners.cs" />
|
||||
<Compile Include="RunnerClientServerTest.cs" />
|
||||
<Compile Include="Control.cs" />
|
||||
<Compile Include="Payloads.cs" />
|
||||
<Compile Include="Services.cs" />
|
||||
<Compile Include="ServicesGrpc.cs" />
|
||||
<Compile Include="Stats.cs" />
|
||||
<Compile Include="BenchmarkServiceImpl.cs" />
|
||||
<Compile Include="Histogram.cs" />
|
||||
<Compile Include="HistogramTest.cs" />
|
||||
<Compile Include="WorkerServiceImpl.cs" />
|
||||
<Compile Include="QpsWorker.cs" />
|
||||
<Compile Include="WallClockStopwatch.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
using NUnit.Framework;
|
||||
using Grpc.Testing;
|
||||
|
||||
namespace Grpc.IntegrationTesting
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic implementation of histogram based on grpc/support/histogram.h.
|
||||
/// </summary>
|
||||
public class Histogram
|
||||
{
|
||||
readonly object myLock = new object();
|
||||
readonly double multiplier;
|
||||
readonly double oneOnLogMultiplier;
|
||||
readonly double maxPossible;
|
||||
readonly uint[] buckets;
|
||||
|
||||
int count;
|
||||
double sum;
|
||||
double sumOfSquares;
|
||||
double min;
|
||||
double max;
|
||||
|
||||
public Histogram(double resolution, double maxPossible)
|
||||
{
|
||||
Grpc.Core.Utils.Preconditions.CheckArgument(resolution > 0);
|
||||
Grpc.Core.Utils.Preconditions.CheckArgument(maxPossible > 0);
|
||||
this.maxPossible = maxPossible;
|
||||
this.multiplier = 1.0 + resolution;
|
||||
this.oneOnLogMultiplier = 1.0 / Math.Log(1.0 + resolution);
|
||||
this.buckets = new uint[FindBucket(maxPossible) + 1];
|
||||
|
||||
ResetUnsafe();
|
||||
}
|
||||
|
||||
public void AddObservation(double value)
|
||||
{
|
||||
lock (myLock)
|
||||
{
|
||||
AddObservationUnsafe(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets snapshot of stats and reset
|
||||
/// </summary>
|
||||
public HistogramData GetSnapshot(bool reset = false)
|
||||
{
|
||||
lock (myLock)
|
||||
{
|
||||
return GetSnapshotUnsafe(reset);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds bucket index to which given observation should go.
|
||||
/// </summary>
|
||||
private int FindBucket(double value)
|
||||
{
|
||||
value = Math.Max(value, 1.0);
|
||||
value = Math.Min(value, this.maxPossible);
|
||||
return (int)(Math.Log(value) * oneOnLogMultiplier);
|
||||
}
|
||||
|
||||
private void AddObservationUnsafe(double value)
|
||||
{
|
||||
this.count++;
|
||||
this.sum += value;
|
||||
this.sumOfSquares += value * value;
|
||||
this.min = Math.Min(this.min, value);
|
||||
this.max = Math.Max(this.max, value);
|
||||
|
||||
this.buckets[FindBucket(value)]++;
|
||||
}
|
||||
|
||||
private HistogramData GetSnapshotUnsafe(bool reset)
|
||||
{
|
||||
var data = new HistogramData
|
||||
{
|
||||
Count = count,
|
||||
Sum = sum,
|
||||
SumOfSquares = sumOfSquares,
|
||||
MinSeen = min,
|
||||
MaxSeen = max,
|
||||
Bucket = { buckets }
|
||||
};
|
||||
|
||||
if (reset)
|
||||
{
|
||||
ResetUnsafe();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void ResetUnsafe()
|
||||
{
|
||||
this.count = 0;
|
||||
this.sum = 0;
|
||||
this.sumOfSquares = 0;
|
||||
this.min = double.PositiveInfinity;
|
||||
this.max = double.NegativeInfinity;
|
||||
for (int i = 0; i < this.buckets.Length; i++)
|
||||
{
|
||||
this.buckets[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
using Grpc.Testing;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Grpc.IntegrationTesting
|
||||
{
|
||||
public class HistogramTest
|
||||
{
|
||||
[Test]
|
||||
public void Simple()
|
||||
{
|
||||
var hist = new Histogram(0.01, 60e9);
|
||||
hist.AddObservation(10000);
|
||||
hist.AddObservation(10000);
|
||||
hist.AddObservation(11000);
|
||||
hist.AddObservation(11000);
|
||||
|
||||
var data = hist.GetSnapshot();
|
||||
|
||||
Assert.AreEqual(4, data.Count);
|
||||
Assert.AreEqual(42000.0, data.Sum, 1e-6);
|
||||
Assert.AreEqual(10000, data.MinSeen);
|
||||
Assert.AreEqual(11000, data.MaxSeen);
|
||||
Assert.AreEqual(2.0*10000*10000 + 2.0*11000*11000, data.SumOfSquares, 1e-6);
|
||||
|
||||
// 1.01^925 < 10000 < 1.01^926
|
||||
Assert.AreEqual(2, data.Bucket[925]);
|
||||
Assert.AreEqual(2, data.Bucket[935]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtremeObservations()
|
||||
{
|
||||
var hist = new Histogram(0.01, 60e9);
|
||||
hist.AddObservation(-0.5); // should be in the first bucket
|
||||
hist.AddObservation(1e12); // should be in the last bucket
|
||||
|
||||
var data = hist.GetSnapshot();
|
||||
Assert.AreEqual(1, data.Bucket[0]);
|
||||
Assert.AreEqual(1, data.Bucket[data.Bucket.Count - 1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reset()
|
||||
{
|
||||
var hist = new Histogram(0.01, 60e9);
|
||||
hist.AddObservation(10000);
|
||||
hist.AddObservation(11000);
|
||||
|
||||
var data = hist.GetSnapshot(true); // snapshot contains data before reset
|
||||
Assert.AreEqual(2, data.Count);
|
||||
Assert.AreEqual(10000, data.MinSeen);
|
||||
Assert.AreEqual(11000, data.MaxSeen);
|
||||
|
||||
data = hist.GetSnapshot(); // snapshot contains state after reset
|
||||
Assert.AreEqual(0, data.Count);
|
||||
Assert.AreEqual(double.PositiveInfinity, data.MinSeen);
|
||||
Assert.AreEqual(double.NegativeInfinity, data.MaxSeen);
|
||||
Assert.AreEqual(0, data.Sum);
|
||||
Assert.AreEqual(0, data.SumOfSquares);
|
||||
CollectionAssert.AreEqual(new uint[data.Bucket.Count], data.Bucket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
using NUnit.Framework;
|
||||
using Grpc.Testing;
|
||||
|
||||
namespace Grpc.IntegrationTesting
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract client runner.
|
||||
/// </summary>
|
||||
public interface IClientRunner
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets stats snapshot.
|
||||
/// </summary>
|
||||
/// <returns>The stats.</returns>
|
||||
ClientStats GetStats(bool reset);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously stops the client.
|
||||
/// </summary>
|
||||
/// <returns>Task that finishes when client has come to a full stop.</returns>
|
||||
Task StopAsync();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
using NUnit.Framework;
|
||||
using Grpc.Testing;
|
||||
|
||||
namespace Grpc.IntegrationTesting
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract server runner.
|
||||
/// </summary>
|
||||
public interface IServerRunner
|
||||
{
|
||||
/// <summary>
|
||||
/// Port on which the server is listening.
|
||||
/// </summary>
|
||||
int BoundPort { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets server stats.
|
||||
/// </summary>
|
||||
/// <returns>The stats.</returns>
|
||||
ServerStats GetStats(bool reset);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously stops the server.
|
||||
/// </summary>
|
||||
/// <returns>Task that finishes when server has shutdown.</returns>
|
||||
Task StopAsync();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,580 @@
|
|||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: test/proto/benchmarks/payloads.proto
|
||||
#pragma warning disable 1591, 0612, 3021
|
||||
#region Designer generated code
|
||||
|
||||
using pb = global::Google.Protobuf;
|
||||
using pbc = global::Google.Protobuf.Collections;
|
||||
using pbr = global::Google.Protobuf.Reflection;
|
||||
using scg = global::System.Collections.Generic;
|
||||
namespace Grpc.Testing {
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public static partial class Payloads {
|
||||
|
||||
#region Descriptor
|
||||
public static pbr::FileDescriptor Descriptor {
|
||||
get { return descriptor; }
|
||||
}
|
||||
private static pbr::FileDescriptor descriptor;
|
||||
|
||||
static Payloads() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"CiR0ZXN0L3Byb3RvL2JlbmNobWFya3MvcGF5bG9hZHMucHJvdG8SDGdycGMu",
|
||||
"dGVzdGluZyI3ChBCeXRlQnVmZmVyUGFyYW1zEhAKCHJlcV9zaXplGAEgASgF",
|
||||
"EhEKCXJlc3Bfc2l6ZRgCIAEoBSI4ChFTaW1wbGVQcm90b1BhcmFtcxIQCghy",
|
||||
"ZXFfc2l6ZRgBIAEoBRIRCglyZXNwX3NpemUYAiABKAUiFAoSQ29tcGxleFBy",
|
||||
"b3RvUGFyYW1zIsoBCg1QYXlsb2FkQ29uZmlnEjgKDmJ5dGVidWZfcGFyYW1z",
|
||||
"GAEgASgLMh4uZ3JwYy50ZXN0aW5nLkJ5dGVCdWZmZXJQYXJhbXNIABI4Cg1z",
|
||||
"aW1wbGVfcGFyYW1zGAIgASgLMh8uZ3JwYy50ZXN0aW5nLlNpbXBsZVByb3Rv",
|
||||
"UGFyYW1zSAASOgoOY29tcGxleF9wYXJhbXMYAyABKAsyIC5ncnBjLnRlc3Rp",
|
||||
"bmcuQ29tcGxleFByb3RvUGFyYW1zSABCCQoHcGF5bG9hZGIGcHJvdG8z"));
|
||||
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
new pbr::FileDescriptor[] { },
|
||||
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
|
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ByteBufferParams), new[]{ "ReqSize", "RespSize" }, null, null, null),
|
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleProtoParams), new[]{ "ReqSize", "RespSize" }, null, null, null),
|
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ComplexProtoParams), null, null, null, null),
|
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.PayloadConfig), new[]{ "BytebufParams", "SimpleParams", "ComplexParams" }, new[]{ "Payload" }, null, null)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
#region Messages
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public sealed partial class ByteBufferParams : pb::IMessage<ByteBufferParams> {
|
||||
private static readonly pb::MessageParser<ByteBufferParams> _parser = new pb::MessageParser<ByteBufferParams>(() => new ByteBufferParams());
|
||||
public static pb::MessageParser<ByteBufferParams> Parser { get { return _parser; } }
|
||||
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
public ByteBufferParams() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
public ByteBufferParams(ByteBufferParams other) : this() {
|
||||
reqSize_ = other.reqSize_;
|
||||
respSize_ = other.respSize_;
|
||||
}
|
||||
|
||||
public ByteBufferParams Clone() {
|
||||
return new ByteBufferParams(this);
|
||||
}
|
||||
|
||||
public const int ReqSizeFieldNumber = 1;
|
||||
private int reqSize_;
|
||||
public int ReqSize {
|
||||
get { return reqSize_; }
|
||||
set {
|
||||
reqSize_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int RespSizeFieldNumber = 2;
|
||||
private int respSize_;
|
||||
public int RespSize {
|
||||
get { return respSize_; }
|
||||
set {
|
||||
respSize_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as ByteBufferParams);
|
||||
}
|
||||
|
||||
public bool Equals(ByteBufferParams other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (ReqSize != other.ReqSize) return false;
|
||||
if (RespSize != other.RespSize) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (ReqSize != 0) hash ^= ReqSize.GetHashCode();
|
||||
if (RespSize != 0) hash ^= RespSize.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.Default.Format(this);
|
||||
}
|
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
if (ReqSize != 0) {
|
||||
output.WriteRawTag(8);
|
||||
output.WriteInt32(ReqSize);
|
||||
}
|
||||
if (RespSize != 0) {
|
||||
output.WriteRawTag(16);
|
||||
output.WriteInt32(RespSize);
|
||||
}
|
||||
}
|
||||
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (ReqSize != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeInt32Size(ReqSize);
|
||||
}
|
||||
if (RespSize != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeInt32Size(RespSize);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void MergeFrom(ByteBufferParams other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.ReqSize != 0) {
|
||||
ReqSize = other.ReqSize;
|
||||
}
|
||||
if (other.RespSize != 0) {
|
||||
RespSize = other.RespSize;
|
||||
}
|
||||
}
|
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
input.SkipLastField();
|
||||
break;
|
||||
case 8: {
|
||||
ReqSize = input.ReadInt32();
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
RespSize = input.ReadInt32();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public sealed partial class SimpleProtoParams : pb::IMessage<SimpleProtoParams> {
|
||||
private static readonly pb::MessageParser<SimpleProtoParams> _parser = new pb::MessageParser<SimpleProtoParams>(() => new SimpleProtoParams());
|
||||
public static pb::MessageParser<SimpleProtoParams> Parser { get { return _parser; } }
|
||||
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[1]; }
|
||||
}
|
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
public SimpleProtoParams() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
public SimpleProtoParams(SimpleProtoParams other) : this() {
|
||||
reqSize_ = other.reqSize_;
|
||||
respSize_ = other.respSize_;
|
||||
}
|
||||
|
||||
public SimpleProtoParams Clone() {
|
||||
return new SimpleProtoParams(this);
|
||||
}
|
||||
|
||||
public const int ReqSizeFieldNumber = 1;
|
||||
private int reqSize_;
|
||||
public int ReqSize {
|
||||
get { return reqSize_; }
|
||||
set {
|
||||
reqSize_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int RespSizeFieldNumber = 2;
|
||||
private int respSize_;
|
||||
public int RespSize {
|
||||
get { return respSize_; }
|
||||
set {
|
||||
respSize_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as SimpleProtoParams);
|
||||
}
|
||||
|
||||
public bool Equals(SimpleProtoParams other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (ReqSize != other.ReqSize) return false;
|
||||
if (RespSize != other.RespSize) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (ReqSize != 0) hash ^= ReqSize.GetHashCode();
|
||||
if (RespSize != 0) hash ^= RespSize.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.Default.Format(this);
|
||||
}
|
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
if (ReqSize != 0) {
|
||||
output.WriteRawTag(8);
|
||||
output.WriteInt32(ReqSize);
|
||||
}
|
||||
if (RespSize != 0) {
|
||||
output.WriteRawTag(16);
|
||||
output.WriteInt32(RespSize);
|
||||
}
|
||||
}
|
||||
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (ReqSize != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeInt32Size(ReqSize);
|
||||
}
|
||||
if (RespSize != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeInt32Size(RespSize);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void MergeFrom(SimpleProtoParams other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.ReqSize != 0) {
|
||||
ReqSize = other.ReqSize;
|
||||
}
|
||||
if (other.RespSize != 0) {
|
||||
RespSize = other.RespSize;
|
||||
}
|
||||
}
|
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
input.SkipLastField();
|
||||
break;
|
||||
case 8: {
|
||||
ReqSize = input.ReadInt32();
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
RespSize = input.ReadInt32();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public sealed partial class ComplexProtoParams : pb::IMessage<ComplexProtoParams> {
|
||||
private static readonly pb::MessageParser<ComplexProtoParams> _parser = new pb::MessageParser<ComplexProtoParams>(() => new ComplexProtoParams());
|
||||
public static pb::MessageParser<ComplexProtoParams> Parser { get { return _parser; } }
|
||||
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[2]; }
|
||||
}
|
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
public ComplexProtoParams() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
public ComplexProtoParams(ComplexProtoParams other) : this() {
|
||||
}
|
||||
|
||||
public ComplexProtoParams Clone() {
|
||||
return new ComplexProtoParams(this);
|
||||
}
|
||||
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as ComplexProtoParams);
|
||||
}
|
||||
|
||||
public bool Equals(ComplexProtoParams other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.Default.Format(this);
|
||||
}
|
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
}
|
||||
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
public void MergeFrom(ComplexProtoParams other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
input.SkipLastField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public sealed partial class PayloadConfig : pb::IMessage<PayloadConfig> {
|
||||
private static readonly pb::MessageParser<PayloadConfig> _parser = new pb::MessageParser<PayloadConfig>(() => new PayloadConfig());
|
||||
public static pb::MessageParser<PayloadConfig> Parser { get { return _parser; } }
|
||||
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[3]; }
|
||||
}
|
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
public PayloadConfig() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
public PayloadConfig(PayloadConfig other) : this() {
|
||||
switch (other.PayloadCase) {
|
||||
case PayloadOneofCase.BytebufParams:
|
||||
BytebufParams = other.BytebufParams.Clone();
|
||||
break;
|
||||
case PayloadOneofCase.SimpleParams:
|
||||
SimpleParams = other.SimpleParams.Clone();
|
||||
break;
|
||||
case PayloadOneofCase.ComplexParams:
|
||||
ComplexParams = other.ComplexParams.Clone();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public PayloadConfig Clone() {
|
||||
return new PayloadConfig(this);
|
||||
}
|
||||
|
||||
public const int BytebufParamsFieldNumber = 1;
|
||||
public global::Grpc.Testing.ByteBufferParams BytebufParams {
|
||||
get { return payloadCase_ == PayloadOneofCase.BytebufParams ? (global::Grpc.Testing.ByteBufferParams) payload_ : null; }
|
||||
set {
|
||||
payload_ = value;
|
||||
payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BytebufParams;
|
||||
}
|
||||
}
|
||||
|
||||
public const int SimpleParamsFieldNumber = 2;
|
||||
public global::Grpc.Testing.SimpleProtoParams SimpleParams {
|
||||
get { return payloadCase_ == PayloadOneofCase.SimpleParams ? (global::Grpc.Testing.SimpleProtoParams) payload_ : null; }
|
||||
set {
|
||||
payload_ = value;
|
||||
payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.SimpleParams;
|
||||
}
|
||||
}
|
||||
|
||||
public const int ComplexParamsFieldNumber = 3;
|
||||
public global::Grpc.Testing.ComplexProtoParams ComplexParams {
|
||||
get { return payloadCase_ == PayloadOneofCase.ComplexParams ? (global::Grpc.Testing.ComplexProtoParams) payload_ : null; }
|
||||
set {
|
||||
payload_ = value;
|
||||
payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.ComplexParams;
|
||||
}
|
||||
}
|
||||
|
||||
private object payload_;
|
||||
public enum PayloadOneofCase {
|
||||
None = 0,
|
||||
BytebufParams = 1,
|
||||
SimpleParams = 2,
|
||||
ComplexParams = 3,
|
||||
}
|
||||
private PayloadOneofCase payloadCase_ = PayloadOneofCase.None;
|
||||
public PayloadOneofCase PayloadCase {
|
||||
get { return payloadCase_; }
|
||||
}
|
||||
|
||||
public void ClearPayload() {
|
||||
payloadCase_ = PayloadOneofCase.None;
|
||||
payload_ = null;
|
||||
}
|
||||
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as PayloadConfig);
|
||||
}
|
||||
|
||||
public bool Equals(PayloadConfig other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (!object.Equals(BytebufParams, other.BytebufParams)) return false;
|
||||
if (!object.Equals(SimpleParams, other.SimpleParams)) return false;
|
||||
if (!object.Equals(ComplexParams, other.ComplexParams)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (payloadCase_ == PayloadOneofCase.BytebufParams) hash ^= BytebufParams.GetHashCode();
|
||||
if (payloadCase_ == PayloadOneofCase.SimpleParams) hash ^= SimpleParams.GetHashCode();
|
||||
if (payloadCase_ == PayloadOneofCase.ComplexParams) hash ^= ComplexParams.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.Default.Format(this);
|
||||
}
|
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
if (payloadCase_ == PayloadOneofCase.BytebufParams) {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteMessage(BytebufParams);
|
||||
}
|
||||
if (payloadCase_ == PayloadOneofCase.SimpleParams) {
|
||||
output.WriteRawTag(18);
|
||||
output.WriteMessage(SimpleParams);
|
||||
}
|
||||
if (payloadCase_ == PayloadOneofCase.ComplexParams) {
|
||||
output.WriteRawTag(26);
|
||||
output.WriteMessage(ComplexParams);
|
||||
}
|
||||
}
|
||||
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (payloadCase_ == PayloadOneofCase.BytebufParams) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(BytebufParams);
|
||||
}
|
||||
if (payloadCase_ == PayloadOneofCase.SimpleParams) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(SimpleParams);
|
||||
}
|
||||
if (payloadCase_ == PayloadOneofCase.ComplexParams) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ComplexParams);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void MergeFrom(PayloadConfig other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
switch (other.PayloadCase) {
|
||||
case PayloadOneofCase.BytebufParams:
|
||||
BytebufParams = other.BytebufParams;
|
||||
break;
|
||||
case PayloadOneofCase.SimpleParams:
|
||||
SimpleParams = other.SimpleParams;
|
||||
break;
|
||||
case PayloadOneofCase.ComplexParams:
|
||||
ComplexParams = other.ComplexParams;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
input.SkipLastField();
|
||||
break;
|
||||
case 10: {
|
||||
global::Grpc.Testing.ByteBufferParams subBuilder = new global::Grpc.Testing.ByteBufferParams();
|
||||
if (payloadCase_ == PayloadOneofCase.BytebufParams) {
|
||||
subBuilder.MergeFrom(BytebufParams);
|
||||
}
|
||||
input.ReadMessage(subBuilder);
|
||||
BytebufParams = subBuilder;
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
global::Grpc.Testing.SimpleProtoParams subBuilder = new global::Grpc.Testing.SimpleProtoParams();
|
||||
if (payloadCase_ == PayloadOneofCase.SimpleParams) {
|
||||
subBuilder.MergeFrom(SimpleParams);
|
||||
}
|
||||
input.ReadMessage(subBuilder);
|
||||
SimpleParams = subBuilder;
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
global::Grpc.Testing.ComplexProtoParams subBuilder = new global::Grpc.Testing.ComplexProtoParams();
|
||||
if (payloadCase_ == PayloadOneofCase.ComplexParams) {
|
||||
subBuilder.MergeFrom(ComplexParams);
|
||||
}
|
||||
input.ReadMessage(subBuilder);
|
||||
ComplexParams = subBuilder;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
#endregion Designer generated code
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using CommandLine;
|
||||
using CommandLine.Text;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
using Grpc.Testing;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Grpc.IntegrationTesting
|
||||
{
|
||||
public class QpsWorker
|
||||
{
|
||||
private class ServerOptions
|
||||
{
|
||||
[Option("driver_port", DefaultValue = 0)]
|
||||
public int DriverPort { get; set; }
|
||||
|
||||
[HelpOption]
|
||||
public string GetUsage()
|
||||
{
|
||||
var help = new HelpText
|
||||
{
|
||||
Heading = "gRPC C# performance testing worker",
|
||||
AddDashesToOption = true
|
||||
};
|
||||
help.AddPreOptionsLine("Usage:");
|
||||
help.AddOptions(this);
|
||||
return help;
|
||||
}
|
||||
}
|
||||
|
||||
ServerOptions options;
|
||||
|
||||
private QpsWorker(ServerOptions options)
|
||||
{
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public static void Run(string[] args)
|
||||
{
|
||||
var options = new ServerOptions();
|
||||
if (!Parser.Default.ParseArguments(args, options))
|
||||
{
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
var workerServer = new QpsWorker(options);
|
||||
workerServer.Run();
|
||||
}
|
||||
|
||||
private void Run()
|
||||
{
|
||||
string host = "0.0.0.0";
|
||||
int port = options.DriverPort;
|
||||
|
||||
var server = new Server
|
||||
{
|
||||
Services = { WorkerService.BindService(new WorkerServiceImpl()) },
|
||||
Ports = { new ServerPort(host, options.DriverPort, ServerCredentials.Insecure )}
|
||||
};
|
||||
int boundPort = server.Ports.Single().BoundPort;
|
||||
Console.WriteLine("Running qps worker server on " + string.Format("{0}:{1}", host, boundPort));
|
||||
server.Start();
|
||||
|
||||
server.ShutdownTask.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
using Grpc.Testing;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Grpc.IntegrationTesting
|
||||
{
|
||||
/// <summary>
|
||||
/// Runs performance tests in-process.
|
||||
/// </summary>
|
||||
public class RunnerClientServerTest
|
||||
{
|
||||
const string Host = "localhost";
|
||||
IServerRunner serverRunner;
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void Init()
|
||||
{
|
||||
var serverConfig = new ServerConfig
|
||||
{
|
||||
ServerType = ServerType.ASYNC_SERVER,
|
||||
Host = Host,
|
||||
PayloadConfig = new PayloadConfig
|
||||
{
|
||||
SimpleParams = new SimpleProtoParams
|
||||
{
|
||||
RespSize = 100
|
||||
}
|
||||
}
|
||||
};
|
||||
serverRunner = ServerRunners.CreateStarted(serverConfig);
|
||||
}
|
||||
|
||||
[TestFixtureTearDown]
|
||||
public void Cleanup()
|
||||
{
|
||||
serverRunner.StopAsync().Wait();
|
||||
}
|
||||
|
||||
// Test attribute commented out to prevent running as part of the default test suite.
|
||||
//[Test]
|
||||
//[Category("Performance")]
|
||||
public async Task ClientServerRunner()
|
||||
{
|
||||
var config = new ClientConfig
|
||||
{
|
||||
ServerTargets = { string.Format("{0}:{1}", Host, serverRunner.BoundPort) },
|
||||
RpcType = RpcType.UNARY,
|
||||
LoadParams = new LoadParams { ClosedLoop = new ClosedLoopParams() },
|
||||
PayloadConfig = new PayloadConfig
|
||||
{
|
||||
SimpleParams = new SimpleProtoParams
|
||||
{
|
||||
ReqSize = 100
|
||||
}
|
||||
},
|
||||
HistogramParams = new HistogramParams
|
||||
{
|
||||
Resolution = 0.01,
|
||||
MaxPossible = 60e9
|
||||
}
|
||||
};
|
||||
|
||||
var runner = ClientRunners.CreateStarted(config);
|
||||
|
||||
System.Console.WriteLine("Warming up");
|
||||
await Task.Delay(3000);
|
||||
runner.GetStats(true); // throw away warm-up data
|
||||
|
||||
System.Console.WriteLine("Benchmarking");
|
||||
await Task.Delay(3000);
|
||||
var stats = runner.GetStats(true);
|
||||
await runner.StopAsync();
|
||||
|
||||
System.Console.WriteLine(stats);
|
||||
System.Console.WriteLine("avg micros/call " + (long) (stats.Latencies.Sum / stats.Latencies.Count / 1000.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
using NUnit.Framework;
|
||||
using Grpc.Testing;
|
||||
|
||||
namespace Grpc.IntegrationTesting
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper methods to start server runners for performance testing.
|
||||
/// </summary>
|
||||
public static class ServerRunners
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a started server runner.
|
||||
/// </summary>
|
||||
public static IServerRunner CreateStarted(ServerConfig config)
|
||||
{
|
||||
Grpc.Core.Utils.Preconditions.CheckArgument(config.ServerType == ServerType.ASYNC_SERVER);
|
||||
var credentials = config.SecurityParams != null ? TestCredentials.CreateSslServerCredentials() : ServerCredentials.Insecure;
|
||||
|
||||
// TODO: qps_driver needs to setup payload properly...
|
||||
int responseSize = config.PayloadConfig != null ? config.PayloadConfig.SimpleParams.RespSize : 0;
|
||||
var server = new Server
|
||||
{
|
||||
Services = { BenchmarkService.BindService(new BenchmarkServiceImpl(responseSize)) },
|
||||
Ports = { new ServerPort(config.Host, config.Port, credentials) }
|
||||
};
|
||||
|
||||
server.Start();
|
||||
return new ServerRunnerImpl(server);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server runner.
|
||||
/// </summary>
|
||||
public class ServerRunnerImpl : IServerRunner
|
||||
{
|
||||
readonly Server server;
|
||||
readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
|
||||
|
||||
public ServerRunnerImpl(Server server)
|
||||
{
|
||||
this.server = Grpc.Core.Utils.Preconditions.CheckNotNull(server);
|
||||
}
|
||||
|
||||
public int BoundPort
|
||||
{
|
||||
get
|
||||
{
|
||||
return server.Ports.Single().BoundPort;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets server stats.
|
||||
/// </summary>
|
||||
/// <returns>The stats.</returns>
|
||||
public ServerStats GetStats(bool reset)
|
||||
{
|
||||
var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds;
|
||||
|
||||
// TODO: populate user time and system time
|
||||
return new ServerStats
|
||||
{
|
||||
TimeElapsed = secondsElapsed,
|
||||
TimeUser = 0,
|
||||
TimeSystem = 0
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously stops the server.
|
||||
/// </summary>
|
||||
/// <returns>Task that finishes when server has shutdown.</returns>
|
||||
public Task StopAsync()
|
||||
{
|
||||
return server.ShutdownAsync();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: test/proto/benchmarks/services.proto
|
||||
#pragma warning disable 1591, 0612, 3021
|
||||
#region Designer generated code
|
||||
|
||||
using pb = global::Google.Protobuf;
|
||||
using pbc = global::Google.Protobuf.Collections;
|
||||
using pbr = global::Google.Protobuf.Reflection;
|
||||
using scg = global::System.Collections.Generic;
|
||||
namespace Grpc.Testing {
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public static partial class Services {
|
||||
|
||||
#region Descriptor
|
||||
public static pbr::FileDescriptor Descriptor {
|
||||
get { return descriptor; }
|
||||
}
|
||||
private static pbr::FileDescriptor descriptor;
|
||||
|
||||
static Services() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"CiR0ZXN0L3Byb3RvL2JlbmNobWFya3Mvc2VydmljZXMucHJvdG8SDGdycGMu",
|
||||
"dGVzdGluZxoZdGVzdC9wcm90by9tZXNzYWdlcy5wcm90bxojdGVzdC9wcm90",
|
||||
"by9iZW5jaG1hcmtzL2NvbnRyb2wucHJvdG8yqgEKEEJlbmNobWFya1NlcnZp",
|
||||
"Y2USRgoJVW5hcnlDYWxsEhsuZ3JwYy50ZXN0aW5nLlNpbXBsZVJlcXVlc3Qa",
|
||||
"HC5ncnBjLnRlc3RpbmcuU2ltcGxlUmVzcG9uc2USTgoNU3RyZWFtaW5nQ2Fs",
|
||||
"bBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0aW5n",
|
||||
"LlNpbXBsZVJlc3BvbnNlKAEwATKdAQoNV29ya2VyU2VydmljZRJFCglSdW5T",
|
||||
"ZXJ2ZXISGC5ncnBjLnRlc3RpbmcuU2VydmVyQXJncxoaLmdycGMudGVzdGlu",
|
||||
"Zy5TZXJ2ZXJTdGF0dXMoATABEkUKCVJ1bkNsaWVudBIYLmdycGMudGVzdGlu",
|
||||
"Zy5DbGllbnRBcmdzGhouZ3JwYy50ZXN0aW5nLkNsaWVudFN0YXR1cygBMAFi",
|
||||
"BnByb3RvMw=="));
|
||||
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
new pbr::FileDescriptor[] { global::Grpc.Testing.Messages.Descriptor, global::Grpc.Testing.Control.Descriptor, },
|
||||
new pbr::GeneratedCodeInfo(null, null));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Designer generated code
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: test/proto/benchmarks/services.proto
|
||||
#region Designer generated code
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Grpc.Core;
|
||||
|
||||
namespace Grpc.Testing {
|
||||
public static class BenchmarkService
|
||||
{
|
||||
static readonly string __ServiceName = "grpc.testing.BenchmarkService";
|
||||
|
||||
static readonly Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_SimpleRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
|
||||
static readonly Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_SimpleResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
|
||||
|
||||
static readonly Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
|
||||
MethodType.Unary,
|
||||
__ServiceName,
|
||||
"UnaryCall",
|
||||
__Marshaller_SimpleRequest,
|
||||
__Marshaller_SimpleResponse);
|
||||
|
||||
static readonly Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingCall = new Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
|
||||
MethodType.DuplexStreaming,
|
||||
__ServiceName,
|
||||
"StreamingCall",
|
||||
__Marshaller_SimpleRequest,
|
||||
__Marshaller_SimpleResponse);
|
||||
|
||||
// service descriptor
|
||||
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
|
||||
{
|
||||
get { return global::Grpc.Testing.Services.Descriptor.Services[0]; }
|
||||
}
|
||||
|
||||
// client interface
|
||||
public interface IBenchmarkServiceClient
|
||||
{
|
||||
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
|
||||
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
|
||||
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
|
||||
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
|
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
|
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options);
|
||||
}
|
||||
|
||||
// server-side interface
|
||||
public interface IBenchmarkService
|
||||
{
|
||||
Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
|
||||
Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context);
|
||||
}
|
||||
|
||||
// client stub
|
||||
public class BenchmarkServiceClient : ClientBase, IBenchmarkServiceClient
|
||||
{
|
||||
public BenchmarkServiceClient(Channel channel) : base(channel)
|
||||
{
|
||||
}
|
||||
public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
|
||||
return Calls.BlockingUnaryCall(call, request);
|
||||
}
|
||||
public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
|
||||
{
|
||||
var call = CreateCall(__Method_UnaryCall, options);
|
||||
return Calls.BlockingUnaryCall(call, request);
|
||||
}
|
||||
public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
|
||||
return Calls.AsyncUnaryCall(call, request);
|
||||
}
|
||||
public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
|
||||
{
|
||||
var call = CreateCall(__Method_UnaryCall, options);
|
||||
return Calls.AsyncUnaryCall(call, request);
|
||||
}
|
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var call = CreateCall(__Method_StreamingCall, new CallOptions(headers, deadline, cancellationToken));
|
||||
return Calls.AsyncDuplexStreamingCall(call);
|
||||
}
|
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options)
|
||||
{
|
||||
var call = CreateCall(__Method_StreamingCall, options);
|
||||
return Calls.AsyncDuplexStreamingCall(call);
|
||||
}
|
||||
}
|
||||
|
||||
// creates service definition that can be registered with a server
|
||||
public static ServerServiceDefinition BindService(IBenchmarkService serviceImpl)
|
||||
{
|
||||
return ServerServiceDefinition.CreateBuilder(__ServiceName)
|
||||
.AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
|
||||
.AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
|
||||
}
|
||||
|
||||
// creates a new client
|
||||
public static BenchmarkServiceClient NewClient(Channel channel)
|
||||
{
|
||||
return new BenchmarkServiceClient(channel);
|
||||
}
|
||||
|
||||
}
|
||||
public static class WorkerService
|
||||
{
|
||||
static readonly string __ServiceName = "grpc.testing.WorkerService";
|
||||
|
||||
static readonly Marshaller<global::Grpc.Testing.ServerArgs> __Marshaller_ServerArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerArgs.Parser.ParseFrom);
|
||||
static readonly Marshaller<global::Grpc.Testing.ServerStatus> __Marshaller_ServerStatus = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerStatus.Parser.ParseFrom);
|
||||
static readonly Marshaller<global::Grpc.Testing.ClientArgs> __Marshaller_ClientArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientArgs.Parser.ParseFrom);
|
||||
static readonly Marshaller<global::Grpc.Testing.ClientStatus> __Marshaller_ClientStatus = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientStatus.Parser.ParseFrom);
|
||||
|
||||
static readonly Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> __Method_RunServer = new Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus>(
|
||||
MethodType.DuplexStreaming,
|
||||
__ServiceName,
|
||||
"RunServer",
|
||||
__Marshaller_ServerArgs,
|
||||
__Marshaller_ServerStatus);
|
||||
|
||||
static readonly Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> __Method_RunClient = new Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus>(
|
||||
MethodType.DuplexStreaming,
|
||||
__ServiceName,
|
||||
"RunClient",
|
||||
__Marshaller_ClientArgs,
|
||||
__Marshaller_ClientStatus);
|
||||
|
||||
// service descriptor
|
||||
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
|
||||
{
|
||||
get { return global::Grpc.Testing.Services.Descriptor.Services[1]; }
|
||||
}
|
||||
|
||||
// client interface
|
||||
public interface IWorkerServiceClient
|
||||
{
|
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
|
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options);
|
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
|
||||
AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options);
|
||||
}
|
||||
|
||||
// server-side interface
|
||||
public interface IWorkerService
|
||||
{
|
||||
Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context);
|
||||
Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context);
|
||||
}
|
||||
|
||||
// client stub
|
||||
public class WorkerServiceClient : ClientBase, IWorkerServiceClient
|
||||
{
|
||||
public WorkerServiceClient(Channel channel) : base(channel)
|
||||
{
|
||||
}
|
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var call = CreateCall(__Method_RunServer, new CallOptions(headers, deadline, cancellationToken));
|
||||
return Calls.AsyncDuplexStreamingCall(call);
|
||||
}
|
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options)
|
||||
{
|
||||
var call = CreateCall(__Method_RunServer, options);
|
||||
return Calls.AsyncDuplexStreamingCall(call);
|
||||
}
|
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var call = CreateCall(__Method_RunClient, new CallOptions(headers, deadline, cancellationToken));
|
||||
return Calls.AsyncDuplexStreamingCall(call);
|
||||
}
|
||||
public AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options)
|
||||
{
|
||||
var call = CreateCall(__Method_RunClient, options);
|
||||
return Calls.AsyncDuplexStreamingCall(call);
|
||||
}
|
||||
}
|
||||
|
||||
// creates service definition that can be registered with a server
|
||||
public static ServerServiceDefinition BindService(IWorkerService serviceImpl)
|
||||
{
|
||||
return ServerServiceDefinition.CreateBuilder(__ServiceName)
|
||||
.AddMethod(__Method_RunServer, serviceImpl.RunServer)
|
||||
.AddMethod(__Method_RunClient, serviceImpl.RunClient).Build();
|
||||
}
|
||||
|
||||
// creates a new client
|
||||
public static WorkerServiceClient NewClient(Channel channel)
|
||||
{
|
||||
return new WorkerServiceClient(channel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
<StyleCopSettings Version="105">
|
||||
<SourceFileList>
|
||||
<SourceFile>Messages.cs</SourceFile>
|
||||
<SourceFile>Empty.cs</SourceFile>
|
||||
<SourceFile>Control.cs</SourceFile>
|
||||
<SourceFile>Messages.cs</SourceFile>
|
||||
<SourceFile>Payloads.cs</SourceFile>
|
||||
<SourceFile>Stats.cs</SourceFile>
|
||||
<Settings>
|
||||
<GlobalSettings>
|
||||
<BooleanProperty Name="RulesEnabledByDefault">False</BooleanProperty>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,744 @@
|
|||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: test/proto/benchmarks/stats.proto
|
||||
#pragma warning disable 1591, 0612, 3021
|
||||
#region Designer generated code
|
||||
|
||||
using pb = global::Google.Protobuf;
|
||||
using pbc = global::Google.Protobuf.Collections;
|
||||
using pbr = global::Google.Protobuf.Reflection;
|
||||
using scg = global::System.Collections.Generic;
|
||||
namespace Grpc.Testing {
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public static partial class Stats {
|
||||
|
||||
#region Descriptor
|
||||
public static pbr::FileDescriptor Descriptor {
|
||||
get { return descriptor; }
|
||||
}
|
||||
private static pbr::FileDescriptor descriptor;
|
||||
|
||||
static Stats() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"CiF0ZXN0L3Byb3RvL2JlbmNobWFya3Mvc3RhdHMucHJvdG8SDGdycGMudGVz",
|
||||
"dGluZyJLCgtTZXJ2ZXJTdGF0cxIUCgx0aW1lX2VsYXBzZWQYASABKAESEQoJ",
|
||||
"dGltZV91c2VyGAIgASgBEhMKC3RpbWVfc3lzdGVtGAMgASgBIjsKD0hpc3Rv",
|
||||
"Z3JhbVBhcmFtcxISCgpyZXNvbHV0aW9uGAEgASgBEhQKDG1heF9wb3NzaWJs",
|
||||
"ZRgCIAEoASJ3Cg1IaXN0b2dyYW1EYXRhEg4KBmJ1Y2tldBgBIAMoDRIQCght",
|
||||
"aW5fc2VlbhgCIAEoARIQCghtYXhfc2VlbhgDIAEoARILCgNzdW0YBCABKAES",
|
||||
"FgoOc3VtX29mX3NxdWFyZXMYBSABKAESDQoFY291bnQYBiABKAEiewoLQ2xp",
|
||||
"ZW50U3RhdHMSLgoJbGF0ZW5jaWVzGAEgASgLMhsuZ3JwYy50ZXN0aW5nLkhp",
|
||||
"c3RvZ3JhbURhdGESFAoMdGltZV9lbGFwc2VkGAIgASgBEhEKCXRpbWVfdXNl",
|
||||
"chgDIAEoARITCgt0aW1lX3N5c3RlbRgEIAEoAWIGcHJvdG8z"));
|
||||
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
|
||||
new pbr::FileDescriptor[] { },
|
||||
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
|
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerStats), new[]{ "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null),
|
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.HistogramParams), new[]{ "Resolution", "MaxPossible" }, null, null, null),
|
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.HistogramData), new[]{ "Bucket", "MinSeen", "MaxSeen", "Sum", "SumOfSquares", "Count" }, null, null, null),
|
||||
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientStats), new[]{ "Latencies", "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
#region Messages
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public sealed partial class ServerStats : pb::IMessage<ServerStats> {
|
||||
private static readonly pb::MessageParser<ServerStats> _parser = new pb::MessageParser<ServerStats>(() => new ServerStats());
|
||||
public static pb::MessageParser<ServerStats> Parser { get { return _parser; } }
|
||||
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
public ServerStats() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
public ServerStats(ServerStats other) : this() {
|
||||
timeElapsed_ = other.timeElapsed_;
|
||||
timeUser_ = other.timeUser_;
|
||||
timeSystem_ = other.timeSystem_;
|
||||
}
|
||||
|
||||
public ServerStats Clone() {
|
||||
return new ServerStats(this);
|
||||
}
|
||||
|
||||
public const int TimeElapsedFieldNumber = 1;
|
||||
private double timeElapsed_;
|
||||
public double TimeElapsed {
|
||||
get { return timeElapsed_; }
|
||||
set {
|
||||
timeElapsed_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int TimeUserFieldNumber = 2;
|
||||
private double timeUser_;
|
||||
public double TimeUser {
|
||||
get { return timeUser_; }
|
||||
set {
|
||||
timeUser_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int TimeSystemFieldNumber = 3;
|
||||
private double timeSystem_;
|
||||
public double TimeSystem {
|
||||
get { return timeSystem_; }
|
||||
set {
|
||||
timeSystem_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as ServerStats);
|
||||
}
|
||||
|
||||
public bool Equals(ServerStats other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (TimeElapsed != other.TimeElapsed) return false;
|
||||
if (TimeUser != other.TimeUser) return false;
|
||||
if (TimeSystem != other.TimeSystem) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode();
|
||||
if (TimeUser != 0D) hash ^= TimeUser.GetHashCode();
|
||||
if (TimeSystem != 0D) hash ^= TimeSystem.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.Default.Format(this);
|
||||
}
|
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
if (TimeElapsed != 0D) {
|
||||
output.WriteRawTag(9);
|
||||
output.WriteDouble(TimeElapsed);
|
||||
}
|
||||
if (TimeUser != 0D) {
|
||||
output.WriteRawTag(17);
|
||||
output.WriteDouble(TimeUser);
|
||||
}
|
||||
if (TimeSystem != 0D) {
|
||||
output.WriteRawTag(25);
|
||||
output.WriteDouble(TimeSystem);
|
||||
}
|
||||
}
|
||||
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (TimeElapsed != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
if (TimeUser != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
if (TimeSystem != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void MergeFrom(ServerStats other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.TimeElapsed != 0D) {
|
||||
TimeElapsed = other.TimeElapsed;
|
||||
}
|
||||
if (other.TimeUser != 0D) {
|
||||
TimeUser = other.TimeUser;
|
||||
}
|
||||
if (other.TimeSystem != 0D) {
|
||||
TimeSystem = other.TimeSystem;
|
||||
}
|
||||
}
|
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
input.SkipLastField();
|
||||
break;
|
||||
case 9: {
|
||||
TimeElapsed = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
case 17: {
|
||||
TimeUser = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
case 25: {
|
||||
TimeSystem = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public sealed partial class HistogramParams : pb::IMessage<HistogramParams> {
|
||||
private static readonly pb::MessageParser<HistogramParams> _parser = new pb::MessageParser<HistogramParams>(() => new HistogramParams());
|
||||
public static pb::MessageParser<HistogramParams> Parser { get { return _parser; } }
|
||||
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[1]; }
|
||||
}
|
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
public HistogramParams() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
public HistogramParams(HistogramParams other) : this() {
|
||||
resolution_ = other.resolution_;
|
||||
maxPossible_ = other.maxPossible_;
|
||||
}
|
||||
|
||||
public HistogramParams Clone() {
|
||||
return new HistogramParams(this);
|
||||
}
|
||||
|
||||
public const int ResolutionFieldNumber = 1;
|
||||
private double resolution_;
|
||||
public double Resolution {
|
||||
get { return resolution_; }
|
||||
set {
|
||||
resolution_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int MaxPossibleFieldNumber = 2;
|
||||
private double maxPossible_;
|
||||
public double MaxPossible {
|
||||
get { return maxPossible_; }
|
||||
set {
|
||||
maxPossible_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as HistogramParams);
|
||||
}
|
||||
|
||||
public bool Equals(HistogramParams other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (Resolution != other.Resolution) return false;
|
||||
if (MaxPossible != other.MaxPossible) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (Resolution != 0D) hash ^= Resolution.GetHashCode();
|
||||
if (MaxPossible != 0D) hash ^= MaxPossible.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.Default.Format(this);
|
||||
}
|
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
if (Resolution != 0D) {
|
||||
output.WriteRawTag(9);
|
||||
output.WriteDouble(Resolution);
|
||||
}
|
||||
if (MaxPossible != 0D) {
|
||||
output.WriteRawTag(17);
|
||||
output.WriteDouble(MaxPossible);
|
||||
}
|
||||
}
|
||||
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (Resolution != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
if (MaxPossible != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void MergeFrom(HistogramParams other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.Resolution != 0D) {
|
||||
Resolution = other.Resolution;
|
||||
}
|
||||
if (other.MaxPossible != 0D) {
|
||||
MaxPossible = other.MaxPossible;
|
||||
}
|
||||
}
|
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
input.SkipLastField();
|
||||
break;
|
||||
case 9: {
|
||||
Resolution = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
case 17: {
|
||||
MaxPossible = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public sealed partial class HistogramData : pb::IMessage<HistogramData> {
|
||||
private static readonly pb::MessageParser<HistogramData> _parser = new pb::MessageParser<HistogramData>(() => new HistogramData());
|
||||
public static pb::MessageParser<HistogramData> Parser { get { return _parser; } }
|
||||
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[2]; }
|
||||
}
|
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
public HistogramData() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
public HistogramData(HistogramData other) : this() {
|
||||
bucket_ = other.bucket_.Clone();
|
||||
minSeen_ = other.minSeen_;
|
||||
maxSeen_ = other.maxSeen_;
|
||||
sum_ = other.sum_;
|
||||
sumOfSquares_ = other.sumOfSquares_;
|
||||
count_ = other.count_;
|
||||
}
|
||||
|
||||
public HistogramData Clone() {
|
||||
return new HistogramData(this);
|
||||
}
|
||||
|
||||
public const int BucketFieldNumber = 1;
|
||||
private static readonly pb::FieldCodec<uint> _repeated_bucket_codec
|
||||
= pb::FieldCodec.ForUInt32(10);
|
||||
private readonly pbc::RepeatedField<uint> bucket_ = new pbc::RepeatedField<uint>();
|
||||
public pbc::RepeatedField<uint> Bucket {
|
||||
get { return bucket_; }
|
||||
}
|
||||
|
||||
public const int MinSeenFieldNumber = 2;
|
||||
private double minSeen_;
|
||||
public double MinSeen {
|
||||
get { return minSeen_; }
|
||||
set {
|
||||
minSeen_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int MaxSeenFieldNumber = 3;
|
||||
private double maxSeen_;
|
||||
public double MaxSeen {
|
||||
get { return maxSeen_; }
|
||||
set {
|
||||
maxSeen_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int SumFieldNumber = 4;
|
||||
private double sum_;
|
||||
public double Sum {
|
||||
get { return sum_; }
|
||||
set {
|
||||
sum_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int SumOfSquaresFieldNumber = 5;
|
||||
private double sumOfSquares_;
|
||||
public double SumOfSquares {
|
||||
get { return sumOfSquares_; }
|
||||
set {
|
||||
sumOfSquares_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int CountFieldNumber = 6;
|
||||
private double count_;
|
||||
public double Count {
|
||||
get { return count_; }
|
||||
set {
|
||||
count_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as HistogramData);
|
||||
}
|
||||
|
||||
public bool Equals(HistogramData other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if(!bucket_.Equals(other.bucket_)) return false;
|
||||
if (MinSeen != other.MinSeen) return false;
|
||||
if (MaxSeen != other.MaxSeen) return false;
|
||||
if (Sum != other.Sum) return false;
|
||||
if (SumOfSquares != other.SumOfSquares) return false;
|
||||
if (Count != other.Count) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
hash ^= bucket_.GetHashCode();
|
||||
if (MinSeen != 0D) hash ^= MinSeen.GetHashCode();
|
||||
if (MaxSeen != 0D) hash ^= MaxSeen.GetHashCode();
|
||||
if (Sum != 0D) hash ^= Sum.GetHashCode();
|
||||
if (SumOfSquares != 0D) hash ^= SumOfSquares.GetHashCode();
|
||||
if (Count != 0D) hash ^= Count.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.Default.Format(this);
|
||||
}
|
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
bucket_.WriteTo(output, _repeated_bucket_codec);
|
||||
if (MinSeen != 0D) {
|
||||
output.WriteRawTag(17);
|
||||
output.WriteDouble(MinSeen);
|
||||
}
|
||||
if (MaxSeen != 0D) {
|
||||
output.WriteRawTag(25);
|
||||
output.WriteDouble(MaxSeen);
|
||||
}
|
||||
if (Sum != 0D) {
|
||||
output.WriteRawTag(33);
|
||||
output.WriteDouble(Sum);
|
||||
}
|
||||
if (SumOfSquares != 0D) {
|
||||
output.WriteRawTag(41);
|
||||
output.WriteDouble(SumOfSquares);
|
||||
}
|
||||
if (Count != 0D) {
|
||||
output.WriteRawTag(49);
|
||||
output.WriteDouble(Count);
|
||||
}
|
||||
}
|
||||
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
size += bucket_.CalculateSize(_repeated_bucket_codec);
|
||||
if (MinSeen != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
if (MaxSeen != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
if (Sum != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
if (SumOfSquares != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
if (Count != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void MergeFrom(HistogramData other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
bucket_.Add(other.bucket_);
|
||||
if (other.MinSeen != 0D) {
|
||||
MinSeen = other.MinSeen;
|
||||
}
|
||||
if (other.MaxSeen != 0D) {
|
||||
MaxSeen = other.MaxSeen;
|
||||
}
|
||||
if (other.Sum != 0D) {
|
||||
Sum = other.Sum;
|
||||
}
|
||||
if (other.SumOfSquares != 0D) {
|
||||
SumOfSquares = other.SumOfSquares;
|
||||
}
|
||||
if (other.Count != 0D) {
|
||||
Count = other.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
input.SkipLastField();
|
||||
break;
|
||||
case 10:
|
||||
case 8: {
|
||||
bucket_.AddEntriesFrom(input, _repeated_bucket_codec);
|
||||
break;
|
||||
}
|
||||
case 17: {
|
||||
MinSeen = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
case 25: {
|
||||
MaxSeen = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
case 33: {
|
||||
Sum = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
case 41: {
|
||||
SumOfSquares = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
case 49: {
|
||||
Count = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public sealed partial class ClientStats : pb::IMessage<ClientStats> {
|
||||
private static readonly pb::MessageParser<ClientStats> _parser = new pb::MessageParser<ClientStats>(() => new ClientStats());
|
||||
public static pb::MessageParser<ClientStats> Parser { get { return _parser; } }
|
||||
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[3]; }
|
||||
}
|
||||
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
public ClientStats() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
public ClientStats(ClientStats other) : this() {
|
||||
Latencies = other.latencies_ != null ? other.Latencies.Clone() : null;
|
||||
timeElapsed_ = other.timeElapsed_;
|
||||
timeUser_ = other.timeUser_;
|
||||
timeSystem_ = other.timeSystem_;
|
||||
}
|
||||
|
||||
public ClientStats Clone() {
|
||||
return new ClientStats(this);
|
||||
}
|
||||
|
||||
public const int LatenciesFieldNumber = 1;
|
||||
private global::Grpc.Testing.HistogramData latencies_;
|
||||
public global::Grpc.Testing.HistogramData Latencies {
|
||||
get { return latencies_; }
|
||||
set {
|
||||
latencies_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int TimeElapsedFieldNumber = 2;
|
||||
private double timeElapsed_;
|
||||
public double TimeElapsed {
|
||||
get { return timeElapsed_; }
|
||||
set {
|
||||
timeElapsed_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int TimeUserFieldNumber = 3;
|
||||
private double timeUser_;
|
||||
public double TimeUser {
|
||||
get { return timeUser_; }
|
||||
set {
|
||||
timeUser_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int TimeSystemFieldNumber = 4;
|
||||
private double timeSystem_;
|
||||
public double TimeSystem {
|
||||
get { return timeSystem_; }
|
||||
set {
|
||||
timeSystem_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as ClientStats);
|
||||
}
|
||||
|
||||
public bool Equals(ClientStats other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (!object.Equals(Latencies, other.Latencies)) return false;
|
||||
if (TimeElapsed != other.TimeElapsed) return false;
|
||||
if (TimeUser != other.TimeUser) return false;
|
||||
if (TimeSystem != other.TimeSystem) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (latencies_ != null) hash ^= Latencies.GetHashCode();
|
||||
if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode();
|
||||
if (TimeUser != 0D) hash ^= TimeUser.GetHashCode();
|
||||
if (TimeSystem != 0D) hash ^= TimeSystem.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.Default.Format(this);
|
||||
}
|
||||
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
if (latencies_ != null) {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteMessage(Latencies);
|
||||
}
|
||||
if (TimeElapsed != 0D) {
|
||||
output.WriteRawTag(17);
|
||||
output.WriteDouble(TimeElapsed);
|
||||
}
|
||||
if (TimeUser != 0D) {
|
||||
output.WriteRawTag(25);
|
||||
output.WriteDouble(TimeUser);
|
||||
}
|
||||
if (TimeSystem != 0D) {
|
||||
output.WriteRawTag(33);
|
||||
output.WriteDouble(TimeSystem);
|
||||
}
|
||||
}
|
||||
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (latencies_ != null) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Latencies);
|
||||
}
|
||||
if (TimeElapsed != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
if (TimeUser != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
if (TimeSystem != 0D) {
|
||||
size += 1 + 8;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void MergeFrom(ClientStats other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.latencies_ != null) {
|
||||
if (latencies_ == null) {
|
||||
latencies_ = new global::Grpc.Testing.HistogramData();
|
||||
}
|
||||
Latencies.MergeFrom(other.Latencies);
|
||||
}
|
||||
if (other.TimeElapsed != 0D) {
|
||||
TimeElapsed = other.TimeElapsed;
|
||||
}
|
||||
if (other.TimeUser != 0D) {
|
||||
TimeUser = other.TimeUser;
|
||||
}
|
||||
if (other.TimeSystem != 0D) {
|
||||
TimeSystem = other.TimeSystem;
|
||||
}
|
||||
}
|
||||
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
input.SkipLastField();
|
||||
break;
|
||||
case 10: {
|
||||
if (latencies_ == null) {
|
||||
latencies_ = new global::Grpc.Testing.HistogramData();
|
||||
}
|
||||
input.ReadMessage(latencies_);
|
||||
break;
|
||||
}
|
||||
case 17: {
|
||||
TimeElapsed = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
case 25: {
|
||||
TimeUser = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
case 33: {
|
||||
TimeSystem = input.ReadDouble();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
#endregion Designer generated code
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
using NUnit.Framework;
|
||||
using Grpc.Testing;
|
||||
|
||||
namespace Grpc.IntegrationTesting
|
||||
{
|
||||
/// <summary>
|
||||
/// Snapshottable wall clock stopwatch.
|
||||
/// </summary>
|
||||
public class WallClockStopwatch
|
||||
{
|
||||
long startTicks;
|
||||
|
||||
public WallClockStopwatch()
|
||||
{
|
||||
this.startTicks = DateTime.UtcNow.Ticks;
|
||||
}
|
||||
|
||||
public TimeSpan GetElapsedSnapshot(bool reset)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
long oldStartTicks;
|
||||
if (reset)
|
||||
{
|
||||
oldStartTicks = Interlocked.Exchange(ref this.startTicks, utcNow.Ticks);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldStartTicks = this.startTicks;
|
||||
}
|
||||
return utcNow - new DateTime(oldStartTicks, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Utils;
|
||||
using Grpc.IntegrationTesting;
|
||||
|
||||
namespace Grpc.Testing
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of WorkerService server
|
||||
/// </summary>
|
||||
public class WorkerServiceImpl : WorkerService.IWorkerService
|
||||
{
|
||||
public async Task RunServer(IAsyncStreamReader<ServerArgs> requestStream, IServerStreamWriter<ServerStatus> responseStream, ServerCallContext context)
|
||||
{
|
||||
Grpc.Core.Utils.Preconditions.CheckState(await requestStream.MoveNext());
|
||||
var serverConfig = requestStream.Current.Setup;
|
||||
var runner = ServerRunners.CreateStarted(serverConfig);
|
||||
|
||||
await responseStream.WriteAsync(new ServerStatus
|
||||
{
|
||||
Stats = runner.GetStats(false),
|
||||
Port = runner.BoundPort,
|
||||
Cores = 0, // TODO: set number of cores
|
||||
});
|
||||
|
||||
while (await requestStream.MoveNext())
|
||||
{
|
||||
var reset = requestStream.Current.Mark.Reset;
|
||||
await responseStream.WriteAsync(new ServerStatus
|
||||
{
|
||||
Stats = runner.GetStats(reset)
|
||||
});
|
||||
}
|
||||
await runner.StopAsync();
|
||||
}
|
||||
|
||||
public async Task RunClient(IAsyncStreamReader<ClientArgs> requestStream, IServerStreamWriter<ClientStatus> responseStream, ServerCallContext context)
|
||||
{
|
||||
Grpc.Core.Utils.Preconditions.CheckState(await requestStream.MoveNext());
|
||||
var clientConfig = requestStream.Current.Setup;
|
||||
var runner = ClientRunners.CreateStarted(clientConfig);
|
||||
|
||||
await responseStream.WriteAsync(new ClientStatus
|
||||
{
|
||||
Stats = runner.GetStats(false)
|
||||
});
|
||||
|
||||
while (await requestStream.MoveNext())
|
||||
{
|
||||
var reset = requestStream.Current.Mark.Reset;
|
||||
await responseStream.WriteAsync(new ClientStatus
|
||||
{
|
||||
Stats = runner.GetStats(reset)
|
||||
});
|
||||
}
|
||||
await runner.StopAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
# Visual Studio 2012
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples", "Grpc.Examples\Grpc.Examples.csproj", "{7DC1433E-3225-42C7-B7EA-546D56E27A4B}"
|
||||
|
|
@ -32,6 +32,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck", "Grpc.He
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.csproj", "{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.QpsWorker", "Grpc.IntegrationTesting.QpsWorker\Grpc.IntegrationTesting.QpsWorker.csproj", "{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -39,72 +41,78 @@ Global
|
|||
ReleaseSigned|Any CPU = ReleaseSigned|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
@ -112,6 +120,8 @@ Global
|
|||
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
|
||||
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
|
|
|
|||
|
|
@ -35,14 +35,14 @@ cd $(dirname $0)
|
|||
PROTOC=../../bins/opt/protobuf/protoc
|
||||
PLUGIN=protoc-gen-grpc=../../bins/opt/grpc_csharp_plugin
|
||||
EXAMPLES_DIR=Grpc.Examples
|
||||
INTEROP_DIR=Grpc.IntegrationTesting
|
||||
TESTING_DIR=Grpc.IntegrationTesting
|
||||
HEALTHCHECK_DIR=Grpc.HealthCheck
|
||||
|
||||
$PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
|
||||
-I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
|
||||
|
||||
$PROTOC --plugin=$PLUGIN --csharp_out=$INTEROP_DIR --grpc_out=$INTEROP_DIR \
|
||||
-I ../.. ../../test/proto/*.proto
|
||||
$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \
|
||||
-I ../.. ../../test/proto/*.proto ../../test/proto/benchmarks/*.proto
|
||||
|
||||
$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
|
||||
-I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto
|
||||
|
|
|
|||
|
|
@ -269,8 +269,8 @@ int *perform_request(servers_fixture *f, grpc_channel *client,
|
|||
memset(s_valid, 0, f->num_servers * sizeof(int));
|
||||
|
||||
c = grpc_channel_create_call(client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
|
||||
"/foo", "foo.test.google.fr", gpr_inf_future(GPR_CLOCK_REALTIME),
|
||||
NULL);
|
||||
"/foo", "foo.test.google.fr",
|
||||
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
|
||||
GPR_ASSERT(c);
|
||||
completed_client = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,6 @@ void grpc_end2end_proxy_destroy(grpc_end2end_proxy *proxy) {
|
|||
}
|
||||
|
||||
static void unrefpc(proxy_call *pc, const char *reason) {
|
||||
gpr_log(GPR_DEBUG, "PROXY UNREF %s", reason);
|
||||
if (gpr_unref(&pc->refs)) {
|
||||
grpc_call_destroy(pc->c2p);
|
||||
grpc_call_destroy(pc->p2s);
|
||||
|
|
@ -158,10 +157,7 @@ static void unrefpc(proxy_call *pc, const char *reason) {
|
|||
}
|
||||
}
|
||||
|
||||
static void refpc(proxy_call *pc, const char *reason) {
|
||||
gpr_log(GPR_DEBUG, "PROXY REF %s", reason);
|
||||
gpr_ref(&pc->refs);
|
||||
}
|
||||
static void refpc(proxy_call *pc, const char *reason) { gpr_ref(&pc->refs); }
|
||||
|
||||
static void on_c2p_sent_initial_metadata(void *arg, int success) {
|
||||
proxy_call *pc = arg;
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ import collections
|
|||
import hashlib
|
||||
|
||||
|
||||
FixtureOptions = collections.namedtuple('FixtureOptions', 'fullstack includes_proxy dns_resolver secure platforms ci_mac')
|
||||
default_unsecure_fixture_options = FixtureOptions(True, False, True, False, ['windows', 'linux', 'mac', 'posix'], True)
|
||||
FixtureOptions = collections.namedtuple('FixtureOptions', 'fullstack includes_proxy dns_resolver secure platforms ci_mac tracing')
|
||||
default_unsecure_fixture_options = FixtureOptions(True, False, True, False, ['windows', 'linux', 'mac', 'posix'], True, False)
|
||||
socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(fullstack=False, dns_resolver=False)
|
||||
default_secure_fixture_options = default_unsecure_fixture_options._replace(secure=True)
|
||||
uds_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, platforms=['linux', 'mac', 'posix'])
|
||||
|
|
@ -54,7 +54,7 @@ END2END_FIXTURES = {
|
|||
'h2_proxy': default_unsecure_fixture_options._replace(includes_proxy=True, ci_mac=False),
|
||||
'h2_sockpair_1byte': socketpair_unsecure_fixture_options._replace(ci_mac=False),
|
||||
'h2_sockpair': socketpair_unsecure_fixture_options._replace(ci_mac=False),
|
||||
'h2_sockpair+trace': socketpair_unsecure_fixture_options,
|
||||
'h2_sockpair+trace': socketpair_unsecure_fixture_options._replace(tracing=True),
|
||||
'h2_ssl': default_secure_fixture_options,
|
||||
'h2_ssl+poll': default_secure_fixture_options._replace(platforms=['linux']),
|
||||
'h2_ssl_proxy': default_secure_fixture_options._replace(includes_proxy=True, ci_mac=False),
|
||||
|
|
@ -63,8 +63,8 @@ END2END_FIXTURES = {
|
|||
'h2_uds': uds_fixture_options,
|
||||
}
|
||||
|
||||
TestOptions = collections.namedtuple('TestOptions', 'needs_fullstack needs_dns proxyable flaky secure')
|
||||
default_test_options = TestOptions(False, False, True, False, False)
|
||||
TestOptions = collections.namedtuple('TestOptions', 'needs_fullstack needs_dns proxyable flaky secure traceable')
|
||||
default_test_options = TestOptions(False, False, True, False, False, True)
|
||||
connectivity_test_options = default_test_options._replace(needs_fullstack=True)
|
||||
|
||||
# maps test names to options
|
||||
|
|
@ -85,6 +85,7 @@ END2END_TESTS = {
|
|||
'disappearing_server': connectivity_test_options,
|
||||
'empty_batch': default_test_options,
|
||||
'graceful_server_shutdown': default_test_options,
|
||||
'hpack_size': default_test_options._replace(proxyable=False, traceable=False),
|
||||
'high_initial_seqno': default_test_options,
|
||||
'invoke_large_request': default_test_options,
|
||||
'large_metadata': default_test_options,
|
||||
|
|
@ -117,6 +118,9 @@ def compatible(f, t):
|
|||
if not END2END_TESTS[t].proxyable:
|
||||
if END2END_FIXTURES[f].includes_proxy:
|
||||
return False
|
||||
if not END2END_TESTS[t].traceable:
|
||||
if END2END_FIXTURES[f].tracing:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,8 @@ static void simple_request_body(grpc_end2end_test_fixture f, size_t num_ops) {
|
|||
cq_verifier_destroy(cqv);
|
||||
}
|
||||
|
||||
static void test_invoke_simple_request(grpc_end2end_test_config config, size_t num_ops) {
|
||||
static void test_invoke_simple_request(grpc_end2end_test_config config,
|
||||
size_t num_ops) {
|
||||
grpc_end2end_test_fixture f;
|
||||
|
||||
f = begin_test(config, "test_invoke_simple_request", NULL, NULL);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,446 @@
|
|||
/*
|
||||
*
|
||||
* 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/core/end2end/end2end_tests.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <grpc/byte_buffer.h>
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/string_util.h>
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpc/support/useful.h>
|
||||
|
||||
#include "src/core/support/string.h"
|
||||
#include "test/core/end2end/cq_verifier.h"
|
||||
|
||||
static void *tag(gpr_intptr t) { return (void *)t; }
|
||||
|
||||
const char *hobbits[][2] = {{"Adaldrida", "Brandybuck"},
|
||||
{"Adamanta", "Took"},
|
||||
{"Adalgrim", "Took"},
|
||||
{"Adelard", "Took"},
|
||||
{"Amaranth", "Brandybuck"},
|
||||
{"Andwise", "Roper"},
|
||||
{"Angelica", "Baggins"},
|
||||
{"Asphodel", "Burrows"},
|
||||
{"Balbo", "Baggins"},
|
||||
{"Bandobras", "Took"},
|
||||
{"Belba", "Bolger"},
|
||||
{"Bell", "Gamgee"},
|
||||
{"Belladonna", "Baggins"},
|
||||
{"Berylla", "Baggins"},
|
||||
{"Bilbo", "Baggins"},
|
||||
{"Bilbo", "Gardner"},
|
||||
{"Bill", "Butcher"},
|
||||
{"Bingo", "Baggins"},
|
||||
{"Bodo", "Proudfoot"},
|
||||
{"Bowman", "Cotton"},
|
||||
{"Bungo", "Baggins"},
|
||||
{"Camellia", "Sackville"},
|
||||
{"Carl", "Cotton"},
|
||||
{"Celandine", "Brandybuck"},
|
||||
{"Chica", "Baggins"},
|
||||
{"Daddy", "Twofoot"},
|
||||
{"Daisy", "Boffin"},
|
||||
{"Diamond", "Took"},
|
||||
{"Dinodas", "Brandybuck"},
|
||||
{"Doderic", "Brandybuck"},
|
||||
{"Dodinas", "Brandybuck"},
|
||||
{"Donnamira", "Boffin"},
|
||||
{"Dora", "Baggins"},
|
||||
{"Drogo", "Baggins"},
|
||||
{"Dudo", "Baggins"},
|
||||
{"Eglantine", "Took"},
|
||||
{"Elanor", "Fairbairn"},
|
||||
{"Elfstan", "Fairbairn"},
|
||||
{"Esmeralda", "Brandybuck"},
|
||||
{"Estella", "Brandybuck"},
|
||||
{"Everard", "Took"},
|
||||
{"Falco", "Chubb-Baggins"},
|
||||
{"Faramir", "Took"},
|
||||
{"Farmer", "Maggot"},
|
||||
{"Fastolph", "Bolger"},
|
||||
{"Ferdibrand", "Took"},
|
||||
{"Ferdinand", "Took"},
|
||||
{"Ferumbras", "Took"},
|
||||
{"Ferumbras", "Took"},
|
||||
{"Filibert", "Bolger"},
|
||||
{"Firiel", "Fairbairn"},
|
||||
{"Flambard", "Took"},
|
||||
{"Folco", "Boffin"},
|
||||
{"Fortinbras", "Took"},
|
||||
{"Fortinbras", "Took"},
|
||||
{"Fosco", "Baggins"},
|
||||
{"Fredegar", "Bolger"},
|
||||
{"Frodo", "Baggins"},
|
||||
{"Frodo", "Gardner"},
|
||||
{"Gerontius", "Took"},
|
||||
{"Gilly", "Baggins"},
|
||||
{"Goldilocks", "Took"},
|
||||
{"Gorbadoc", "Brandybuck"},
|
||||
{"Gorbulas", "Brandybuck"},
|
||||
{"Gorhendad", "Brandybuck"},
|
||||
{"Gormadoc", "Brandybuck"},
|
||||
{"Griffo", "Boffin"},
|
||||
{"Halfast", "Gamgee"},
|
||||
{"Halfred", "Gamgee"},
|
||||
{"Halfred", "Greenhand"},
|
||||
{"Hanna", "Brandybuck"},
|
||||
{"Hamfast", "Gamgee"},
|
||||
{"Hamfast", "Gardner"},
|
||||
{"Hamson", "Gamgee"},
|
||||
{"Harding", "Gardner"},
|
||||
{"Hilda", "Brandybuck"},
|
||||
{"Hildibrand", "Took"},
|
||||
{"Hildifons", "Took"},
|
||||
{"Hildigard", "Took"},
|
||||
{"Hildigrim", "Took"},
|
||||
{"Hob", "Gammidge"},
|
||||
{"Hob", "Hayward"},
|
||||
{"Hobson", "Gamgee"},
|
||||
{"Holfast", "Gardner"},
|
||||
{"Holman", "Cotton"},
|
||||
{"Holman", "Greenhand"},
|
||||
{"Hugo", "Boffin"},
|
||||
{"Hugo", "Bracegirdle"},
|
||||
{"Ilberic", "Brandybuck"},
|
||||
{"Isembard", "Took"},
|
||||
{"Isembold", "Took"},
|
||||
{"Isengar", "Took"},
|
||||
{"Isengrim", "Took"},
|
||||
{"Isengrim", "Took"},
|
||||
{"Isumbras", "Took"},
|
||||
{"Isumbras", "Took"},
|
||||
{"Jolly", "Cotton"},
|
||||
{"Lalia", "Took"},
|
||||
{"Largo", "Baggins"},
|
||||
{"Laura", "Baggins"},
|
||||
{"Lily", "Goodbody"},
|
||||
{"Lily", "Cotton"},
|
||||
{"Linda", "Proudfoot"},
|
||||
{"Lobelia", "Sackville-Baggins"},
|
||||
{"Longo", "Baggins"},
|
||||
{"Lotho", "Sackville-Baggins"},
|
||||
{"Madoc", "Brandybuck"},
|
||||
{"Malva", "Brandybuck"},
|
||||
{"Marigold", "Cotton"},
|
||||
{"Marmadas", "Brandybuck"},
|
||||
{"Marmadoc", "Brandybuck"},
|
||||
{"Marroc", "Brandybuck"},
|
||||
{"May", "Gamgee"},
|
||||
{"Melilot", "Brandybuck"},
|
||||
{"Menegilda", "Brandybuck"},
|
||||
{"Mentha", "Brandybuck"},
|
||||
{"Meriadoc", "Brandybuck"},
|
||||
{"Merimac", "Brandybuck"},
|
||||
{"Merimas", "Brandybuck"},
|
||||
{"Merry", "Gardner"},
|
||||
{"Milo", "Burrows"},
|
||||
{"Mimosa", "Baggins"},
|
||||
{"Minto", "Burrows"},
|
||||
{"Mirabella", "Brandybuck"},
|
||||
{"Moro", "Burrows"},
|
||||
{"Mosco", "Burrows"},
|
||||
{"Mungo", "Baggins"},
|
||||
{"Myrtle", "Burrows"},
|
||||
{"Odo", "Proudfoot"},
|
||||
{"Odovacar", "Bolger"},
|
||||
{"Olo", "Proudfoot"},
|
||||
{"Orgulas", "Brandybuck"},
|
||||
{"Otho", "Sackville-Baggins"},
|
||||
{"Paladin", "Took"},
|
||||
{"Pansy", "Bolger"},
|
||||
{"Pearl", "Took"},
|
||||
{"Peony", "Burrows"},
|
||||
{"Peregrin", "Took"},
|
||||
{"Pervinca", "Took"},
|
||||
{"Pimpernel", "Took"},
|
||||
{"Pippin", "Gardner"},
|
||||
{"Polo", "Baggins"},
|
||||
{"Ponto", "Baggins"},
|
||||
{"Porto", "Baggins"},
|
||||
{"Posco", "Baggins"},
|
||||
{"Poppy", "Bolger"},
|
||||
{"Primrose", "Gardner"},
|
||||
{"Primula", "Baggins"},
|
||||
{"Prisca", "Bolger"},
|
||||
{"Reginard", "Took"},
|
||||
{"Robin", "Smallburrow"},
|
||||
{"Robin", "Gardner"},
|
||||
{"Rorimac", "Brandybuck"},
|
||||
{"Rosa", "Took"},
|
||||
{"Rosamunda", "Bolger"},
|
||||
{"Rose", "Gardner"},
|
||||
{"Ruby", "Baggins"},
|
||||
{"Ruby", "Gardner"},
|
||||
{"Rudigar", "Bolger"},
|
||||
{"Rufus", "Burrows"},
|
||||
{"Sadoc", "Brandybuck"},
|
||||
{"Salvia", "Bolger"},
|
||||
{"Samwise", "Gamgee"},
|
||||
{"Sancho", "Proudfoot"},
|
||||
{"Saradas", "Brandybuck"},
|
||||
{"Saradoc", "Brandybuck"},
|
||||
{"Seredic", "Brandybuck"},
|
||||
{"Sigismond", "Took"},
|
||||
{"Smeagol", "Gollum"},
|
||||
{"Tanta", "Baggins"},
|
||||
{"Ted", "Sandyman"},
|
||||
{"Tobold", "Hornblower"},
|
||||
{"Togo", "Goodbody"},
|
||||
{"Tolman", "Cotton"},
|
||||
{"Tolman", "Gardner"},
|
||||
{"Widow", "Rumble"},
|
||||
{"Wilcome", "Cotton"},
|
||||
{"Wilcome", "Cotton"},
|
||||
{"Wilibald", "Bolger"},
|
||||
{"Will", "Whitfoot"},
|
||||
{"Wiseman", "Gamwich"}};
|
||||
|
||||
const char *dragons[] = {"Ancalagon", "Glaurung", "Scatha",
|
||||
"Smaug the Magnificent"};
|
||||
|
||||
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
|
||||
const char *test_name,
|
||||
grpc_channel_args *client_args,
|
||||
grpc_channel_args *server_args) {
|
||||
grpc_end2end_test_fixture f;
|
||||
gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
|
||||
f = config.create_fixture(client_args, server_args);
|
||||
config.init_client(&f, client_args);
|
||||
config.init_server(&f, server_args);
|
||||
return f;
|
||||
}
|
||||
|
||||
static gpr_timespec n_seconds_time(int n) {
|
||||
return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n);
|
||||
}
|
||||
|
||||
static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
|
||||
|
||||
static void drain_cq(grpc_completion_queue *cq) {
|
||||
grpc_event ev;
|
||||
do {
|
||||
ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
|
||||
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
|
||||
}
|
||||
|
||||
static void shutdown_server(grpc_end2end_test_fixture *f) {
|
||||
if (!f->server) return;
|
||||
grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
|
||||
GPR_ASSERT(grpc_completion_queue_pluck(
|
||||
f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
|
||||
.type == GRPC_OP_COMPLETE);
|
||||
grpc_server_destroy(f->server);
|
||||
f->server = NULL;
|
||||
}
|
||||
|
||||
static void shutdown_client(grpc_end2end_test_fixture *f) {
|
||||
if (!f->client) return;
|
||||
grpc_channel_destroy(f->client);
|
||||
f->client = NULL;
|
||||
}
|
||||
|
||||
static void end_test(grpc_end2end_test_fixture *f) {
|
||||
shutdown_server(f);
|
||||
shutdown_client(f);
|
||||
|
||||
grpc_completion_queue_shutdown(f->cq);
|
||||
drain_cq(f->cq);
|
||||
grpc_completion_queue_destroy(f->cq);
|
||||
}
|
||||
|
||||
static void simple_request_body(grpc_end2end_test_fixture f, size_t index) {
|
||||
grpc_call *c;
|
||||
grpc_call *s;
|
||||
gpr_timespec deadline = five_seconds_time();
|
||||
cq_verifier *cqv = cq_verifier_create(f.cq);
|
||||
grpc_op ops[6];
|
||||
grpc_op *op;
|
||||
grpc_metadata_array initial_metadata_recv;
|
||||
grpc_metadata_array trailing_metadata_recv;
|
||||
grpc_metadata_array request_metadata_recv;
|
||||
grpc_call_details call_details;
|
||||
grpc_status_code status;
|
||||
grpc_call_error error;
|
||||
grpc_metadata extra_metadata[3];
|
||||
char *details = NULL;
|
||||
size_t details_capacity = 0;
|
||||
int was_cancelled = 2;
|
||||
|
||||
memset(extra_metadata, 0, sizeof(extra_metadata));
|
||||
extra_metadata[0].key = "hobbit-first-name";
|
||||
extra_metadata[0].value = hobbits[index % GPR_ARRAY_SIZE(hobbits)][0];
|
||||
extra_metadata[0].value_length = strlen(extra_metadata[0].value);
|
||||
extra_metadata[1].key = "hobbit-second-name";
|
||||
extra_metadata[1].value = hobbits[index % GPR_ARRAY_SIZE(hobbits)][1];
|
||||
extra_metadata[1].value_length = strlen(extra_metadata[1].value);
|
||||
extra_metadata[2].key = "dragon";
|
||||
extra_metadata[2].value = dragons[index % GPR_ARRAY_SIZE(dragons)];
|
||||
extra_metadata[2].value_length = strlen(extra_metadata[2].value);
|
||||
|
||||
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
|
||||
"/foo", "foo.test.google.fr:1234", deadline,
|
||||
NULL);
|
||||
GPR_ASSERT(c);
|
||||
|
||||
grpc_metadata_array_init(&initial_metadata_recv);
|
||||
grpc_metadata_array_init(&trailing_metadata_recv);
|
||||
grpc_metadata_array_init(&request_metadata_recv);
|
||||
grpc_call_details_init(&call_details);
|
||||
|
||||
op = ops;
|
||||
op->op = GRPC_OP_SEND_INITIAL_METADATA;
|
||||
op->data.send_initial_metadata.count = GPR_ARRAY_SIZE(extra_metadata);
|
||||
op->data.send_initial_metadata.metadata = extra_metadata;
|
||||
op->flags = 0;
|
||||
op->reserved = NULL;
|
||||
op++;
|
||||
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
|
||||
op->flags = 0;
|
||||
op->reserved = NULL;
|
||||
op++;
|
||||
op->op = GRPC_OP_RECV_INITIAL_METADATA;
|
||||
op->data.recv_initial_metadata = &initial_metadata_recv;
|
||||
op->flags = 0;
|
||||
op->reserved = NULL;
|
||||
op++;
|
||||
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
|
||||
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
|
||||
op->data.recv_status_on_client.status = &status;
|
||||
op->data.recv_status_on_client.status_details = &details;
|
||||
op->data.recv_status_on_client.status_details_capacity = &details_capacity;
|
||||
op->flags = 0;
|
||||
op->reserved = NULL;
|
||||
op++;
|
||||
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
|
||||
GPR_ASSERT(GRPC_CALL_OK == error);
|
||||
|
||||
error =
|
||||
grpc_server_request_call(f.server, &s, &call_details,
|
||||
&request_metadata_recv, f.cq, f.cq, tag(101));
|
||||
GPR_ASSERT(GRPC_CALL_OK == error);
|
||||
cq_expect_completion(cqv, tag(101), 1);
|
||||
cq_verify(cqv);
|
||||
|
||||
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_STATUS_FROM_SERVER;
|
||||
op->data.send_status_from_server.trailing_metadata_count = 0;
|
||||
op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
|
||||
op->data.send_status_from_server.status_details = "xyz";
|
||||
op->flags = 0;
|
||||
op->reserved = NULL;
|
||||
op++;
|
||||
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
|
||||
op->data.recv_close_on_server.cancelled = &was_cancelled;
|
||||
op->flags = 0;
|
||||
op->reserved = NULL;
|
||||
op++;
|
||||
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
|
||||
GPR_ASSERT(GRPC_CALL_OK == error);
|
||||
|
||||
cq_expect_completion(cqv, tag(102), 1);
|
||||
cq_expect_completion(cqv, tag(1), 1);
|
||||
cq_verify(cqv);
|
||||
|
||||
GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
|
||||
GPR_ASSERT(0 == strcmp(details, "xyz"));
|
||||
GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
|
||||
GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
|
||||
GPR_ASSERT(was_cancelled == 1);
|
||||
|
||||
gpr_free(details);
|
||||
grpc_metadata_array_destroy(&initial_metadata_recv);
|
||||
grpc_metadata_array_destroy(&trailing_metadata_recv);
|
||||
grpc_metadata_array_destroy(&request_metadata_recv);
|
||||
grpc_call_details_destroy(&call_details);
|
||||
|
||||
grpc_call_destroy(c);
|
||||
grpc_call_destroy(s);
|
||||
|
||||
cq_verifier_destroy(cqv);
|
||||
}
|
||||
|
||||
static void test_size(grpc_end2end_test_config config, int encode_size,
|
||||
int decode_size) {
|
||||
size_t i;
|
||||
grpc_end2end_test_fixture f;
|
||||
grpc_arg server_arg;
|
||||
grpc_channel_args server_args;
|
||||
grpc_arg client_arg;
|
||||
grpc_channel_args client_args;
|
||||
char *name;
|
||||
|
||||
server_arg.type = GRPC_ARG_INTEGER;
|
||||
server_arg.key = GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER;
|
||||
server_arg.value.integer = decode_size;
|
||||
server_args.num_args = 1;
|
||||
server_args.args = &server_arg;
|
||||
|
||||
client_arg.type = GRPC_ARG_INTEGER;
|
||||
client_arg.key = GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER;
|
||||
client_arg.value.integer = encode_size;
|
||||
client_args.num_args = 1;
|
||||
client_args.args = &client_arg;
|
||||
|
||||
gpr_asprintf(&name, "test_size:e=%d:d=%d", encode_size, decode_size);
|
||||
f = begin_test(config, name, encode_size != 4096 ? &client_args : NULL,
|
||||
decode_size != 4096 ? &server_args : NULL);
|
||||
for (i = 0; i < 4 * GPR_ARRAY_SIZE(hobbits); i++) {
|
||||
simple_request_body(f, i);
|
||||
}
|
||||
end_test(&f);
|
||||
config.tear_down_data(&f);
|
||||
gpr_free(name);
|
||||
}
|
||||
|
||||
void grpc_end2end_tests(grpc_end2end_test_config config) {
|
||||
static const int interesting_sizes[] = {4096, 0, 100,
|
||||
1000, 32768, 4 * 1024 * 1024};
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < GPR_ARRAY_SIZE(interesting_sizes); i++) {
|
||||
for (j = 0; j < GPR_ARRAY_SIZE(interesting_sizes); j++) {
|
||||
test_size(config, interesting_sizes[i], interesting_sizes[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -163,7 +163,8 @@ static void simple_request_body(grpc_end2end_test_fixture f, size_t num_ops) {
|
|||
cq_verifier_destroy(cqv);
|
||||
}
|
||||
|
||||
static void test_invoke_simple_request(grpc_end2end_test_config config, size_t num_ops) {
|
||||
static void test_invoke_simple_request(grpc_end2end_test_config config,
|
||||
size_t num_ops) {
|
||||
grpc_end2end_test_fixture f;
|
||||
|
||||
f = begin_test(config, "test_invoke_simple_request", NULL, NULL);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ static int poll_read_bytes(int fd, char *buf, size_t read_size, int spin) {
|
|||
gpr_log(GPR_ERROR, "Read failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
bytes_read += (size_t) err2;
|
||||
bytes_read += (size_t)err2;
|
||||
} while (bytes_read < read_size);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -174,11 +174,11 @@ static int epoll_read_bytes(struct thread_args *args, char *buf, int spin) {
|
|||
GPR_ASSERT(ev.data.fd == args->fds.read_fd);
|
||||
do {
|
||||
do {
|
||||
err2 = read(args->fds.read_fd, buf + bytes_read,
|
||||
read_size - bytes_read);
|
||||
err2 =
|
||||
read(args->fds.read_fd, buf + bytes_read, read_size - bytes_read);
|
||||
} while (err2 < 0 && errno == EINTR);
|
||||
if (errno == EAGAIN) break;
|
||||
bytes_read += (size_t) err2;
|
||||
bytes_read += (size_t)err2;
|
||||
/* TODO(klempner): This should really be doing an extra call after we are
|
||||
done to ensure we see an EAGAIN */
|
||||
} while (bytes_read < read_size);
|
||||
|
|
|
|||
|
|
@ -353,8 +353,8 @@ static void test_google_iam_creds(void) {
|
|||
test_google_iam_authorization_token, test_google_iam_authority_selector,
|
||||
NULL);
|
||||
grpc_call_credentials_get_request_metadata(&exec_ctx, creds, NULL,
|
||||
test_service_url,
|
||||
check_google_iam_metadata, creds);
|
||||
test_service_url,
|
||||
check_google_iam_metadata, creds);
|
||||
grpc_exec_ctx_finish(&exec_ctx);
|
||||
}
|
||||
|
||||
|
|
@ -436,7 +436,8 @@ static void test_oauth2_google_iam_composite_creds(void) {
|
|||
test_google_iam_authorization_token, test_google_iam_authority_selector,
|
||||
NULL);
|
||||
grpc_call_credentials *composite_creds =
|
||||
grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds, NULL);
|
||||
grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds,
|
||||
NULL);
|
||||
grpc_call_credentials_unref(oauth2_creds);
|
||||
grpc_call_credentials_unref(google_iam_creds);
|
||||
GPR_ASSERT(
|
||||
|
|
@ -481,7 +482,8 @@ static void test_channel_oauth2_google_iam_composite_creds(void) {
|
|||
grpc_call_credentials *oauth2_creds =
|
||||
grpc_access_token_credentials_create("blah", NULL);
|
||||
grpc_channel_credentials *channel_oauth2_creds =
|
||||
grpc_composite_channel_credentials_create(channel_creds, oauth2_creds, NULL);
|
||||
grpc_composite_channel_credentials_create(channel_creds, oauth2_creds,
|
||||
NULL);
|
||||
grpc_call_credentials *google_iam_creds = grpc_google_iam_credentials_create(
|
||||
test_google_iam_authorization_token, test_google_iam_authority_selector,
|
||||
NULL);
|
||||
|
|
|
|||
|
|
@ -185,8 +185,8 @@ static void test_byte_buffer_from_reader(void) {
|
|||
}
|
||||
|
||||
static void test_readall(void) {
|
||||
char* lotsa_as[512];
|
||||
char* lotsa_bs[1024];
|
||||
char *lotsa_as[512];
|
||||
char *lotsa_bs[1024];
|
||||
gpr_slice slices[2];
|
||||
grpc_byte_buffer *buffer;
|
||||
grpc_byte_buffer_reader reader;
|
||||
|
|
|
|||
|
|
@ -151,7 +151,8 @@ static void test_vectors(grpc_slice_split_mode mode) {
|
|||
grpc_chttp2_hpack_parser_destroy(&parser);
|
||||
|
||||
grpc_chttp2_hpack_parser_init(&parser, mdctx);
|
||||
parser.table.max_bytes = 256;
|
||||
grpc_chttp2_hptbl_set_max_bytes(&parser.table, 256);
|
||||
grpc_chttp2_hptbl_set_current_table_size(&parser.table, 256);
|
||||
/* D.5.1 */
|
||||
test_vector(&parser, mode,
|
||||
"4803 3330 3258 0770 7269 7661 7465 611d"
|
||||
|
|
@ -184,7 +185,8 @@ static void test_vectors(grpc_slice_split_mode mode) {
|
|||
grpc_chttp2_hpack_parser_destroy(&parser);
|
||||
|
||||
grpc_chttp2_hpack_parser_init(&parser, mdctx);
|
||||
parser.table.max_bytes = 256;
|
||||
grpc_chttp2_hptbl_set_max_bytes(&parser.table, 256);
|
||||
grpc_chttp2_hptbl_set_current_table_size(&parser.table, 256);
|
||||
/* D.6.1 */
|
||||
test_vector(&parser, mode,
|
||||
"4882 6402 5885 aec3 771a 4b61 96d0 7abe"
|
||||
|
|
|
|||
|
|
@ -143,9 +143,12 @@ static void test_many_additions(void) {
|
|||
grpc_chttp2_hptbl_init(&tbl, mdctx);
|
||||
|
||||
for (i = 0; i < 1000000; i++) {
|
||||
grpc_mdelem *elem;
|
||||
gpr_asprintf(&key, "K:%d", i);
|
||||
gpr_asprintf(&value, "VALUE:%d", i);
|
||||
grpc_chttp2_hptbl_add(&tbl, grpc_mdelem_from_strings(mdctx, key, value));
|
||||
elem = grpc_mdelem_from_strings(mdctx, key, value);
|
||||
GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem));
|
||||
GRPC_MDELEM_UNREF(elem);
|
||||
assert_index(&tbl, 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY, key, value);
|
||||
gpr_free(key);
|
||||
gpr_free(value);
|
||||
|
|
@ -173,18 +176,25 @@ static grpc_chttp2_hptbl_find_result find_simple(grpc_chttp2_hptbl *tbl,
|
|||
|
||||
static void test_find(void) {
|
||||
grpc_chttp2_hptbl tbl;
|
||||
int i;
|
||||
gpr_uint32 i;
|
||||
char buffer[32];
|
||||
grpc_mdctx *mdctx;
|
||||
grpc_mdelem *elem;
|
||||
grpc_chttp2_hptbl_find_result r;
|
||||
|
||||
LOG_TEST("test_find");
|
||||
|
||||
mdctx = grpc_mdctx_create();
|
||||
grpc_chttp2_hptbl_init(&tbl, mdctx);
|
||||
grpc_chttp2_hptbl_add(&tbl, grpc_mdelem_from_strings(mdctx, "abc", "xyz"));
|
||||
grpc_chttp2_hptbl_add(&tbl, grpc_mdelem_from_strings(mdctx, "abc", "123"));
|
||||
grpc_chttp2_hptbl_add(&tbl, grpc_mdelem_from_strings(mdctx, "x", "1"));
|
||||
elem = grpc_mdelem_from_strings(mdctx, "abc", "xyz");
|
||||
GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem));
|
||||
GRPC_MDELEM_UNREF(elem);
|
||||
elem = grpc_mdelem_from_strings(mdctx, "abc", "123");
|
||||
GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem));
|
||||
GRPC_MDELEM_UNREF(elem);
|
||||
elem = grpc_mdelem_from_strings(mdctx, "x", "1");
|
||||
GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem));
|
||||
GRPC_MDELEM_UNREF(elem);
|
||||
|
||||
r = find_simple(&tbl, "abc", "123");
|
||||
GPR_ASSERT(r.index == 2 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
|
||||
|
|
@ -233,8 +243,9 @@ static void test_find(void) {
|
|||
/* overflow the string buffer, check find still works */
|
||||
for (i = 0; i < 10000; i++) {
|
||||
gpr_ltoa(i, buffer);
|
||||
grpc_chttp2_hptbl_add(&tbl,
|
||||
grpc_mdelem_from_strings(mdctx, "test", buffer));
|
||||
elem = grpc_mdelem_from_strings(mdctx, "test", buffer);
|
||||
GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem));
|
||||
GRPC_MDELEM_UNREF(elem);
|
||||
}
|
||||
|
||||
r = find_simple(&tbl, "abc", "123");
|
||||
|
|
@ -250,7 +261,7 @@ static void test_find(void) {
|
|||
GPR_ASSERT(r.has_value == 1);
|
||||
|
||||
for (i = 0; i < tbl.num_ents; i++) {
|
||||
int expect = 9999 - i;
|
||||
gpr_uint32 expect = 9999 - i;
|
||||
gpr_ltoa(expect, buffer);
|
||||
|
||||
r = find_simple(&tbl, "test", buffer);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ void test_tcp_server_init(test_tcp_server *server,
|
|||
|
||||
void test_tcp_server_start(test_tcp_server *server, int port) {
|
||||
struct sockaddr_in addr;
|
||||
grpc_tcp_listener *listener;
|
||||
int port_added;
|
||||
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
|
||||
|
||||
|
|
@ -65,8 +66,8 @@ void test_tcp_server_start(test_tcp_server *server, int port) {
|
|||
memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
|
||||
|
||||
server->tcp_server = grpc_tcp_server_create();
|
||||
port_added =
|
||||
grpc_tcp_server_add_port(server->tcp_server, &addr, sizeof(addr));
|
||||
listener = grpc_tcp_server_add_port(server->tcp_server, &addr, sizeof(addr));
|
||||
port_added = grpc_tcp_listener_get_port(listener);
|
||||
GPR_ASSERT(port_added == port);
|
||||
|
||||
grpc_tcp_server_start(&exec_ctx, server->tcp_server, server->pollsets, 1,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
*
|
||||
* 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.
|
||||
*is % allowed in string
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <grpc++/grpc++.h>
|
||||
|
||||
#include "test/cpp/util/metrics_server.h"
|
||||
#include "test/cpp/util/test_config.h"
|
||||
#include "test/proto/metrics.grpc.pb.h"
|
||||
#include "test/proto/metrics.pb.h"
|
||||
|
||||
DEFINE_string(metrics_server_address, "",
|
||||
"The metrics server addresses in the fomrat <hostname>:<port>");
|
||||
|
||||
using grpc::testing::EmptyMessage;
|
||||
using grpc::testing::GaugeResponse;
|
||||
using grpc::testing::MetricsService;
|
||||
using grpc::testing::MetricsServiceImpl;
|
||||
|
||||
void PrintMetrics(grpc::string& server_address) {
|
||||
gpr_log(GPR_INFO, "creating a channel to %s", server_address.c_str());
|
||||
std::shared_ptr<grpc::Channel> channel(
|
||||
grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()));
|
||||
|
||||
std::unique_ptr<MetricsService::Stub> stub(MetricsService::NewStub(channel));
|
||||
|
||||
grpc::ClientContext context;
|
||||
EmptyMessage message;
|
||||
|
||||
std::unique_ptr<grpc::ClientReader<GaugeResponse>> reader(
|
||||
stub->GetAllGauges(&context, message));
|
||||
|
||||
GaugeResponse gauge_response;
|
||||
long overall_qps = 0;
|
||||
int idx = 0;
|
||||
while (reader->Read(&gauge_response)) {
|
||||
if (gauge_response.value_case() == GaugeResponse::kLongValue) {
|
||||
gpr_log(GPR_INFO, "Gauge: %d (%s: %ld)", ++idx,
|
||||
gauge_response.name().c_str(), gauge_response.long_value());
|
||||
overall_qps += gauge_response.long_value();
|
||||
} else {
|
||||
gpr_log(GPR_INFO, "Gauge %s is not a long value",
|
||||
gauge_response.name().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
gpr_log(GPR_INFO, "OVERALL: %ld", overall_qps);
|
||||
|
||||
const grpc::Status status = reader->Finish();
|
||||
if (!status.ok()) {
|
||||
gpr_log(GPR_ERROR, "Error in getting metrics from the client");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
grpc::testing::InitTest(&argc, &argv, true);
|
||||
|
||||
// Make sure server_addresses flag is not empty
|
||||
if (FLAGS_metrics_server_address.empty()) {
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"Cannot connect to the Metrics server. Please pass the address of the"
|
||||
"metrics server to connect to via the 'metrics_server_address' flag");
|
||||
return 1;
|
||||
}
|
||||
|
||||
PrintMetrics(FLAGS_metrics_server_address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
#include <grpc++/create_channel.h>
|
||||
|
||||
#include "test/cpp/interop/interop_client.h"
|
||||
#include "test/cpp/util/metrics_server.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace testing {
|
||||
|
|
@ -81,21 +82,19 @@ TestCaseType WeightedRandomTestSelector::GetNextTest() const {
|
|||
|
||||
StressTestInteropClient::StressTestInteropClient(
|
||||
int test_id, const grpc::string& server_address,
|
||||
std::shared_ptr<Channel> channel,
|
||||
const WeightedRandomTestSelector& test_selector, long test_duration_secs,
|
||||
long sleep_duration_ms)
|
||||
long sleep_duration_ms, long metrics_collection_interval_secs)
|
||||
: test_id_(test_id),
|
||||
server_address_(server_address),
|
||||
channel_(channel),
|
||||
interop_client_(new InteropClient(channel, false)),
|
||||
test_selector_(test_selector),
|
||||
test_duration_secs_(test_duration_secs),
|
||||
sleep_duration_ms_(sleep_duration_ms) {
|
||||
// TODO(sreek): This will change once we add support for other tests
|
||||
// that won't work with InsecureChannelCredentials()
|
||||
std::shared_ptr<Channel> channel(
|
||||
CreateChannel(server_address, InsecureChannelCredentials()));
|
||||
interop_client_.reset(new InteropClient(channel, false));
|
||||
}
|
||||
sleep_duration_ms_(sleep_duration_ms),
|
||||
metrics_collection_interval_secs_(metrics_collection_interval_secs) {}
|
||||
|
||||
void StressTestInteropClient::MainLoop() {
|
||||
void StressTestInteropClient::MainLoop(std::shared_ptr<Gauge> qps_gauge) {
|
||||
gpr_log(GPR_INFO, "Running test %d. ServerAddr: %s", test_id_,
|
||||
server_address_.c_str());
|
||||
|
||||
|
|
@ -104,21 +103,38 @@ void StressTestInteropClient::MainLoop() {
|
|||
gpr_time_from_seconds(test_duration_secs_, GPR_TIMESPAN));
|
||||
|
||||
gpr_timespec current_time = gpr_now(GPR_CLOCK_REALTIME);
|
||||
gpr_timespec next_stat_collection_time = current_time;
|
||||
gpr_timespec collection_interval =
|
||||
gpr_time_from_seconds(metrics_collection_interval_secs_, GPR_TIMESPAN);
|
||||
long num_calls_per_interval = 0;
|
||||
|
||||
while (test_duration_secs_ < 0 ||
|
||||
gpr_time_cmp(current_time, test_end_time) < 0) {
|
||||
gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), test_end_time) < 0) {
|
||||
// Select the test case to execute based on the weights and execute it
|
||||
TestCaseType test_case = test_selector_.GetNextTest();
|
||||
gpr_log(GPR_INFO, "%d - Executing the test case %d", test_id_, test_case);
|
||||
RunTest(test_case);
|
||||
|
||||
// Sleep between successive calls if needed
|
||||
if (sleep_duration_ms_ > 0) {
|
||||
gpr_timespec sleep_time = gpr_time_add(
|
||||
current_time, gpr_time_from_millis(sleep_duration_ms_, GPR_TIMESPAN));
|
||||
gpr_sleep_until(sleep_time);
|
||||
num_calls_per_interval++;
|
||||
|
||||
// See if its time to collect stats yet
|
||||
current_time = gpr_now(GPR_CLOCK_REALTIME);
|
||||
if (gpr_time_cmp(next_stat_collection_time, current_time) < 0) {
|
||||
qps_gauge->Set(num_calls_per_interval /
|
||||
metrics_collection_interval_secs_);
|
||||
|
||||
num_calls_per_interval = 0;
|
||||
next_stat_collection_time =
|
||||
gpr_time_add(current_time, collection_interval);
|
||||
}
|
||||
|
||||
current_time = gpr_now(GPR_CLOCK_REALTIME);
|
||||
// Sleep between successive calls if needed
|
||||
if (sleep_duration_ms_ > 0) {
|
||||
gpr_timespec sleep_time =
|
||||
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
|
||||
gpr_time_from_millis(sleep_duration_ms_, GPR_TIMESPAN));
|
||||
gpr_sleep_until(sleep_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include <grpc++/create_channel.h>
|
||||
|
||||
#include "test/cpp/interop/interop_client.h"
|
||||
#include "test/cpp/util/metrics_server.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace testing {
|
||||
|
|
@ -84,20 +85,26 @@ class WeightedRandomTestSelector {
|
|||
class StressTestInteropClient {
|
||||
public:
|
||||
StressTestInteropClient(int test_id, const grpc::string& server_address,
|
||||
std::shared_ptr<Channel> channel,
|
||||
const WeightedRandomTestSelector& test_selector,
|
||||
long test_duration_secs, long sleep_duration_ms);
|
||||
long test_duration_secs, long sleep_duration_ms,
|
||||
long metrics_collection_interval_secs);
|
||||
|
||||
void MainLoop(); // The main function. Use this as the thread entry point.
|
||||
// The main function. Use this as the thread entry point.
|
||||
// qps_gauge is the Gauge to record the requests per second metric
|
||||
void MainLoop(std::shared_ptr<Gauge> qps_gauge);
|
||||
|
||||
private:
|
||||
void RunTest(TestCaseType test_case);
|
||||
|
||||
int test_id_;
|
||||
std::unique_ptr<InteropClient> interop_client_;
|
||||
const grpc::string& server_address_;
|
||||
std::shared_ptr<Channel> channel_;
|
||||
std::unique_ptr<InteropClient> interop_client_;
|
||||
const WeightedRandomTestSelector& test_selector_;
|
||||
long test_duration_secs_;
|
||||
long sleep_duration_ms_;
|
||||
long metrics_collection_interval_secs_;
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
|
|
|
|||
|
|
@ -45,7 +45,15 @@
|
|||
|
||||
#include "test/cpp/interop/interop_client.h"
|
||||
#include "test/cpp/interop/stress_interop_client.h"
|
||||
#include "test/cpp/util/metrics_server.h"
|
||||
#include "test/cpp/util/test_config.h"
|
||||
#include "test/proto/metrics.grpc.pb.h"
|
||||
#include "test/proto/metrics.pb.h"
|
||||
|
||||
DEFINE_int32(metrics_port, 8081, "The metrics server port.");
|
||||
|
||||
DEFINE_int32(metrics_collection_interval_secs, 5,
|
||||
"How often (in seconds) should metrics be recorded.");
|
||||
|
||||
DEFINE_int32(sleep_duration_ms, 0,
|
||||
"The duration (in millisec) between two"
|
||||
|
|
@ -62,6 +70,11 @@ DEFINE_string(server_addresses, "localhost:8080",
|
|||
" \"<name_1>:<port_1>,<name_2>:<port_1>...<name_N>:<port_N>\"\n"
|
||||
" Note: <name> can be servername or IP address.");
|
||||
|
||||
DEFINE_int32(num_stubs_per_channel, 1,
|
||||
"Number of stubs per each channels to server. This number also "
|
||||
"indicates the max number of parallel RPC calls on each channel "
|
||||
"at any given time.");
|
||||
|
||||
// TODO(sreek): Add more test cases here in future
|
||||
DEFINE_string(test_cases, "",
|
||||
"List of test cases to call along with the"
|
||||
|
|
@ -79,15 +92,13 @@ DEFINE_string(test_cases, "",
|
|||
" 'large_unary', 10% of the time and 'empty_stream' the remaining"
|
||||
" 70% of the time");
|
||||
|
||||
using std::make_pair;
|
||||
using std::pair;
|
||||
using std::vector;
|
||||
|
||||
using grpc::testing::kTestCaseList;
|
||||
using grpc::testing::MetricsService;
|
||||
using grpc::testing::MetricsServiceImpl;
|
||||
using grpc::testing::StressTestInteropClient;
|
||||
using grpc::testing::TestCaseType;
|
||||
using grpc::testing::WeightedRandomTestSelector;
|
||||
using grpc::testing::UNKNOWN_TEST;
|
||||
using grpc::testing::WeightedRandomTestSelector;
|
||||
|
||||
TestCaseType GetTestTypeFromName(const grpc::string& test_name) {
|
||||
TestCaseType test_case = UNKNOWN_TEST;
|
||||
|
|
@ -104,7 +115,7 @@ TestCaseType GetTestTypeFromName(const grpc::string& test_name) {
|
|||
|
||||
// Converts a string of comma delimited tokens to a vector of tokens
|
||||
bool ParseCommaDelimitedString(const grpc::string& comma_delimited_str,
|
||||
vector<grpc::string>& tokens) {
|
||||
std::vector<grpc::string>& tokens) {
|
||||
size_t bpos = 0;
|
||||
size_t epos = grpc::string::npos;
|
||||
|
||||
|
|
@ -122,10 +133,10 @@ bool ParseCommaDelimitedString(const grpc::string& comma_delimited_str,
|
|||
// - Whether parsing was successful (return value)
|
||||
// - Vector of (test_type_enum, weight) pairs returned via 'tests' parameter
|
||||
bool ParseTestCasesString(const grpc::string& test_cases,
|
||||
vector<pair<TestCaseType, int>>& tests) {
|
||||
std::vector<std::pair<TestCaseType, int>>& tests) {
|
||||
bool is_success = true;
|
||||
|
||||
vector<grpc::string> tokens;
|
||||
std::vector<grpc::string> tokens;
|
||||
ParseCommaDelimitedString(test_cases, tokens);
|
||||
|
||||
for (auto it = tokens.begin(); it != tokens.end(); it++) {
|
||||
|
|
@ -153,8 +164,8 @@ bool ParseTestCasesString(const grpc::string& test_cases,
|
|||
}
|
||||
|
||||
// For debugging purposes
|
||||
void LogParameterInfo(const vector<grpc::string>& addresses,
|
||||
const vector<pair<TestCaseType, int>>& tests) {
|
||||
void LogParameterInfo(const std::vector<grpc::string>& addresses,
|
||||
const std::vector<std::pair<TestCaseType, int>>& tests) {
|
||||
gpr_log(GPR_INFO, "server_addresses: %s", FLAGS_server_addresses.c_str());
|
||||
gpr_log(GPR_INFO, "test_cases : %s", FLAGS_test_cases.c_str());
|
||||
gpr_log(GPR_INFO, "sleep_duration_ms: %d", FLAGS_sleep_duration_ms);
|
||||
|
|
@ -180,7 +191,7 @@ int main(int argc, char** argv) {
|
|||
srand(time(NULL));
|
||||
|
||||
// Parse the server addresses
|
||||
vector<grpc::string> server_addresses;
|
||||
std::vector<grpc::string> server_addresses;
|
||||
ParseCommaDelimitedString(FLAGS_server_addresses, server_addresses);
|
||||
|
||||
// Parse test cases and weights
|
||||
|
|
@ -189,7 +200,7 @@ int main(int argc, char** argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
vector<pair<TestCaseType, int>> tests;
|
||||
std::vector<std::pair<TestCaseType, int>> tests;
|
||||
if (!ParseTestCasesString(FLAGS_test_cases, tests)) {
|
||||
gpr_log(GPR_ERROR, "Error in parsing test cases string %s ",
|
||||
FLAGS_test_cases.c_str());
|
||||
|
|
@ -199,23 +210,48 @@ int main(int argc, char** argv) {
|
|||
LogParameterInfo(server_addresses, tests);
|
||||
|
||||
WeightedRandomTestSelector test_selector(tests);
|
||||
MetricsServiceImpl metrics_service;
|
||||
|
||||
gpr_log(GPR_INFO, "Starting test(s)..");
|
||||
|
||||
vector<grpc::thread> test_threads;
|
||||
std::vector<grpc::thread> test_threads;
|
||||
|
||||
int thread_idx = 0;
|
||||
for (auto it = server_addresses.begin(); it != server_addresses.end(); it++) {
|
||||
StressTestInteropClient* client = new StressTestInteropClient(
|
||||
++thread_idx, *it, test_selector, FLAGS_test_duration_secs,
|
||||
FLAGS_sleep_duration_ms);
|
||||
// TODO(sreek): This will change once we add support for other tests
|
||||
// that won't work with InsecureChannelCredentials()
|
||||
std::shared_ptr<grpc::Channel> channel(
|
||||
grpc::CreateChannel(*it, grpc::InsecureChannelCredentials()));
|
||||
|
||||
test_threads.emplace_back(
|
||||
grpc::thread(&StressTestInteropClient::MainLoop, client));
|
||||
// Make multiple stubs (as defined by num_stubs_per_channel flag) to use the
|
||||
// same channel. This is to test calling multiple RPC calls in parallel on
|
||||
// each channel.
|
||||
for (int i = 0; i < FLAGS_num_stubs_per_channel; i++) {
|
||||
StressTestInteropClient* client = new StressTestInteropClient(
|
||||
++thread_idx, *it, channel, test_selector, FLAGS_test_duration_secs,
|
||||
FLAGS_sleep_duration_ms, FLAGS_metrics_collection_interval_secs);
|
||||
|
||||
bool is_already_created;
|
||||
grpc::string metricName =
|
||||
"/stress_test/qps/thread/" + std::to_string(thread_idx);
|
||||
test_threads.emplace_back(grpc::thread(
|
||||
&StressTestInteropClient::MainLoop, client,
|
||||
metrics_service.CreateGauge(metricName, &is_already_created)));
|
||||
|
||||
// The Gauge should not have been already created
|
||||
GPR_ASSERT(!is_already_created);
|
||||
}
|
||||
}
|
||||
|
||||
// Start metrics server before waiting for the stress test threads
|
||||
std::unique_ptr<grpc::Server> metrics_server =
|
||||
metrics_service.StartServer(FLAGS_metrics_port);
|
||||
|
||||
// Wait for the stress test threads to complete
|
||||
for (auto it = test_threads.begin(); it != test_threads.end(); it++) {
|
||||
it->join();
|
||||
}
|
||||
|
||||
metrics_server->Wait();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ static void RunAsyncStreamingPingPong() {
|
|||
|
||||
ServerConfig server_config;
|
||||
server_config.set_server_type(ASYNC_SERVER);
|
||||
server_config.set_host("localhost");
|
||||
server_config.set_async_server_threads(1);
|
||||
|
||||
const auto result =
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ static void RunAsyncUnaryPingPong() {
|
|||
|
||||
ServerConfig server_config;
|
||||
server_config.set_server_type(ASYNC_SERVER);
|
||||
server_config.set_host("localhost");
|
||||
server_config.set_async_server_threads(1);
|
||||
|
||||
const auto result =
|
||||
|
|
|
|||
|
|
@ -181,29 +181,29 @@ class Client {
|
|||
|
||||
std::unique_ptr<RandomDist> random_dist;
|
||||
switch (load.load_case()) {
|
||||
case LoadParams::kClosedLoop:
|
||||
// Closed-loop doesn't use random dist at all
|
||||
break;
|
||||
case LoadParams::kPoisson:
|
||||
random_dist.reset(
|
||||
new ExpDist(load.poisson().offered_load() / num_threads));
|
||||
break;
|
||||
case LoadParams::kUniform:
|
||||
random_dist.reset(
|
||||
new UniformDist(load.uniform().interarrival_lo() * num_threads,
|
||||
load.uniform().interarrival_hi() * num_threads));
|
||||
break;
|
||||
case LoadParams::kDeterm:
|
||||
random_dist.reset(
|
||||
new DetDist(num_threads / load.determ().offered_load()));
|
||||
break;
|
||||
case LoadParams::kPareto:
|
||||
random_dist.reset(
|
||||
new ParetoDist(load.pareto().interarrival_base() * num_threads,
|
||||
load.pareto().alpha()));
|
||||
break;
|
||||
default:
|
||||
GPR_ASSERT(false);
|
||||
case LoadParams::kClosedLoop:
|
||||
// Closed-loop doesn't use random dist at all
|
||||
break;
|
||||
case LoadParams::kPoisson:
|
||||
random_dist.reset(
|
||||
new ExpDist(load.poisson().offered_load() / num_threads));
|
||||
break;
|
||||
case LoadParams::kUniform:
|
||||
random_dist.reset(
|
||||
new UniformDist(load.uniform().interarrival_lo() * num_threads,
|
||||
load.uniform().interarrival_hi() * num_threads));
|
||||
break;
|
||||
case LoadParams::kDeterm:
|
||||
random_dist.reset(
|
||||
new DetDist(num_threads / load.determ().offered_load()));
|
||||
break;
|
||||
case LoadParams::kPareto:
|
||||
random_dist.reset(
|
||||
new ParetoDist(load.pareto().interarrival_base() * num_threads,
|
||||
load.pareto().alpha()));
|
||||
break;
|
||||
default:
|
||||
GPR_ASSERT(false);
|
||||
}
|
||||
|
||||
// Set closed_loop_ based on whether or not random_dist is set
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ std::unique_ptr<ScenarioResult> RunScenario(
|
|||
list<ClientContext> contexts;
|
||||
|
||||
// To be added to the result, containing the final configuration used for
|
||||
// client and config (incluiding host, etc.)
|
||||
// client and config (including host, etc.)
|
||||
ClientConfig result_client_config;
|
||||
ServerConfig result_server_config;
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ namespace testing {
|
|||
|
||||
class Histogram {
|
||||
public:
|
||||
Histogram() : impl_(gpr_histogram_create(0.01, 60e9)) {}
|
||||
// TODO: look into making histogram params not hardcoded for C++
|
||||
Histogram()
|
||||
: impl_(gpr_histogram_create(default_resolution(),
|
||||
default_max_possible())) {}
|
||||
~Histogram() {
|
||||
if (impl_) gpr_histogram_destroy(impl_);
|
||||
}
|
||||
|
|
@ -73,6 +76,9 @@ class Histogram {
|
|||
p.sum_of_squares(), p.count());
|
||||
}
|
||||
|
||||
static double default_resolution() { return 0.01; }
|
||||
static double default_max_possible() { return 60e9; }
|
||||
|
||||
private:
|
||||
Histogram(const Histogram&);
|
||||
Histogram& operator=(const Histogram&);
|
||||
|
|
|
|||
|
|
@ -137,8 +137,14 @@ static void QpsDriver() {
|
|||
// No further load parameters to set up for closed loop
|
||||
}
|
||||
|
||||
client_config.mutable_histogram_params()->set_resolution(
|
||||
Histogram::default_resolution());
|
||||
client_config.mutable_histogram_params()->set_max_possible(
|
||||
Histogram::default_max_possible());
|
||||
|
||||
ServerConfig server_config;
|
||||
server_config.set_server_type(server_type);
|
||||
server_config.set_host("localhost");
|
||||
server_config.set_async_server_threads(FLAGS_async_server_threads);
|
||||
|
||||
if (FLAGS_secure_test) {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ static void RunQPS() {
|
|||
|
||||
ServerConfig server_config;
|
||||
server_config.set_server_type(ASYNC_SERVER);
|
||||
server_config.set_host("localhost");
|
||||
server_config.set_async_server_threads(4);
|
||||
|
||||
const auto result =
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ static void RunQPS() {
|
|||
|
||||
ServerConfig server_config;
|
||||
server_config.set_server_type(ASYNC_SERVER);
|
||||
server_config.set_host("localhost");
|
||||
server_config.set_async_server_threads(8);
|
||||
|
||||
const auto result =
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ static void RunQPS() {
|
|||
|
||||
ServerConfig server_config;
|
||||
server_config.set_server_type(ASYNC_SERVER);
|
||||
server_config.set_host("localhost");
|
||||
server_config.set_async_server_threads(4);
|
||||
|
||||
const auto result =
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ static void RunSynchronousUnaryPingPong() {
|
|||
|
||||
ServerConfig server_config;
|
||||
server_config.set_server_type(SYNC_SERVER);
|
||||
server_config.set_host("localhost");
|
||||
|
||||
// Set up security params
|
||||
SecurityParams security;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class AsyncQpsServerTest : public Server {
|
|||
explicit AsyncQpsServerTest(const ServerConfig &config) : Server(config) {
|
||||
char *server_address = NULL;
|
||||
|
||||
gpr_join_host_port(&server_address, "::", port());
|
||||
gpr_join_host_port(&server_address, config.host().c_str(), port());
|
||||
|
||||
ServerBuilder builder;
|
||||
builder.AddListeningPort(server_address,
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ class SynchronousServer GRPC_FINAL : public grpc::testing::Server {
|
|||
|
||||
char* server_address = NULL;
|
||||
|
||||
gpr_join_host_port(&server_address, "::", port());
|
||||
gpr_join_host_port(&server_address, config.host().c_str(), port());
|
||||
builder.AddListeningPort(server_address,
|
||||
Server::CreateServerCredentials(config));
|
||||
gpr_free(server_address);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ static void RunSynchronousStreamingPingPong() {
|
|||
|
||||
ServerConfig server_config;
|
||||
server_config.set_server_type(SYNC_SERVER);
|
||||
server_config.set_host("localhost");
|
||||
|
||||
const auto result =
|
||||
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ static void RunSynchronousUnaryPingPong() {
|
|||
|
||||
ServerConfig server_config;
|
||||
server_config.set_server_type(SYNC_SERVER);
|
||||
server_config.set_host("localhost");
|
||||
|
||||
const auto result =
|
||||
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
*
|
||||
* 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.
|
||||
*is % allowed in string
|
||||
*/
|
||||
|
||||
#include "test/cpp/util/metrics_server.h"
|
||||
|
||||
#include <grpc++/server_builder.h>
|
||||
|
||||
#include "test/proto/metrics.grpc.pb.h"
|
||||
#include "test/proto/metrics.pb.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace testing {
|
||||
|
||||
Gauge::Gauge(long initial_val) : val_(initial_val) {}
|
||||
|
||||
void Gauge::Set(long new_val) {
|
||||
std::lock_guard<std::mutex> lock(val_mu_);
|
||||
val_ = new_val;
|
||||
}
|
||||
|
||||
long Gauge::Get() {
|
||||
std::lock_guard<std::mutex> lock(val_mu_);
|
||||
return val_;
|
||||
}
|
||||
|
||||
grpc::Status MetricsServiceImpl::GetAllGauges(
|
||||
ServerContext* context, const EmptyMessage* request,
|
||||
ServerWriter<GaugeResponse>* writer) {
|
||||
gpr_log(GPR_INFO, "GetAllGauges called");
|
||||
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
for (auto it = gauges_.begin(); it != gauges_.end(); it++) {
|
||||
GaugeResponse resp;
|
||||
resp.set_name(it->first); // Gauge name
|
||||
resp.set_long_value(it->second->Get()); // Gauge value
|
||||
writer->Write(resp);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
grpc::Status MetricsServiceImpl::GetGauge(ServerContext* context,
|
||||
const GaugeRequest* request,
|
||||
GaugeResponse* response) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
|
||||
const auto it = gauges_.find(request->name());
|
||||
if (it != gauges_.end()) {
|
||||
response->set_name(it->first);
|
||||
response->set_long_value(it->second->Get());
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
std::shared_ptr<Gauge> MetricsServiceImpl::CreateGauge(const grpc::string& name,
|
||||
bool* already_present) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
|
||||
std::shared_ptr<Gauge> gauge(new Gauge(0));
|
||||
const auto p = gauges_.emplace(name, gauge);
|
||||
|
||||
// p.first is an iterator pointing to <name, shared_ptr<Gauge>> pair. p.second
|
||||
// is a boolean which is set to 'true' if the Gauge is inserted in the guages_
|
||||
// map and 'false' if it is already present in the map
|
||||
*already_present = !p.second;
|
||||
return p.first->second;
|
||||
}
|
||||
|
||||
// Starts the metrics server and returns the grpc::Server instance. Call Wait()
|
||||
// on the returned server instance.
|
||||
std::unique_ptr<grpc::Server> MetricsServiceImpl::StartServer(int port) {
|
||||
gpr_log(GPR_INFO, "Building metrics server..");
|
||||
|
||||
const grpc::string address = "0.0.0.0:" + std::to_string(port);
|
||||
|
||||
ServerBuilder builder;
|
||||
builder.AddListeningPort(address, grpc::InsecureServerCredentials());
|
||||
builder.RegisterService(this);
|
||||
|
||||
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
|
||||
gpr_log(GPR_INFO, "Metrics server %s started. Ready to receive requests..",
|
||||
address.c_str());
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
*
|
||||
* 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.
|
||||
*is % allowed in string
|
||||
*/
|
||||
#ifndef GRPC_TEST_CPP_METRICS_SERVER_H
|
||||
#define GRPC_TEST_CPP_METRICS_SERVER_H
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
#include "test/proto/metrics.grpc.pb.h"
|
||||
#include "test/proto/metrics.pb.h"
|
||||
|
||||
/*
|
||||
* This implements a Metrics server defined in test/proto/metrics.proto. Any
|
||||
* test service can use this to export Metrics (TODO (sreek): Only Gauges for
|
||||
* now).
|
||||
*
|
||||
* Example:
|
||||
* MetricsServiceImpl metricsImpl;
|
||||
* ..
|
||||
* // Create Gauge(s). Note: Gauges can be created even after calling
|
||||
* // 'StartServer'.
|
||||
* Gauge gauge1 = metricsImpl.CreateGauge("foo",is_present);
|
||||
* // gauge1 can now be used anywhere in the program to set values.
|
||||
* ...
|
||||
* // Create the metrics server
|
||||
* std::unique_ptr<grpc::Server> server = metricsImpl.StartServer(port);
|
||||
* server->Wait(); // Note: This is blocking.
|
||||
*/
|
||||
namespace grpc {
|
||||
namespace testing {
|
||||
|
||||
// TODO(sreek): Add support for other types of Gauges like Double, String in
|
||||
// future
|
||||
class Gauge {
|
||||
public:
|
||||
Gauge(long initial_val);
|
||||
void Set(long new_val);
|
||||
long Get();
|
||||
|
||||
private:
|
||||
long val_;
|
||||
std::mutex val_mu_;
|
||||
};
|
||||
|
||||
class MetricsServiceImpl GRPC_FINAL : public MetricsService::Service {
|
||||
public:
|
||||
grpc::Status GetAllGauges(ServerContext* context, const EmptyMessage* request,
|
||||
ServerWriter<GaugeResponse>* writer) GRPC_OVERRIDE;
|
||||
|
||||
grpc::Status GetGauge(ServerContext* context, const GaugeRequest* request,
|
||||
GaugeResponse* response) GRPC_OVERRIDE;
|
||||
|
||||
// Create a Gauge with name 'name'. is_present is set to true if the Gauge
|
||||
// is already present in the map.
|
||||
// NOTE: CreateGauge can be called anytime (i.e before or after calling
|
||||
// StartServer).
|
||||
std::shared_ptr<Gauge> CreateGauge(const grpc::string& name,
|
||||
bool* already_present);
|
||||
|
||||
std::unique_ptr<grpc::Server> StartServer(int port);
|
||||
|
||||
private:
|
||||
std::map<string, std::shared_ptr<Gauge>> gauges_;
|
||||
std::mutex mu_;
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_TEST_CPP_METRICS_SERVER_H
|
||||
|
|
@ -49,7 +49,10 @@ enum RpcType {
|
|||
STREAMING = 1;
|
||||
}
|
||||
|
||||
// Parameters of poisson process distribution, which is a good representation
|
||||
// of activity coming in from independent identical stationary sources.
|
||||
message PoissonParams {
|
||||
// The rate of arrivals (a.k.a. lambda parameter of the exp distribution).
|
||||
double offered_load = 1;
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +70,8 @@ message ParetoParams {
|
|||
double alpha = 2;
|
||||
}
|
||||
|
||||
// Once an RPC finishes, immediately start a new one.
|
||||
// No configuration parameters needed.
|
||||
message ClosedLoopParams {
|
||||
}
|
||||
|
||||
|
|
@ -87,16 +92,23 @@ message SecurityParams {
|
|||
}
|
||||
|
||||
message ClientConfig {
|
||||
// List of targets to connect to. At least one target needs to be specified.
|
||||
repeated string server_targets = 1;
|
||||
ClientType client_type = 2;
|
||||
SecurityParams security_params = 3;
|
||||
// How many concurrent RPCs to start for each channel.
|
||||
// For synchronous client, use a separate thread for each outstanding RPC.
|
||||
int32 outstanding_rpcs_per_channel = 4;
|
||||
// Number of independent client channels to create.
|
||||
// i-th channel will connect to server_target[i % server_targets.size()]
|
||||
int32 client_channels = 5;
|
||||
// only for async client:
|
||||
// Only for async client. Number of threads to use to start/manage RPCs.
|
||||
int32 async_client_threads = 7;
|
||||
RpcType rpc_type = 8;
|
||||
// The requested load for the entire client (aggregated over all the threads).
|
||||
LoadParams load_params = 10;
|
||||
PayloadConfig payload_config = 11;
|
||||
HistogramParams histogram_params = 12;
|
||||
}
|
||||
|
||||
message ClientStatus {
|
||||
|
|
@ -105,6 +117,7 @@ message ClientStatus {
|
|||
|
||||
// Request current stats
|
||||
message Mark {
|
||||
// if true, the stats will be reset after taking their snapshot.
|
||||
bool reset = 1;
|
||||
}
|
||||
|
||||
|
|
@ -118,10 +131,13 @@ message ClientArgs {
|
|||
message ServerConfig {
|
||||
ServerType server_type = 1;
|
||||
SecurityParams security_params = 2;
|
||||
// Host on which to listen.
|
||||
string host = 3;
|
||||
// Port on which to listen. Zero means pick unused port.
|
||||
int32 port = 4;
|
||||
// only for async server
|
||||
// Only for async server. Number of threads used to serve the requests.
|
||||
int32 async_server_threads = 7;
|
||||
// restrict core usage
|
||||
// restrict core usage, currently unused
|
||||
int32 core_limit = 8;
|
||||
PayloadConfig payload_config = 9;
|
||||
}
|
||||
|
|
@ -135,6 +151,8 @@ message ServerArgs {
|
|||
|
||||
message ServerStatus {
|
||||
ServerStats stats = 1;
|
||||
// the port bound by the server
|
||||
int32 port = 2;
|
||||
// Number of cores on the server. See gpr_cpu_num_cores.
|
||||
int32 cores = 3;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,9 +47,19 @@ service BenchmarkService {
|
|||
}
|
||||
|
||||
service WorkerService {
|
||||
// Start server with specified workload
|
||||
// Start server with specified workload.
|
||||
// First request sent specifies the ServerConfig followed by ServerStatus
|
||||
// response. After that, a "Mark" can be sent anytime to request the latest
|
||||
// stats. Closing the stream will initiate shutdown of the test server
|
||||
// and once the shutdown has finished, the OK status is sent to terminate
|
||||
// this RPC.
|
||||
rpc RunServer(stream ServerArgs) returns (stream ServerStatus);
|
||||
|
||||
// Start client with specified workload
|
||||
// Start client with specified workload.
|
||||
// First request sent specifies the ClientConfig followed by ClientStatus
|
||||
// response. After that, a "Mark" can be sent anytime to request the latest
|
||||
// stats. Closing the stream will initiate shutdown of the test client
|
||||
// and once the shutdown has finished, the OK status is sent to terminate
|
||||
// this RPC.
|
||||
rpc RunClient(stream ClientArgs) returns (stream ClientStatus);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,16 +32,24 @@ syntax = "proto3";
|
|||
package grpc.testing;
|
||||
|
||||
message ServerStats {
|
||||
// wall clock time
|
||||
// wall clock time change in seconds since last reset
|
||||
double time_elapsed = 1;
|
||||
|
||||
// user time used by the server process and threads
|
||||
// change in user time (in seconds) used by the server since last reset
|
||||
double time_user = 2;
|
||||
|
||||
// server time used by the server process and all threads
|
||||
// change in server time (in seconds) used by the server process and all
|
||||
// threads since last reset
|
||||
double time_system = 3;
|
||||
}
|
||||
|
||||
// Histogram params based on grpc/support/histogram.c
|
||||
message HistogramParams {
|
||||
double resolution = 1; // first bucket is [0, 1 + resolution)
|
||||
double max_possible = 2; // use enough buckets to allow this value
|
||||
}
|
||||
|
||||
// Histogram data based on grpc/support/histogram.c
|
||||
message HistogramData {
|
||||
repeated uint32 bucket = 1;
|
||||
double min_seen = 2;
|
||||
|
|
@ -52,7 +60,10 @@ message HistogramData {
|
|||
}
|
||||
|
||||
message ClientStats {
|
||||
// Latency histogram. Data points are in nanoseconds.
|
||||
HistogramData latencies = 1;
|
||||
|
||||
// See ServerStats for details.
|
||||
double time_elapsed = 2;
|
||||
double time_user = 3;
|
||||
double time_system = 4;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
// 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.
|
||||
|
||||
// An integration test service that covers all the method signature permutations
|
||||
// of unary/streaming requests/responses.
|
||||
syntax = "proto3";
|
||||
|
||||
package grpc.testing;
|
||||
|
||||
message GaugeResponse {
|
||||
string name = 1;
|
||||
oneof value {
|
||||
int64 long_value = 2;
|
||||
double double_vale = 3;
|
||||
string string_value = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message GaugeRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message EmptyMessage {
|
||||
}
|
||||
|
||||
service MetricsService {
|
||||
rpc GetAllGauges(EmptyMessage) returns (stream GaugeResponse);
|
||||
rpc GetGauge(GaugeRequest) returns (GaugeResponse);
|
||||
}
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
#!/usr/bin/env python2.7
|
||||
# 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.
|
||||
|
||||
import requests
|
||||
import json
|
||||
|
||||
_REQUEST_TIMEOUT_SECS = 10
|
||||
|
||||
def _make_pod_config(pod_name, image_name, container_port_list, cmd_list,
|
||||
arg_list):
|
||||
"""Creates a string containing the Pod defintion as required by the Kubernetes API"""
|
||||
body = {
|
||||
'kind': 'Pod',
|
||||
'apiVersion': 'v1',
|
||||
'metadata': {
|
||||
'name': pod_name,
|
||||
'labels': {'name': pod_name}
|
||||
},
|
||||
'spec': {
|
||||
'containers': [
|
||||
{
|
||||
'name': pod_name,
|
||||
'image': image_name,
|
||||
'ports': []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
# Populate the 'ports' list
|
||||
for port in container_port_list:
|
||||
port_entry = {'containerPort': port, 'protocol': 'TCP'}
|
||||
body['spec']['containers'][0]['ports'].append(port_entry)
|
||||
|
||||
# Add the 'Command' and 'Args' attributes if they are passed.
|
||||
# Note:
|
||||
# - 'Command' overrides the ENTRYPOINT in the Docker Image
|
||||
# - 'Args' override the COMMAND in Docker image (yes, it is confusing!)
|
||||
if len(cmd_list) > 0:
|
||||
body['spec']['containers'][0]['command'] = cmd_list
|
||||
if len(arg_list) > 0:
|
||||
body['spec']['containers'][0]['args'] = arg_list
|
||||
return json.dumps(body)
|
||||
|
||||
|
||||
def _make_service_config(service_name, pod_name, service_port_list,
|
||||
container_port_list, is_headless):
|
||||
"""Creates a string containing the Service definition as required by the Kubernetes API.
|
||||
|
||||
NOTE:
|
||||
This creates either a Headless Service or 'LoadBalancer' service depending on
|
||||
the is_headless parameter. For Headless services, there is no 'type' attribute
|
||||
and the 'clusterIP' attribute is set to 'None'. Also, if the service is
|
||||
Headless, Kubernetes creates DNS entries for Pods - i.e creates DNS A-records
|
||||
mapping the service's name to the Pods' IPs
|
||||
"""
|
||||
if len(container_port_list) != len(service_port_list):
|
||||
print(
|
||||
'ERROR: container_port_list and service_port_list must be of same size')
|
||||
return ''
|
||||
body = {
|
||||
'kind': 'Service',
|
||||
'apiVersion': 'v1',
|
||||
'metadata': {
|
||||
'name': service_name,
|
||||
'labels': {
|
||||
'name': service_name
|
||||
}
|
||||
},
|
||||
'spec': {
|
||||
'ports': [],
|
||||
'selector': {
|
||||
'name': pod_name
|
||||
}
|
||||
}
|
||||
}
|
||||
# Populate the 'ports' list in the 'spec' section. This maps service ports
|
||||
# (port numbers that are exposed by Kubernetes) to container ports (i.e port
|
||||
# numbers that are exposed by your Docker image)
|
||||
for idx in range(len(container_port_list)):
|
||||
port_entry = {
|
||||
'port': service_port_list[idx],
|
||||
'targetPort': container_port_list[idx],
|
||||
'protocol': 'TCP'
|
||||
}
|
||||
body['spec']['ports'].append(port_entry)
|
||||
|
||||
# Make this either a LoadBalancer service or a headless service depending on
|
||||
# the is_headless parameter
|
||||
if is_headless:
|
||||
body['spec']['clusterIP'] = 'None'
|
||||
else:
|
||||
body['spec']['type'] = 'LoadBalancer'
|
||||
return json.dumps(body)
|
||||
|
||||
|
||||
def _print_connection_error(msg):
|
||||
print('ERROR: Connection failed. Did you remember to run Kubenetes proxy on '
|
||||
'localhost (i.e kubectl proxy --port=<proxy_port>) ?. Error: %s' % msg)
|
||||
|
||||
def _do_post(post_url, api_name, request_body):
|
||||
"""Helper to do HTTP POST.
|
||||
|
||||
Note:
|
||||
1) On success, Kubernetes returns a success code of 201(CREATED) not 200(OK)
|
||||
2) A response code of 509(CONFLICT) is interpreted as a success code (since
|
||||
the error is most likely due to the resource already existing). This makes
|
||||
_do_post() idempotent which is semantically desirable.
|
||||
"""
|
||||
is_success = True
|
||||
try:
|
||||
r = requests.post(post_url, data=request_body, timeout=_REQUEST_TIMEOUT_SECS)
|
||||
if r.status_code == requests.codes.conflict:
|
||||
print('WARN: Looks like the resource already exists. Api: %s, url: %s' %
|
||||
(api_name, post_url))
|
||||
elif r.status_code != requests.codes.created:
|
||||
print('ERROR: %s API returned error. HTTP response: (%d) %s' %
|
||||
(api_name, r.status_code, r.text))
|
||||
is_success = False
|
||||
except(requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
|
||||
is_success = False
|
||||
_print_connection_error(str(e))
|
||||
return is_success
|
||||
|
||||
|
||||
def _do_delete(del_url, api_name):
|
||||
"""Helper to do HTTP DELETE.
|
||||
|
||||
Note: A response code of 404(NOT_FOUND) is treated as success to keep
|
||||
_do_delete() idempotent.
|
||||
"""
|
||||
is_success = True
|
||||
try:
|
||||
r = requests.delete(del_url, timeout=_REQUEST_TIMEOUT_SECS)
|
||||
if r.status_code == requests.codes.not_found:
|
||||
print('WARN: The resource does not exist. Api: %s, url: %s' %
|
||||
(api_name, del_url))
|
||||
elif r.status_code != requests.codes.ok:
|
||||
print('ERROR: %s API returned error. HTTP response: %s' %
|
||||
(api_name, r.text))
|
||||
is_success = False
|
||||
except(requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
|
||||
is_success = False
|
||||
_print_connection_error(str(e))
|
||||
return is_success
|
||||
|
||||
|
||||
def create_service(kube_host, kube_port, namespace, service_name, pod_name,
|
||||
service_port_list, container_port_list, is_headless):
|
||||
"""Creates either a Headless Service or a LoadBalancer Service depending
|
||||
on the is_headless parameter.
|
||||
"""
|
||||
post_url = 'http://%s:%d/api/v1/namespaces/%s/services' % (
|
||||
kube_host, kube_port, namespace)
|
||||
request_body = _make_service_config(service_name, pod_name, service_port_list,
|
||||
container_port_list, is_headless)
|
||||
return _do_post(post_url, 'Create Service', request_body)
|
||||
|
||||
|
||||
def create_pod(kube_host, kube_port, namespace, pod_name, image_name,
|
||||
container_port_list, cmd_list, arg_list):
|
||||
"""Creates a Kubernetes Pod.
|
||||
|
||||
Note that it is generally NOT considered a good practice to directly create
|
||||
Pods. Typically, the recommendation is to create 'Controllers' to create and
|
||||
manage Pods' lifecycle. Currently Kubernetes only supports 'Replication
|
||||
Controller' which creates a configurable number of 'identical Replicas' of
|
||||
Pods and automatically restarts any Pods in case of failures (for eg: Machine
|
||||
failures in Kubernetes). This makes it less flexible for our test use cases
|
||||
where we might want slightly different set of args to each Pod. Hence we
|
||||
directly create Pods and not care much about Kubernetes failures since those
|
||||
are very rare.
|
||||
"""
|
||||
post_url = 'http://%s:%d/api/v1/namespaces/%s/pods' % (kube_host, kube_port,
|
||||
namespace)
|
||||
request_body = _make_pod_config(pod_name, image_name, container_port_list,
|
||||
cmd_list, arg_list)
|
||||
return _do_post(post_url, 'Create Pod', request_body)
|
||||
|
||||
|
||||
def delete_service(kube_host, kube_port, namespace, service_name):
|
||||
del_url = 'http://%s:%d/api/v1/namespaces/%s/services/%s' % (
|
||||
kube_host, kube_port, namespace, service_name)
|
||||
return _do_delete(del_url, 'Delete Service')
|
||||
|
||||
|
||||
def delete_pod(kube_host, kube_port, namespace, pod_name):
|
||||
del_url = 'http://%s:%d/api/v1/namespaces/%s/pods/%s' % (kube_host, kube_port,
|
||||
namespace, pod_name)
|
||||
return _do_delete(del_url, 'Delete Pod')
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package http2interop
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type GoAwayFrame struct {
|
||||
Header FrameHeader
|
||||
Reserved
|
||||
StreamID
|
||||
// TODO(carl-mastrangelo): make an enum out of this.
|
||||
Code uint32
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (f *GoAwayFrame) GetHeader() *FrameHeader {
|
||||
return &f.Header
|
||||
}
|
||||
|
||||
func (f *GoAwayFrame) ParsePayload(r io.Reader) error {
|
||||
raw := make([]byte, f.Header.Length)
|
||||
if _, err := io.ReadFull(r, raw); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.UnmarshalPayload(raw)
|
||||
}
|
||||
|
||||
func (f *GoAwayFrame) UnmarshalPayload(raw []byte) error {
|
||||
if f.Header.Length != len(raw) {
|
||||
return fmt.Errorf("Invalid Payload length %d != %d", f.Header.Length, len(raw))
|
||||
}
|
||||
if f.Header.Length < 8 {
|
||||
return fmt.Errorf("Invalid Payload length %d", f.Header.Length)
|
||||
}
|
||||
*f = GoAwayFrame{
|
||||
Reserved: Reserved(raw[0]>>7 == 1),
|
||||
StreamID: StreamID(binary.BigEndian.Uint32(raw[0:4]) & 0x7fffffff),
|
||||
Code: binary.BigEndian.Uint32(raw[4:8]),
|
||||
Data: []byte(string(raw[8:])),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *GoAwayFrame) MarshalPayload() ([]byte, error) {
|
||||
raw := make([]byte, 8, 8+len(f.Data))
|
||||
binary.BigEndian.PutUint32(raw[:4], uint32(f.StreamID))
|
||||
binary.BigEndian.PutUint32(raw[4:8], f.Code)
|
||||
raw = append(raw, f.Data...)
|
||||
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (f *GoAwayFrame) MarshalBinary() ([]byte, error) {
|
||||
payload, err := f.MarshalPayload()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f.Header.Length = len(payload)
|
||||
f.Header.Type = GoAwayFrameType
|
||||
header, err := f.Header.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
header = append(header, payload...)
|
||||
|
||||
return header, nil
|
||||
}
|
||||
|
|
@ -252,6 +252,58 @@ func testTLSApplicationProtocol(ctx *HTTP2InteropCtx) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func testTLSBadCipherSuites(ctx *HTTP2InteropCtx) error {
|
||||
config := buildTlsConfig(ctx)
|
||||
// These are the suites that Go supports, but are forbidden by http2.
|
||||
config.CipherSuites = []uint16{
|
||||
tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
}
|
||||
conn, err := connectWithTls(ctx, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
conn.SetDeadline(time.Now().Add(defaultTimeout))
|
||||
|
||||
if err := http2Connect(conn, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
f, err := parseFrame(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if gf, ok := f.(*GoAwayFrame); ok {
|
||||
return fmt.Errorf("Got goaway frame %d", gf.Code)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func http2Connect(c net.Conn, sf *SettingsFrame) error {
|
||||
if _, err := c.Write([]byte(Preface)); err != nil {
|
||||
return err
|
||||
}
|
||||
if sf == nil {
|
||||
sf = &SettingsFrame{}
|
||||
}
|
||||
if err := streamFrame(c, sf); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func connect(ctx *HTTP2InteropCtx) (net.Conn, error) {
|
||||
var conn net.Conn
|
||||
var err error
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ package http2interop
|
|||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"strings"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -17,8 +17,7 @@ var (
|
|||
serverHost = flag.String("server_host", "", "The host to test")
|
||||
serverPort = flag.Int("server_port", 443, "The port to test")
|
||||
useTls = flag.Bool("use_tls", true, "Should TLS tests be run")
|
||||
// TODO: implement
|
||||
testCase = flag.String("test_case", "", "What test cases to run")
|
||||
testCase = flag.String("test_case", "", "What test cases to run (tls, framing)")
|
||||
|
||||
// The rest of these are unused, but present to fulfill the client interface
|
||||
serverHostOverride = flag.String("server_host_override", "", "Unused")
|
||||
|
|
@ -70,6 +69,9 @@ func (ctx *HTTP2InteropCtx) Close() error {
|
|||
}
|
||||
|
||||
func TestShortPreface(t *testing.T) {
|
||||
if *testCase != "framing" {
|
||||
t.SkipNow()
|
||||
}
|
||||
ctx := InteropCtx(t)
|
||||
for i := 0; i < len(Preface)-1; i++ {
|
||||
if err := testShortPreface(ctx, Preface[:i]+"X"); err != io.EOF {
|
||||
|
|
@ -79,6 +81,9 @@ func TestShortPreface(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnknownFrameType(t *testing.T) {
|
||||
if *testCase != "framing" {
|
||||
t.SkipNow()
|
||||
}
|
||||
ctx := InteropCtx(t)
|
||||
if err := testUnknownFrameType(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -86,33 +91,53 @@ func TestUnknownFrameType(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTLSApplicationProtocol(t *testing.T) {
|
||||
if *testCase != "tls" {
|
||||
t.SkipNow()
|
||||
}
|
||||
ctx := InteropCtx(t)
|
||||
err := testTLSApplicationProtocol(ctx);
|
||||
err := testTLSApplicationProtocol(ctx)
|
||||
matchError(t, err, "EOF")
|
||||
}
|
||||
|
||||
func TestTLSMaxVersion(t *testing.T) {
|
||||
if *testCase != "tls" {
|
||||
t.SkipNow()
|
||||
}
|
||||
ctx := InteropCtx(t)
|
||||
err := testTLSMaxVersion(ctx, tls.VersionTLS11);
|
||||
err := testTLSMaxVersion(ctx, tls.VersionTLS11)
|
||||
// TODO(carl-mastrangelo): maybe this should be some other error. If the server picks
|
||||
// the wrong protocol version, thats bad too.
|
||||
matchError(t, err, "EOF", "server selected unsupported protocol")
|
||||
}
|
||||
|
||||
func TestTLSBadCipherSuites(t *testing.T) {
|
||||
if *testCase != "tls" {
|
||||
t.SkipNow()
|
||||
}
|
||||
ctx := InteropCtx(t)
|
||||
err := testTLSBadCipherSuites(ctx)
|
||||
matchError(t, err, "EOF", "Got goaway frame")
|
||||
}
|
||||
|
||||
func TestClientPrefaceWithStreamId(t *testing.T) {
|
||||
if *testCase != "framing" {
|
||||
t.SkipNow()
|
||||
}
|
||||
ctx := InteropCtx(t)
|
||||
err := testClientPrefaceWithStreamId(ctx)
|
||||
matchError(t, err, "EOF")
|
||||
}
|
||||
|
||||
func matchError(t *testing.T, err error, matches ... string) {
|
||||
if err == nil {
|
||||
t.Fatal("Expected an error")
|
||||
}
|
||||
for _, s := range matches {
|
||||
if strings.Contains(err.Error(), s) {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("Error %v not in %+v", err, matches)
|
||||
func matchError(t *testing.T, err error, matches ...string) {
|
||||
if err == nil {
|
||||
t.Fatal("Expected an error")
|
||||
}
|
||||
for _, s := range matches {
|
||||
if strings.Contains(err.Error(), s) {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("Error %v not in %+v", err, matches)
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ def random_name(base_name):
|
|||
def docker_kill(cid):
|
||||
"""Kills a docker container. Returns True if successful."""
|
||||
return subprocess.call(['docker','kill', str(cid)],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=_DEVNULL,
|
||||
stderr=subprocess.STDOUT) == 0
|
||||
|
||||
|
|
@ -78,6 +79,7 @@ def finish_jobs(jobs):
|
|||
def image_exists(image):
|
||||
"""Returns True if given docker image exists."""
|
||||
return subprocess.call(['docker','inspect', image],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=_DEVNULL,
|
||||
stderr=subprocess.STDOUT) == 0
|
||||
|
||||
|
|
@ -88,6 +90,7 @@ def remove_image(image, skip_nonexistent=False, max_retries=10):
|
|||
return True
|
||||
for attempt in range(0, max_retries):
|
||||
if subprocess.call(['docker','rmi', '-f', image],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=_DEVNULL,
|
||||
stderr=subprocess.STDOUT) == 0:
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@
|
|||
|
||||
"""Generate XML and HTML test reports."""
|
||||
|
||||
try:
|
||||
from mako.runtime import Context
|
||||
from mako.template import Template
|
||||
except (ImportError):
|
||||
pass # Mako not installed but it is ok.
|
||||
import os
|
||||
import string
|
||||
import xml.etree.cElementTree as ET
|
||||
|
|
@ -49,7 +54,7 @@ def _filter_msg(msg, output_format):
|
|||
return msg
|
||||
|
||||
|
||||
def render_xml_report(resultset, xml_report):
|
||||
def render_junit_xml_report(resultset, xml_report):
|
||||
"""Generate JUnit-like XML report."""
|
||||
root = ET.Element('testsuites')
|
||||
testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc',
|
||||
|
|
@ -69,147 +74,36 @@ def render_xml_report(resultset, xml_report):
|
|||
tree.write(xml_report, encoding='UTF-8')
|
||||
|
||||
|
||||
# TODO(adelez): Use mako template.
|
||||
def fill_one_test_result(shortname, resultset, html_str):
|
||||
if shortname in resultset:
|
||||
# Because interop tests does not have runs_per_test flag, each test is run
|
||||
# once. So there should only be one element for each result.
|
||||
result = resultset[shortname][0]
|
||||
if result.state == 'PASSED':
|
||||
html_str = '%s<td bgcolor=\"green\">PASS</td>\n' % html_str
|
||||
else:
|
||||
tooltip = ''
|
||||
if result.returncode > 0 or result.message:
|
||||
if result.returncode > 0:
|
||||
tooltip = 'returncode: %d ' % result.returncode
|
||||
if result.message:
|
||||
escaped_msg = _filter_msg(result.message, 'HTML')
|
||||
tooltip = '%smessage: %s' % (tooltip, escaped_msg)
|
||||
if result.state == 'FAILED':
|
||||
html_str = '%s<td bgcolor=\"red\">' % html_str
|
||||
if tooltip:
|
||||
html_str = ('%s<a href=\"#\" data-toggle=\"tooltip\" '
|
||||
'data-placement=\"auto\" title=\"%s\">FAIL</a></td>\n' %
|
||||
(html_str, tooltip))
|
||||
else:
|
||||
html_str = '%sFAIL</td>\n' % html_str
|
||||
elif result.state == 'TIMEOUT':
|
||||
html_str = '%s<td bgcolor=\"yellow\">' % html_str
|
||||
if tooltip:
|
||||
html_str = ('%s<a href=\"#\" data-toggle=\"tooltip\" '
|
||||
'data-placement=\"auto\" title=\"%s\">TIMEOUT</a></td>\n'
|
||||
% (html_str, tooltip))
|
||||
else:
|
||||
html_str = '%sTIMEOUT</td>\n' % html_str
|
||||
else:
|
||||
html_str = '%s<td bgcolor=\"magenta\">Not implemented</td>\n' % html_str
|
||||
|
||||
return html_str
|
||||
def render_interop_html_report(
|
||||
client_langs, server_langs, test_cases, auth_test_cases, http2_cases,
|
||||
resultset, num_failures, cloud_to_prod, http2_interop):
|
||||
"""Generate HTML report for interop tests."""
|
||||
html_report_dir = 'reports'
|
||||
template_file = os.path.join(html_report_dir, 'interop_html_report.template')
|
||||
try:
|
||||
mytemplate = Template(filename=template_file, format_exceptions=True)
|
||||
except NameError:
|
||||
print 'Mako template is not installed. Skipping HTML report generation.'
|
||||
return
|
||||
except IOError as e:
|
||||
print 'Failed to find the template %s: %s' % (template_file, e)
|
||||
return
|
||||
|
||||
|
||||
def render_html_report(client_langs, server_langs, test_cases, auth_test_cases,
|
||||
http2_cases, resultset, num_failures, cloud_to_prod,
|
||||
http2_interop):
|
||||
"""Generate html report."""
|
||||
sorted_test_cases = sorted(test_cases)
|
||||
sorted_auth_test_cases = sorted(auth_test_cases)
|
||||
sorted_http2_cases = sorted(http2_cases)
|
||||
sorted_client_langs = sorted(client_langs)
|
||||
sorted_server_langs = sorted(server_langs)
|
||||
html_str = ('<!DOCTYPE html>\n'
|
||||
'<html lang=\"en\">\n'
|
||||
'<head><title>Interop Test Result</title></head>\n'
|
||||
'<body>\n')
|
||||
if num_failures > 1:
|
||||
html_str = (
|
||||
'%s<p><h2><font color=\"red\">%d tests failed!</font></h2></p>\n' %
|
||||
(html_str, num_failures))
|
||||
elif num_failures:
|
||||
html_str = (
|
||||
'%s<p><h2><font color=\"red\">%d test failed!</font></h2></p>\n' %
|
||||
(html_str, num_failures))
|
||||
else:
|
||||
html_str = (
|
||||
'%s<p><h2><font color=\"green\">All tests passed!</font></h2></p>\n' %
|
||||
html_str)
|
||||
if cloud_to_prod:
|
||||
# Each column header is the client language.
|
||||
html_str = ('%s<h2>Cloud to Prod</h2>\n'
|
||||
'<table style=\"width:100%%\" border=\"1\">\n'
|
||||
'<tr bgcolor=\"#00BFFF\">\n'
|
||||
'<th>Client languages ►</th>\n') % html_str
|
||||
for client_lang in sorted_client_langs:
|
||||
html_str = '%s<th>%s\n' % (html_str, client_lang)
|
||||
html_str = '%s</tr>\n' % html_str
|
||||
for test_case in sorted_test_cases + sorted_auth_test_cases:
|
||||
html_str = '%s<tr><td><b>%s</b></td>\n' % (html_str, test_case)
|
||||
for client_lang in sorted_client_langs:
|
||||
if not test_case in sorted_auth_test_cases:
|
||||
shortname = 'cloud_to_prod:%s:%s' % (client_lang, test_case)
|
||||
else:
|
||||
shortname = 'cloud_to_prod_auth:%s:%s' % (client_lang, test_case)
|
||||
html_str = fill_one_test_result(shortname, resultset, html_str)
|
||||
html_str = '%s</tr>\n' % html_str
|
||||
html_str = '%s</table>\n' % html_str
|
||||
if http2_interop:
|
||||
# Each column header is the server language.
|
||||
html_str = ('%s<h2>HTTP/2 Interop</h2>\n'
|
||||
'<table style=\"width:100%%\" border=\"1\">\n'
|
||||
'<tr bgcolor=\"#00BFFF\">\n'
|
||||
'<th>Servers ►<br/>'
|
||||
'Test Cases ▼</th>\n') % html_str
|
||||
for server_lang in sorted_server_langs:
|
||||
html_str = '%s<th>%s\n' % (html_str, server_lang)
|
||||
if cloud_to_prod:
|
||||
html_str = '%s<th>%s\n' % (html_str, "prod")
|
||||
html_str = '%s</tr>\n' % html_str
|
||||
for test_case in sorted_http2_cases:
|
||||
html_str = '%s<tr><td><b>%s</b></td>\n' % (html_str, test_case)
|
||||
# Fill up the cells with test result.
|
||||
for server_lang in sorted_server_langs:
|
||||
shortname = 'cloud_to_cloud:%s:%s_server:%s' % (
|
||||
"http2", server_lang, test_case)
|
||||
html_str = fill_one_test_result(shortname, resultset, html_str)
|
||||
if cloud_to_prod:
|
||||
shortname = 'cloud_to_prod:%s:%s' % ("http2", test_case)
|
||||
html_str = fill_one_test_result(shortname, resultset, html_str)
|
||||
html_str = '%s</tr>\n' % html_str
|
||||
html_str = '%s</table>\n' % html_str
|
||||
if server_langs:
|
||||
for test_case in sorted_test_cases:
|
||||
# Each column header is the client language.
|
||||
html_str = ('%s<h2>%s</h2>\n'
|
||||
'<table style=\"width:100%%\" border=\"1\">\n'
|
||||
'<tr bgcolor=\"#00BFFF\">\n'
|
||||
'<th>Client languages ►<br/>'
|
||||
'Server languages ▼</th>\n') % (html_str, test_case)
|
||||
for client_lang in sorted_client_langs:
|
||||
html_str = '%s<th>%s\n' % (html_str, client_lang)
|
||||
html_str = '%s</tr>\n' % html_str
|
||||
# Each row head is the server language.
|
||||
for server_lang in sorted_server_langs:
|
||||
html_str = '%s<tr><td><b>%s</b></td>\n' % (html_str, server_lang)
|
||||
# Fill up the cells with test result.
|
||||
for client_lang in sorted_client_langs:
|
||||
shortname = 'cloud_to_cloud:%s:%s_server:%s' % (
|
||||
client_lang, server_lang, test_case)
|
||||
html_str = fill_one_test_result(shortname, resultset, html_str)
|
||||
html_str = '%s</tr>\n' % html_str
|
||||
html_str = '%s</table>\n' % html_str
|
||||
|
||||
html_str = ('%s\n'
|
||||
'<script>\n'
|
||||
'$(document).ready(function(){'
|
||||
'$(\'[data-toggle=\"tooltip\"]\').tooltip();\n'
|
||||
'});\n'
|
||||
'</script>\n'
|
||||
'</body>\n'
|
||||
'</html>') % html_str
|
||||
|
||||
# Write to reports/index.html as set up in Jenkins plugin.
|
||||
html_report_dir = 'reports'
|
||||
if not os.path.exists(html_report_dir):
|
||||
os.mkdir(html_report_dir)
|
||||
args = {'client_langs': sorted_client_langs,
|
||||
'server_langs': sorted_server_langs,
|
||||
'test_cases': sorted_test_cases,
|
||||
'auth_test_cases': sorted_auth_test_cases,
|
||||
'http2_cases': sorted_http2_cases,
|
||||
'resultset': resultset,
|
||||
'num_failures': num_failures,
|
||||
'cloud_to_prod': cloud_to_prod,
|
||||
'http2_interop': http2_interop}
|
||||
html_file_path = os.path.join(html_report_dir, 'index.html')
|
||||
with open(html_file_path, 'w') as f:
|
||||
f.write(html_str)
|
||||
with open(html_file_path, 'w') as output_file:
|
||||
mytemplate.render_context(Context(output_file, **args))
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ import jobset
|
|||
import multiprocessing
|
||||
import os
|
||||
import report_utils
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
|
@ -170,7 +169,7 @@ class Http2Client:
|
|||
self.safename = str(self)
|
||||
|
||||
def client_args(self):
|
||||
return ['tools/http2_interop/http2_interop.test']
|
||||
return ['tools/http2_interop/http2_interop.test', '-test.v']
|
||||
|
||||
def cloud_to_prod_env(self):
|
||||
return {}
|
||||
|
|
@ -306,7 +305,7 @@ _TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong',
|
|||
_AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
|
||||
'oauth2_auth_token', 'per_rpc_creds']
|
||||
|
||||
_HTTP2_TEST_CASES = ["tls"]
|
||||
_HTTP2_TEST_CASES = ["tls", "framing"]
|
||||
|
||||
def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
|
||||
"""Wraps given cmdline array to create 'docker run' cmdline from it."""
|
||||
|
|
@ -686,9 +685,9 @@ try:
|
|||
else:
|
||||
jobset.message('SUCCESS', 'All tests passed', do_newline=True)
|
||||
|
||||
report_utils.render_xml_report(resultset, 'report.xml')
|
||||
report_utils.render_junit_xml_report(resultset, 'report.xml')
|
||||
|
||||
report_utils.render_html_report(
|
||||
report_utils.render_interop_html_report(
|
||||
set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
|
||||
_HTTP2_TEST_CASES, resultset, num_failures,
|
||||
args.cloud_to_prod_auth or args.cloud_to_prod, args.http2_interop)
|
||||
|
|
|
|||
|
|
@ -485,10 +485,10 @@ _CONFIGS = {
|
|||
'msan': SimpleConfig('msan', timeout_multiplier=1.5),
|
||||
'ubsan': SimpleConfig('ubsan'),
|
||||
'asan': SimpleConfig('asan', timeout_multiplier=1.5, environ={
|
||||
'ASAN_OPTIONS': 'detect_leaks=1:color=always:suppressions=tools/tsan_suppressions.txt',
|
||||
'ASAN_OPTIONS': 'detect_leaks=1:color=always',
|
||||
'LSAN_OPTIONS': 'report_objects=1'}),
|
||||
'asan-noleaks': SimpleConfig('asan', environ={
|
||||
'ASAN_OPTIONS': 'detect_leaks=0:color=always:suppressions=tools/tsan_suppressions.txt'}),
|
||||
'ASAN_OPTIONS': 'detect_leaks=0:color=always'}),
|
||||
'gcov': SimpleConfig('gcov'),
|
||||
'memcheck': ValgrindConfig('valgrind', 'memcheck', ['--leak-check=full']),
|
||||
'helgrind': ValgrindConfig('dbg', 'helgrind')
|
||||
|
|
@ -902,7 +902,7 @@ def _build_and_run(
|
|||
for antagonist in antagonists:
|
||||
antagonist.kill()
|
||||
if xml_report and resultset:
|
||||
report_utils.render_xml_report(resultset, xml_report)
|
||||
report_utils.render_junit_xml_report(resultset, xml_report)
|
||||
|
||||
number_failures, _ = jobset.run(
|
||||
post_tests_steps, maxjobs=1, stop_on_failure=True,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue