From 1bee0c01d607580ca6d4817014d8a076bd909a3f Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Tue, 21 Feb 2017 19:40:44 -0800 Subject: [PATCH 1/6] not to use api_key if service is not activated. (#98) --- WORKSPACE | 2 +- src/nginx/t/check_no_consumer.t | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index a2798b7f0..a313bd4be 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -26,7 +26,7 @@ # # A Bazel (http://bazel.io) workspace for the Google Cloud Endpoints runtime. -ISTIO_PROXY = "6e372fc510de08da504c2dd21060c09255c1aee7" +ISTIO_PROXY = "0804a07680b2bc6a6ab93ffccead554b9680b6b5" git_repository( name = "nginx", diff --git a/src/nginx/t/check_no_consumer.t b/src/nginx/t/check_no_consumer.t index c08f24f01..803e9f79b 100644 --- a/src/nginx/t/check_no_consumer.t +++ b/src/nginx/t/check_no_consumer.t @@ -131,7 +131,6 @@ my $expected_report_body = ServiceControl::gen_report_body({ 'serviceName' => 'endpoints-test.cloudendpointsapis.com', 'url' => '/shelves?key=this-is-an-api-key', 'location' => 'us-central1', - 'api_key' => 'this-is-an-api-key', 'api_method' => 'ListShelves', 'http_method' => 'GET', 'log_message' => 'Method: ListShelves', From 9c85906c6f5192a675597b1f89286ac7c2521c38 Mon Sep 17 00:00:00 2001 From: Sebastien Vas Date: Fri, 10 Feb 2017 16:26:33 -0800 Subject: [PATCH 2/6] Escape run description Change-Id: I6a66f9be92314218ee6a19b2d82897b6c55c42d2 --- script/create-test-env-json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/create-test-env-json b/script/create-test-env-json index 712f71ca9..fab800d6c 100755 --- a/script/create-test-env-json +++ b/script/create-test-env-json @@ -46,7 +46,7 @@ cat << EOF > "${TEST_ENV}" { "test": "${TEST}", "run_id": "${ID}", - "run_description": "${SUBJECT}", + "run_description": "$(printf '%q' "${SUBJECT}")", "owner": "${AUTHOR}" } EOF From 220bd71a055191e59bf2fb7cf47a4bc517a2a039 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Thu, 23 Feb 2017 09:08:09 -0800 Subject: [PATCH 3/6] Fix grpc interop stress test script. (#103) --- script/test-grpc-interop | 65 +++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/script/test-grpc-interop b/script/test-grpc-interop index c1b676472..4bde71a9a 100755 --- a/script/test-grpc-interop +++ b/script/test-grpc-interop @@ -28,7 +28,12 @@ # # This script runs a grpc interop long-running test. -# It requires bazel build //test/grpc:all +# It requires bazel build following targets: +# //test/grpc:all +# @org_golang_google_grpc//stress/metrics_client +# @org_golang_google_grpc//interop/server +# @org_golang_google_grpc//stress/client +#set -x ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" . ${ROOT}/script/all-utilities \ @@ -36,9 +41,8 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" HOST='' DURATION_IN_HOUR=0 -RUN_LENGTH=120 TEST_CASES='empty_unary:10,large_unary:10,' -TEST_CASES+='empty_stream:10,client_streaming:10,half_duplex:10,ping_pong:20,server_streaming:10,' +TEST_CASES+='empty_stream:10,client_streaming:10,ping_pong:20,server_streaming:10,' TEST_CASES+='status_code_and_message:10,custom_metadata:10' while getopts :h:l:t: arg; do @@ -52,16 +56,6 @@ done [[ -n "${HOST}" ]] || error_exit 'Please specify a host with -h option.' -function print_test_metrics() { - local start_time=$(date +"%s") - while true; do - sleep 10 - local curr_time=$(date +"%s") - echo -n "QPS report at $((curr_time - start_time)) seconds:" - $ROOT/bazel-bin/external/org_golang_google_grpc/stress/metrics_client/metrics_client --total_only - done -} - # Waits for the proxy and backend to start. HOST_IP=${HOST%:*} HOST_PORT=${HOST#*:} @@ -70,49 +64,50 @@ retry $ROOT/bazel-bin/test/grpc/interop-client --server_port "${HOST_PORT}" \ --server_host "${HOST_IP}" \ || error_exit 'Failed to send one request, the proxy did not start properly.' +DURATION_IN_SEC=$((DURATION_IN_HOUR * 60 * 60)) +[[ ${DURATION_IN_SEC} -gt 120 ]] || DURATION_IN_SEC=120 + echo "Starts interop stress test at $(date)." -echo "Test during is: $((DURATION_IN_SECONDS / 60)) minutes." +echo "Test during is: $((DURATION_IN_SEC / 60)) minutes." echo "Test cases are: ${TEST_CASES}" -# Start a background print job. -print_test_metrics& -PRINT_JOB=$! -trap "kill ${PRINT_JOB}" EXIT +# Start a background test client job. +$ROOT/bazel-bin/external/org_golang_google_grpc/stress/client/client \ + --server_addresses "${HOST}" \ + --num_channels_per_server 200 \ + --num_stubs_per_channel 1 \ + --test_cases "${TEST_CASES}" 2> /dev/null& +TEST_JOB=$! +trap "kill ${TEST_JOB}" EXIT START_TIME=$(date +"%s") -END_TIME=$((START_TIME + DURATION_IN_HOUR * 60 * 60)) +END_TIME=$((START_TIME + DURATION_IN_SEC)) RUN_COUNT=0 -SUCCESS_TIME=0 +FAIL_COUNT=0 detect_memory_leak_init "http://${HOST}" while true; do CURR_TIME=$(date +"%s") - echo "Test time: $((CURR_TIME - START_TIME)) seconds, success time: ${SUCCESS_TIME} seconds." ((RUN_COUNT++)) - timeout $((RUN_LENGTH + 10)) $ROOT/bazel-bin/external/org_golang_google_grpc/stress/client/client \ - --server_addresses "${HOST}" \ - --test_duration_secs "${RUN_LENGTH}" \ - --num_channels_per_server 200 \ - --num_stubs_per_channel 1 \ - --test_cases "${TEST_CASES}" \ - && ((SUCCESS_TIME += RUN_LENGTH)) - - detect_memory_leak_check ${RUN_COUNT} + sleep 10 + METRIC_RESULT=$("$ROOT/bazel-bin/external/org_golang_google_grpc/stress/metrics_client/metrics_client" \ + --total_only --metrics_server_address=localhost:8081 2>&1) + QPS=$(echo ${METRIC_RESULT}|awk '{print $NF}') + echo "Metric report at $((CURR_TIME - START_TIME)) seconds: ${QPS} qps" + # Count non zero QPS as success. + [[ ${QPS} -gt 100 ]] || ((FAIL_COUNT++)) # Break if test has run long enough. [[ $(date +"%s") -lt ${END_TIME} ]] || break done -END_TIME=$(date +"%s") -echo "Total test time: $((END_TIME - START_TIME)) seconds, success time: ${SUCCESS_TIME} seconds at $(date)." +echo "Total test count: ${RUN_COUNT}, failed count: ${FAIL_COUNT}." -TOTAL_TIME=$((END_TIME - START_TIME)) -FAILURE_TIME=$((TOTAL_TIME - SUCCESS_TIME)) # If failure time is more than %5 of total test time, mark failed. RESULT=0 -[[ ${FAILURE_TIME} -gt $((TOTAL_TIME / 20)) ]] && RESULT=1 +[[ ${FAIL_COUNT} -gt $((RUN_COUNT / 20)) ]] && RESULT=1 # We fail the test if memory increase is large. detect_memory_leak_final && MEMORY_LEAK=0 || MEMORY_LEAK=1 From 23958a936b96e07fe77c7b484d3f7bbb74739819 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Thu, 23 Feb 2017 13:28:17 -0800 Subject: [PATCH 4/6] try to escape json again. (#106) --- script/create-test-env-json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/create-test-env-json b/script/create-test-env-json index fab800d6c..d11415206 100755 --- a/script/create-test-env-json +++ b/script/create-test-env-json @@ -46,7 +46,7 @@ cat << EOF > "${TEST_ENV}" { "test": "${TEST}", "run_id": "${ID}", - "run_description": "$(printf '%q' "${SUBJECT}")", + "run_description": $(python -c "import json; a='${SUBJECT}'; print json.dumps(a)"), "owner": "${AUTHOR}" } EOF From e06ddf56319f6a46ffe4f3261d9019fe59ace560 Mon Sep 17 00:00:00 2001 From: Qian Sun Date: Thu, 23 Feb 2017 14:24:14 -0800 Subject: [PATCH 5/6] Add t test for fail wrong api key. (#104) Change-Id: I0ea9ed4ba94f13283616eae00b93f067f9c00cf5 --- WORKSPACE | 2 +- src/nginx/t/BUILD | 1 + src/nginx/t/fail_wrong_api_key.t | 192 +++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 src/nginx/t/fail_wrong_api_key.t diff --git a/WORKSPACE b/WORKSPACE index a313bd4be..725e511d2 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -26,7 +26,7 @@ # # A Bazel (http://bazel.io) workspace for the Google Cloud Endpoints runtime. -ISTIO_PROXY = "0804a07680b2bc6a6ab93ffccead554b9680b6b5" +ISTIO_PROXY = "20e19d217be714ce1440b6dcdeab21cf1c14c2de" git_repository( name = "nginx", diff --git a/src/nginx/t/BUILD b/src/nginx/t/BUILD index b829dffd4..b0effdcd6 100644 --- a/src/nginx/t/BUILD +++ b/src/nginx/t/BUILD @@ -181,6 +181,7 @@ nginx_suite( "cors.t", "cors_disabled.t", "failed_check.t", + "fail_wrong_api_key.t", "metadata.t", "metadata_fail.t", "metadata_timeout.t", diff --git a/src/nginx/t/fail_wrong_api_key.t b/src/nginx/t/fail_wrong_api_key.t new file mode 100644 index 000000000..70810b13c --- /dev/null +++ b/src/nginx/t/fail_wrong_api_key.t @@ -0,0 +1,192 @@ +# Copyright (C) Extensible Service Proxy Authors +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. 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. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +# +################################################################################ +# +use strict; +use warnings; + +################################################################################ + +use src::nginx::t::ApiManager; # Must be first (sets up import path to the Nginx test module) +use src::nginx::t::HttpServer; +use src::nginx::t::ServiceControl; +use Test::Nginx; # Imports Nginx's test module +use Test::More; # And the test framework + +################################################################################ + +# Port assignments +my $NginxPort = ApiManager::pick_port(); +my $BackendPort = ApiManager::pick_port(); +my $ServiceControlPort = ApiManager::pick_port(); + +my $t = Test::Nginx->new()->has(qw/http proxy/)->plan(18); + +# Save service name in the service configuration protocol buffer file. +my $config = ApiManager::get_bookstore_service_config_allow_unregistered . <<"EOF"; +control { + environment: "http://127.0.0.1:${ServiceControlPort}" +} +EOF +$t->write_file('service.pb.txt', $config); + +ApiManager::write_file_expand($t, 'nginx.conf', <<"EOF"); +%%TEST_GLOBALS%% +daemon off; +events { + worker_connections 32; +} +http { + %%TEST_GLOBALS_HTTP%% + server_tokens off; + server { + listen 127.0.0.1:${NginxPort}; + server_name localhost; + location / { + endpoints { + api service.pb.txt; + %%TEST_CONFIG%% + on; + } + proxy_pass http://127.0.0.1:${BackendPort}; + } + } +} +EOF + +$t->run_daemon(\&bookstore, $t, $BackendPort, 'bookstore.log'); +$t->run_daemon(\&servicecontrol, $t, $ServiceControlPort, 'servicecontrol.log'); + +is($t->waitforsocket("127.0.0.1:${BackendPort}"), 1, 'Bookstore socket ready.'); +is($t->waitforsocket("127.0.0.1:${ServiceControlPort}"), 1, 'Service control socket ready.'); + +$t->run(); + +################################################################################ + +# Use different api_key so service_control will not use its cache. +my $response1 = ApiManager::http_get($NginxPort,'/shelves?key=this-is-an-api-key1'); +my $response2 = ApiManager::http_get($NginxPort,'/shelves?key=this-is-an-api-key2'); + +$t->stop_daemons(); + +like($response1, qr/HTTP\/1\.1 403 Forbidden/, 'Response1 returned HTTP 403.'); +like($response1, qr/content-type: application\/json/i, + 'Forbidden has application/json body.'); +like($response1, qr/API endpoints-test.cloudendpointsapis.com is not enabled for the project/i, + "Error body contains 'activation error'."); + +like($response2, qr/HTTP\/1\.1 400 Bad Request/, 'Response2 returned HTTP 400.'); +like($response2, qr/content-type: application\/json/i, + 'Forbidden has application/json body.'); +like($response2, qr/API key not valid/i, + "Error body contains 'API key error'."); + + +my $bookstore_requests = $t->read_file('bookstore.log'); +is($bookstore_requests, '', 'Request did not reach the backend.'); + +my @servicecontrol_requests = ApiManager::read_http_stream($t, 'servicecontrol.log'); +is(scalar @servicecontrol_requests, 2, 'Service control received 2 request.'); + +# :check #1 +my $r = shift @servicecontrol_requests; +is($r->{verb}, 'POST', ':check 1 was a post'); +is($r->{uri}, '/v1/services/endpoints-test.cloudendpointsapis.com:check', + ':check 1 uri is correct'); +is($r->{headers}->{host}, "127.0.0.1:${ServiceControlPort}", ':check 1 Host header was set.'); +is($r->{headers}->{'content-type'}, 'application/x-protobuf', ':check 1 Content-Type is protocol buffer.'); + +# :check #2 +$r = shift @servicecontrol_requests; +is($r->{verb}, 'POST', ':check 2 was a post'); +is($r->{uri}, '/v1/services/endpoints-test.cloudendpointsapis.com:check', + ':check 2 uri is correct'); +is($r->{headers}->{host}, "127.0.0.1:${ServiceControlPort}", ':check 2 Host header was set.'); +is($r->{headers}->{'content-type'}, 'application/x-protobuf', ':check 2 Content-Type is protocol buffer.'); + +################################################################################ + +sub bookstore { + my ($t, $port, $file) = @_; + my $server = HttpServer->new($port, $t->testdir() . '/' . $file) + or die "Can't create test server socket: $!\n"; + local $SIG{PIPE} = 'IGNORE'; + + # Do not initialize any server state, requests won't reach backend anyway. + + $server->run(); +} + +sub servicecontrol { + my ($t, $port, $file) = @_; + my $server = HttpServer->new($port, $t->testdir() . '/' . $file) + or die "Can't create test server socket: $!\n"; + local $SIG{PIPE} = 'IGNORE'; + + # This is normal 200 HTTP response with error in CheckResponse Json + my $proto_response1 = ServiceControl::convert_proto(<<'EOF', 'check_response', 'binary'); +{ + "operationId": "ListShelves:7b3f4c4f-f29c-4391-b35e-0a676427fec8", + "checkErrors": [ + { + "code": "SERVICE_NOT_ACTIVATED", + "detail": "Project has not activated the endpoints-test.cloudendpointsapis.com API." + } + ] +} +EOF + + $server->on('POST', '/v1/services/endpoints-test.cloudendpointsapis.com:check', <<'EOF' . $proto_response1); +HTTP/1.1 200 OK +Connection: close + +EOF + + # This is normal 200 HTTP response with error in api key + my $proto_response2 = ServiceControl::convert_proto(<<'EOF', 'check_response', 'binary'); +{ + "operationId": "ListShelves:7b3f4c4f-f29c-4391-b35e-0a676427fec9", + "checkErrors": [ + { + "code": "API_KEY_INVALID", + "detail": "API is not valid." + } + ] +} +EOF + + $server->on('POST', '/v1/services/endpoints-test.cloudendpointsapis.com:check', <<'EOF' . $proto_response2); +HTTP/1.1 200 OK +Connection: close + +EOF + + + + $server->run(); +} + +################################################################################ \ No newline at end of file From a6c8d3b2691a4ec24eac24c27e6b1e32e9f8c738 Mon Sep 17 00:00:00 2001 From: Qian Sun Date: Thu, 23 Feb 2017 15:04:32 -0800 Subject: [PATCH 6/6] Allow grpc interop stress test fail once. (#105) Change-Id: I5a090eae45c1d9b7d0641b2f09757bb373746aa1 --- script/test-grpc-interop | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/script/test-grpc-interop b/script/test-grpc-interop index 4bde71a9a..d482d69b0 100755 --- a/script/test-grpc-interop +++ b/script/test-grpc-interop @@ -107,7 +107,9 @@ echo "Total test count: ${RUN_COUNT}, failed count: ${FAIL_COUNT}." # If failure time is more than %5 of total test time, mark failed. RESULT=0 -[[ ${FAIL_COUNT} -gt $((RUN_COUNT / 20)) ]] && RESULT=1 +if [[ ${FAIL_COUNT} -gt $((RUN_COUNT / 20)) && ${FAIL_COUNT} -gt 1 ]] ; then + RESULT=1 +fi # We fail the test if memory increase is large. detect_memory_leak_final && MEMORY_LEAK=0 || MEMORY_LEAK=1