Add testing of bad client behavior

This test will become a suite over coming weeks.
Spin up a server, and send some illegal data to it, and probe that the correct behavior occurs.
pull/1745/head
Craig Tiller 10 years ago
parent 18c26922d1
commit ba3c3cd36c
  1. 61
      Makefile
  2. 9
      src/core/surface/server.c
  3. 2
      src/core/surface/server.h
  4. 133
      test/core/bad_client/bad_client.c
  5. 52
      test/core/bad_client/bad_client.h
  6. 79
      test/core/bad_client/gen_build_json.py
  7. 71
      test/core/bad_client/tests/connection_prefix.c
  8. 1
      tools/buildgen/bunch.py
  9. 15
      tools/buildgen/generate_projects.sh
  10. 9
      tools/run_tests/tests.json
  11. 15
      vsprojects/Grpc.mak

File diff suppressed because one or more lines are too long

@ -1128,3 +1128,12 @@ static void publish_registered_or_batch(grpc_call *call, int success,
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {
return server->channel_args;
}
int grpc_server_has_open_connections(grpc_server *server) {
int r;
gpr_mu_lock(&server->mu);
r = server->root_channel_data.next != &server->root_channel_data;
gpr_mu_unlock(&server->mu);
return r;
}

@ -62,4 +62,6 @@ grpc_transport_setup_result grpc_server_setup_transport(
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
int grpc_server_has_open_connections(grpc_server *server);
#endif /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */

@ -0,0 +1,133 @@
/*
*
* 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/bad_client/bad_client.h"
#include "src/core/channel/channel_stack.h"
#include "src/core/channel/http_server_filter.h"
#include "src/core/iomgr/endpoint_pair.h"
#include "src/core/surface/completion_queue.h"
#include "src/core/surface/server.h"
#include "src/core/transport/chttp2_transport.h"
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
typedef struct {
grpc_server *server;
grpc_completion_queue *cq;
grpc_bad_client_server_side_validator validator;
gpr_event done_thd;
gpr_event done_write;
} thd_args;
static void thd_func(void *arg) {
thd_args *a = arg;
a->validator(a->server, a->cq);
gpr_event_set(&a->done_thd, (void*)1);
}
static void done_write(void *arg, grpc_endpoint_cb_status status) {
thd_args *a = arg;
gpr_event_set(&a->done_write, (void*)1);
}
static grpc_transport_setup_result server_setup_transport(void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
thd_args *a = ts;
static grpc_channel_filter const *extra_filters[] = {
&grpc_http_server_filter};
return grpc_server_setup_transport(a->server, transport, extra_filters,
GPR_ARRAY_SIZE(extra_filters), mdctx);
}
void grpc_run_bad_client_test(const char *name, const char *client_payload,
size_t client_payload_length,
grpc_bad_client_server_side_validator validator
) {
grpc_endpoint_pair sfd;
thd_args a;
gpr_thd_id id;
gpr_slice slice = gpr_slice_from_copied_buffer(client_payload, client_payload_length);
/* Add a debug log */
gpr_log(GPR_INFO, "TEST: %s", name);
/* Init grpc */
grpc_init();
/* Create endpoints */
sfd = grpc_iomgr_create_endpoint_pair(65536);
/* Create server, completion events */
a.server = grpc_server_create_from_filters(NULL, 0, NULL);
a.cq = grpc_completion_queue_create();
gpr_event_init(&a.done_thd);
gpr_event_init(&a.done_write);
a.validator = validator;
grpc_server_register_completion_queue(a.server, a.cq);
grpc_server_start(a.server);
grpc_create_chttp2_transport(server_setup_transport, &a, NULL, sfd.server, NULL, 0, grpc_mdctx_create(), 0);
/* Bind everything into the same pollset */
grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(a.cq));
grpc_endpoint_add_to_pollset(sfd.server, grpc_cq_pollset(a.cq));
/* Check a ground truth */
GPR_ASSERT(grpc_server_has_open_connections(a.server));
/* Start validator */
gpr_thd_new(&id, thd_func, &a, NULL);
/* Write data */
switch (grpc_endpoint_write(sfd.client, &slice, 1, done_write, &a)) {
case GRPC_ENDPOINT_WRITE_DONE:
done_write(&a, 1);
break;
case GRPC_ENDPOINT_WRITE_PENDING:
break;
case GRPC_ENDPOINT_WRITE_ERROR:
done_write(&a, 0);
break;
}
/* Await completion */
GPR_ASSERT(gpr_event_wait(&a.done_write, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)));
GPR_ASSERT(gpr_event_wait(&a.done_thd, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)));
/* Shutdown */
grpc_endpoint_destroy(sfd.client);
grpc_server_destroy(a.server);
grpc_completion_queue_destroy(a.cq);
grpc_shutdown();
}

@ -0,0 +1,52 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_TEST_CORE_BAD_CLIENT_BAD_CLIENT_H
#define GRPC_TEST_CORE_BAD_CLIENT_BAD_CLIENT_H
#include <grpc/grpc.h>
#include "test/core/util/test_config.h"
typedef void (*grpc_bad_client_server_side_validator)(grpc_server *server, grpc_completion_queue *cq);
/* Test runner.
Create a server, and send client_payload to it as bytes from a client.
Execute validator in a separate thread to assert that the bytes are
handled as expected. */
void grpc_run_bad_client_test(const char *name, const char *client_payload,
size_t client_payload_length,
grpc_bad_client_server_side_validator validator
);
#endif /* GRPC_TEST_CORE_BAD_CLIENT_BAD_CLIENT_H */

@ -0,0 +1,79 @@
#!/usr/bin/env python
# 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.
"""Generates the appropriate build.json data for all the end2end tests."""
import simplejson
import collections
TestOptions = collections.namedtuple('TestOptions', 'flaky')
default_test_options = TestOptions(False)
# maps test names to options
BAD_CLIENT_TESTS = {
'connection_prefix': default_test_options,
}
def main():
json = {
'#': 'generated with test/bad_client/gen_build_json.py',
'libs': [
{
'name': 'bad_client_test',
'build': 'private',
'language': 'c',
'src': [
'test/core/bad_client/bad_client.c'
]
}],
'targets': [
{
'name': '%s_bad_client_test' % t,
'build': 'test',
'language': 'c',
'secure': 'no',
'src': ['test/core/bad_client/tests/%s.c' % t],
'flaky': 'invoke_large_request' in t,
'deps': [
'bad_client_test',
'grpc_test_util_unsecure',
'grpc_unsecure',
'gpr_test_util',
'gpr'
]
}
for t in sorted(BAD_CLIENT_TESTS.keys())]}
print simplejson.dumps(json, sort_keys=True, indent=2 * ' ')
if __name__ == '__main__':
main()

@ -0,0 +1,71 @@
/*
*
* 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/bad_client/bad_client.h"
#include "src/core/surface/server.h"
static void verifier(grpc_server *server, grpc_completion_queue *cq) {
while (grpc_server_has_open_connections(server)) {
GPR_ASSERT(grpc_completion_queue_next(cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20)).type == GRPC_QUEUE_TIMEOUT);
}
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_run_bad_client_test("conpfx_1", "X", 1, verifier);
grpc_run_bad_client_test("conpfx_2", "PX", 2, verifier);
grpc_run_bad_client_test("conpfx_3", "PRX", 3, verifier);
grpc_run_bad_client_test("conpfx_4", "PRIX", 4, verifier);
grpc_run_bad_client_test("conpfx_5", "PRI X", 5, verifier);
grpc_run_bad_client_test("conpfx_6", "PRI *X", 6, verifier);
grpc_run_bad_client_test("conpfx_7", "PRI * X", 7, verifier);
grpc_run_bad_client_test("conpfx_8", "PRI * HX", 8, verifier);
grpc_run_bad_client_test("conpfx_9", "PRI * HTX", 9, verifier);
grpc_run_bad_client_test("conpfx_10", "PRI * HTTX", 10, verifier);
grpc_run_bad_client_test("conpfx_11", "PRI * HTTPX", 11, verifier);
grpc_run_bad_client_test("conpfx_12", "PRI * HTTP/X", 12, verifier);
grpc_run_bad_client_test("conpfx_13", "PRI * HTTP/2X", 13, verifier);
grpc_run_bad_client_test("conpfx_14", "PRI * HTTP/2.X", 14, verifier);
grpc_run_bad_client_test("conpfx_15", "PRI * HTTP/2.0X", 15, verifier);
grpc_run_bad_client_test("conpfx_16", "PRI * HTTP/2.0\rX", 16, verifier);
grpc_run_bad_client_test("conpfx_17", "PRI * HTTP/2.0\r\nX", 17, verifier);
grpc_run_bad_client_test("conpfx_18", "PRI * HTTP/2.0\r\n\rX", 18, verifier);
grpc_run_bad_client_test("conpfx_19", "PRI * HTTP/2.0\r\n\r\nX", 19, verifier);
grpc_run_bad_client_test("conpfx_20", "PRI * HTTP/2.0\r\n\r\nSX", 20, verifier);
grpc_run_bad_client_test("conpfx_21", "PRI * HTTP/2.0\r\n\r\nSMX", 21, verifier);
grpc_run_bad_client_test("conpfx_22", "PRI * HTTP/2.0\r\n\r\nSM\rX", 22, verifier);
grpc_run_bad_client_test("conpfx_23", "PRI * HTTP/2.0\r\n\r\nSM\r\nX", 23, verifier);
grpc_run_bad_client_test("conpfx_24", "PRI * HTTP/2.0\r\n\r\nSM\r\n\rX", 24, verifier);
return 0;
}

@ -57,6 +57,7 @@ def merge_json(dst, add):
if isinstance(dst, dict) and isinstance(add, dict):
for k, v in add.items():
if k in dst:
if k == '#': continue
merge_json(dst[k], v)
else:
dst[k] = v

@ -38,14 +38,19 @@ fi
cd `dirname $0`/../..
mako_renderer=tools/buildgen/mako_renderer.py
gen_build_json=test/core/end2end/gen_build_json.py
gen_build_json_dirs="test/core/end2end test/core/bad_client"
if [ "x$TEST" != "x" ] ; then
tools/buildgen/build-cleaner.py build.json
fi
end2end_test_build=`mktemp /tmp/genXXXXXX`
$gen_build_json > $end2end_test_build
gen_build_files=""
for gen_build_json in $gen_build_json_dirs
do
output_file=`mktemp /tmp/genXXXXXX`
$gen_build_json/gen_build_json.py > $output_file
gen_build_files="$gen_build_files $output_file"
done
global_plugins=`find ./tools/buildgen/plugins -name '*.py' |
sort | grep -v __init__ | awk ' { printf "-p %s ", $0 } '`
@ -60,7 +65,7 @@ for dir in . ; do
out=${dir}/${file#$dir/templates/} # strip templates dir prefix
out=${out%.*} # strip template extension
echo "generating file: $out"
json_files="build.json $end2end_test_build"
json_files="build.json $gen_build_files"
data=`for i in $json_files ; do echo $i ; done | awk ' { printf "-d %s ", $0 } '`
if [ "x$TEST" = "xtrue" ] ; then
actual_out=$out
@ -75,4 +80,4 @@ for dir in . ; do
done
done
rm $end2end_test_build
rm $gen_build_files

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

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save