Merge github.com:grpc/grpc into metadata_filter

reviewable/pr8842/r4
Craig Tiller 8 years ago
commit 9d4fc31da4
  1. 92
      Makefile
  2. 2
      README.md
  3. 33
      build.yaml
  4. 6
      config.m4
  5. 7
      doc/negative-http2-interop-test-descriptions.md
  6. 2
      include/grpc/support/log_windows.h
  7. 2
      package.json
  8. 5
      src/core/ext/resolver/dns/native/dns_resolver.c
  9. 2
      src/core/ext/transport/chttp2/transport/frame_rst_stream.c
  10. 2
      src/php/ext/grpc/call.c
  11. 10
      src/php/ext/grpc/call_credentials.c
  12. 12
      src/php/ext/grpc/channel_credentials.c
  13. 12
      src/php/ext/grpc/php7_wrapper.h
  14. 4
      src/php/ext/grpc/php_grpc.h
  15. 4
      src/php/ext/grpc/server_credentials.c
  16. 42
      src/php/ext/grpc/timeval.c
  17. 10
      src/proto/grpc/testing/control.proto
  18. 6
      templates/config.m4.template
  19. 2
      templates/package.json.template
  20. 2
      test/core/support/BUILD
  21. 2
      test/core/util/memory_counters.h
  22. 19
      test/cpp/end2end/async_end2end_test.cc
  23. 20
      test/cpp/end2end/end2end_test.cc
  24. 1
      test/cpp/interop/client.cc
  25. 10
      test/cpp/interop/client_helper.cc
  26. 272
      test/cpp/interop/http2_client.cc
  27. 80
      test/cpp/interop/http2_client.h
  28. 1
      test/cpp/interop/interop_server.cc
  29. 18
      test/cpp/interop/server_helper.cc
  30. 1
      test/cpp/interop/stress_test.cc
  31. 13
      test/cpp/qps/client.h
  32. 1
      test/cpp/qps/qps_json_driver.cc
  33. 64
      test/cpp/util/create_test_channel.cc
  34. 4
      test/cpp/util/create_test_channel.h
  35. 52
      test/cpp/util/test_credentials_provider.cc
  36. 50
      test/cpp/util/test_credentials_provider.h
  37. 2
      tools/run_tests/artifacts/build_artifact_node.bat
  38. 2
      tools/run_tests/artifacts/build_artifact_node.sh
  39. 45
      tools/run_tests/generated/sources_and_headers.json
  40. 8
      tools/run_tests/performance/bq_upload_result.py
  41. 22
      tools/run_tests/performance/scenario_result_schema.json
  42. 132
      tools/run_tests/run_interop_tests.py
  43. 20
      tools/run_tests/run_performance_tests.py
  44. 206
      vsprojects/vcxproj/http2_client_main/http2_client_main.vcxproj
  45. 47
      vsprojects/vcxproj/http2_client_main/http2_client_main.vcxproj.filters
  46. 3
      vsprojects/vcxproj/interop_server_helper/interop_server_helper.vcxproj

@ -1065,6 +1065,7 @@ grpc_ruby_plugin: $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
grpc_tool_test: $(BINDIR)/$(CONFIG)/grpc_tool_test
grpclb_api_test: $(BINDIR)/$(CONFIG)/grpclb_api_test
grpclb_test: $(BINDIR)/$(CONFIG)/grpclb_test
http2_client: $(BINDIR)/$(CONFIG)/http2_client
hybrid_end2end_test: $(BINDIR)/$(CONFIG)/hybrid_end2end_test
interop_client: $(BINDIR)/$(CONFIG)/interop_client
interop_server: $(BINDIR)/$(CONFIG)/interop_server
@ -1240,9 +1241,9 @@ pc_cxx: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc
pc_cxx_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc
ifeq ($(EMBED_OPENSSL),true)
privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
else
privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
endif
@ -1447,6 +1448,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/grpc_tool_test \
$(BINDIR)/$(CONFIG)/grpclb_api_test \
$(BINDIR)/$(CONFIG)/grpclb_test \
$(BINDIR)/$(CONFIG)/http2_client \
$(BINDIR)/$(CONFIG)/hybrid_end2end_test \
$(BINDIR)/$(CONFIG)/interop_client \
$(BINDIR)/$(CONFIG)/interop_server \
@ -1540,6 +1542,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/grpc_tool_test \
$(BINDIR)/$(CONFIG)/grpclb_api_test \
$(BINDIR)/$(CONFIG)/grpclb_test \
$(BINDIR)/$(CONFIG)/http2_client \
$(BINDIR)/$(CONFIG)/hybrid_end2end_test \
$(BINDIR)/$(CONFIG)/interop_client \
$(BINDIR)/$(CONFIG)/interop_server \
@ -4943,6 +4946,59 @@ ifneq ($(NO_DEPS),true)
endif
LIBHTTP2_CLIENT_MAIN_SRC = \
$(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc \
test/cpp/interop/http2_client.cc \
PUBLIC_HEADERS_CXX += \
LIBHTTP2_CLIENT_MAIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBHTTP2_CLIENT_MAIN_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure libraries if you don't have OpenSSL.
$(LIBDIR)/$(CONFIG)/libhttp2_client_main.a: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
$(LIBDIR)/$(CONFIG)/libhttp2_client_main.a: protobuf_dep_error
else
$(LIBDIR)/$(CONFIG)/libhttp2_client_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBHTTP2_CLIENT_MAIN_OBJS)
$(E) "[AR] Creating $@"
$(Q) mkdir -p `dirname $@`
$(Q) rm -f $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a
$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBHTTP2_CLIENT_MAIN_OBJS)
ifeq ($(SYSTEM),Darwin)
$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a
endif
endif
endif
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(LIBHTTP2_CLIENT_MAIN_OBJS:.o=.dep)
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/interop/http2_client.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
LIBINTEROP_CLIENT_HELPER_SRC = \
$(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc \
test/cpp/interop/client_helper.cc \
@ -12897,6 +12953,37 @@ endif
$(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_test.o: $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/http2_client: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
$(BINDIR)/$(CONFIG)/http2_client: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/http2_client: $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/http2_client
endif
endif
HYBRID_END2END_TEST_SRC = \
test/cpp/end2end/hybrid_end2end_test.cc \
@ -16814,6 +16901,7 @@ test/core/util/test_tcp_server.c: $(OPENSSL_DEP)
test/cpp/end2end/test_service_impl.cc: $(OPENSSL_DEP)
test/cpp/interop/client.cc: $(OPENSSL_DEP)
test/cpp/interop/client_helper.cc: $(OPENSSL_DEP)
test/cpp/interop/http2_client.cc: $(OPENSSL_DEP)
test/cpp/interop/interop_client.cc: $(OPENSSL_DEP)
test/cpp/interop/interop_server.cc: $(OPENSSL_DEP)
test/cpp/interop/interop_server_bootstrap.cc: $(OPENSSL_DEP)

@ -17,6 +17,8 @@ See [INSTALL](INSTALL.md) for installation instructions for various platforms.
See [tools/run_tests](tools/run_tests) for more guidance on how to run various test suites (e.g. unit tests, interop tests, benchmarks)
See [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5712453606309888) for the performance numbers for v1.0.x.
#Repository Structure & Status
This repository contains source code for gRPC libraries for multiple languages written on top of shared C core library [src/core] (src/core).

@ -1223,6 +1223,22 @@ libs:
vs_project_guid: '{B6E81D84-2ACB-41B8-8781-493A944C7817}'
vs_props:
- protoc
- name: http2_client_main
build: private
language: c++
headers:
- test/cpp/interop/http2_client.h
src:
- src/proto/grpc/testing/empty.proto
- src/proto/grpc/testing/messages.proto
- src/proto/grpc/testing/test.proto
- test/cpp/interop/http2_client.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_config
- name: interop_client_helper
build: private
language: c++
@ -1265,6 +1281,7 @@ libs:
src:
- test/cpp/interop/server_helper.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
@ -3197,6 +3214,22 @@ targets:
- grpc++
- grpc++_test_util
- grpc_test_util
- name: http2_client
build: test
run: false
language: c++
src: []
deps:
- http2_client_main
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_config
platforms:
- mac
- linux
- posix
- name: hybrid_end2end_test
gtest: true
build: test

@ -5,9 +5,9 @@ if test "$PHP_GRPC" != "no"; then
dnl Write more examples of tests here...
dnl # --with-grpc -> add include path
PHP_ADD_INCLUDE(../../grpc/include)
PHP_ADD_INCLUDE(../../grpc/src/php/ext/grpc)
PHP_ADD_INCLUDE(../../grpc/third_party/boringssl/include)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/include)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include)
LIBS="-lpthread $LIBS"

@ -49,7 +49,8 @@ server. The client should handle the goaway by switching to a new stream without
the user application having to do a thing.
Client Procedure:
1. Client sends two UnaryCall requests with:
1. Client sends two UnaryCall requests (and sleeps for 1 second in-between).
TODO: resolve [9300](https://github.com/grpc/grpc/issues/9300) and remove the 1 second sleep
```
{
@ -61,14 +62,14 @@ Client Procedure:
```
Client asserts:
* Call was successful.
* Both calls are successful.
* Response payload body is 314159 bytes in size.
Server Procedure:
1. Server sends a GOAWAY after receiving the first UnaryCall.
Server asserts:
* The second UnaryCall has a different stream_id than the first one.
* Two different connections were used from the client.
### rst_after_header

@ -34,6 +34,8 @@
#ifndef GRPC_SUPPORT_LOG_WINDOWS_H
#define GRPC_SUPPORT_LOG_WINDOWS_H
#include <grpc/impl/codegen/port_platform.h>
#ifdef __cplusplus
extern "C" {
#endif

@ -50,7 +50,7 @@
"poisson-process": "^0.2.1"
},
"engines": {
"node": ">=0.12.0"
"node": ">=1.1.0"
},
"binary": {
"module_name": "grpc_node",

@ -188,9 +188,8 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
gpr_timespec timeout = gpr_time_sub(next_try, now);
const char *msg = grpc_error_string(error);
gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
grpc_error_string(error));
GPR_ASSERT(!r->have_retry_timer);
r->have_retry_timer = true;
GRPC_RESOLVER_REF(&r->base, "retry-timer");

@ -108,7 +108,7 @@ grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx,
(((uint32_t)p->reason_bytes[2]) << 8) |
(((uint32_t)p->reason_bytes[3]));
grpc_error *error = GRPC_ERROR_NONE;
if (reason != GRPC_HTTP2_NO_ERROR) {
if (reason != GRPC_HTTP2_NO_ERROR || s->header_frames_received < 2) {
error = grpc_error_set_int(GRPC_ERROR_CREATE("RST_STREAM"),
GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)reason);
}

@ -482,6 +482,7 @@ PHP_METHOD(Call, startBatch) {
gpr_free(status_details_text);
add_property_zval(result, "status", recv_status);
PHP_GRPC_DELREF(recv_status);
PHP_GRPC_FREE_STD_ZVAL(recv_status);
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
add_property_bool(result, "cancelled", cancelled);
@ -504,6 +505,7 @@ cleanup:
}
if (ops[i].op == GRPC_OP_RECV_MESSAGE) {
grpc_byte_buffer_destroy(message);
PHP_GRPC_FREE_STD_ZVAL(message_str);
}
}
RETURN_DESTROY_ZVAL(result);

@ -111,9 +111,7 @@ PHP_METHOD(CallCredentials, createComposite) {
grpc_call_credentials *creds =
grpc_composite_call_credentials_create(cred1->wrapped, cred2->wrapped,
NULL);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
@ -155,9 +153,7 @@ PHP_METHOD(CallCredentials, createFromPlugin) {
grpc_call_credentials *creds =
grpc_metadata_credentials_create_from_plugin(plugin, NULL);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
@ -211,6 +207,8 @@ void plugin_destroy_state(void *ptr) {
plugin_state *state = (plugin_state *)ptr;
efree(state->fci);
efree(state->fci_cache);
PHP_GRPC_FREE_STD_ZVAL(state->fci->params);
PHP_GRPC_FREE_STD_ZVAL(state->fci->retval);
efree(state);
}

@ -121,9 +121,7 @@ PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
*/
PHP_METHOD(ChannelCredentials, createDefault) {
grpc_channel_credentials *creds = grpc_google_default_credentials_create();
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
@ -160,9 +158,7 @@ PHP_METHOD(ChannelCredentials, createSsl) {
grpc_channel_credentials *creds = grpc_ssl_credentials_create(
pem_root_certs,
pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
@ -191,9 +187,7 @@ PHP_METHOD(ChannelCredentials, createComposite) {
grpc_channel_credentials *creds =
grpc_composite_channel_credentials_create(cred1->wrapped, cred2->wrapped,
NULL);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}

@ -50,8 +50,13 @@
#define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val, dup)
#define PHP_GRPC_MAKE_STD_ZVAL(pzv) MAKE_STD_ZVAL(pzv)
#define PHP_GRPC_FREE_STD_ZVAL(pzv)
#define PHP_GRPC_DELREF(zv) Z_DELREF_P(zv)
#define RETURN_DESTROY_ZVAL(val) \
RETURN_ZVAL(val, false /* Don't execute copy constructor */, \
true /* Dealloc original before returning */)
#define PHP_GRPC_WRAP_OBJECT_START(name) \
typedef struct name { \
zend_object std;
@ -144,8 +149,15 @@ static inline int php_grpc_zend_hash_find(HashTable *ht, char *key, int len,
#define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val)
#define PHP_GRPC_MAKE_STD_ZVAL(pzv) \
pzv = (zval *)emalloc(sizeof(zval));
#define PHP_GRPC_FREE_STD_ZVAL(pzv) efree(pzv);
#define PHP_GRPC_DELREF(zv)
#define RETURN_DESTROY_ZVAL(val) \
RETVAL_ZVAL(val, false /* Don't execute copy constructor */, \
true /* Dealloc original before returning */); \
efree(val); \
return
#define PHP_GRPC_WRAP_OBJECT_START(name) \
typedef struct name {
#define PHP_GRPC_WRAP_OBJECT_END(name) \

@ -61,10 +61,6 @@ extern zend_module_entry grpc_module_entry;
#include "grpc/grpc.h"
#define RETURN_DESTROY_ZVAL(val) \
RETURN_ZVAL(val, false /* Don't execute copy constructor */, \
true /* Dealloc original before returning */)
/* These are all function declarations */
/* Code that runs at module initialization */
PHP_MINIT_FUNCTION(grpc);

@ -113,9 +113,7 @@ PHP_METHOD(ServerCredentials, createSsl) {
grpc_server_credentials *creds = grpc_ssl_server_credentials_create_ex(
pem_root_certs, &pem_key_cert_pair, 1,
GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, NULL);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_server_credentials(creds TSRMLS_CC);
zval *creds_object = grpc_php_wrap_server_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}

@ -115,11 +115,9 @@ PHP_METHOD(Timeval, add) {
}
wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
zval *sum;
PHP_GRPC_MAKE_STD_ZVAL(sum);
sum =
grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped)
TSRMLS_CC);
zval *sum =
grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped)
TSRMLS_CC);
RETURN_DESTROY_ZVAL(sum);
}
@ -141,11 +139,9 @@ PHP_METHOD(Timeval, subtract) {
}
wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
zval *diff;
PHP_GRPC_MAKE_STD_ZVAL(diff);
diff =
grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped)
TSRMLS_CC);
zval *diff =
grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped)
TSRMLS_CC);
RETURN_DESTROY_ZVAL(diff);
}
@ -206,9 +202,7 @@ PHP_METHOD(Timeval, similar) {
* @return Timeval The current time
*/
PHP_METHOD(Timeval, now) {
zval *now;
PHP_GRPC_MAKE_STD_ZVAL(now);
now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME) TSRMLS_CC);
zval *now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME) TSRMLS_CC);
RETURN_DESTROY_ZVAL(now);
}
@ -217,13 +211,9 @@ PHP_METHOD(Timeval, now) {
* @return Timeval Zero length time interval
*/
PHP_METHOD(Timeval, zero) {
zval *grpc_php_timeval_zero;
PHP_GRPC_MAKE_STD_ZVAL(grpc_php_timeval_zero);
grpc_php_timeval_zero =
grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME) TSRMLS_CC);
RETURN_ZVAL(grpc_php_timeval_zero,
false, /* Copy original before returning? */
true /* Destroy original before returning */);
zval *grpc_php_timeval_zero =
grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME) TSRMLS_CC);
RETURN_DESTROY_ZVAL(grpc_php_timeval_zero);
}
/**
@ -231,10 +221,8 @@ PHP_METHOD(Timeval, zero) {
* @return Timeval Infinite future time value
*/
PHP_METHOD(Timeval, infFuture) {
zval *grpc_php_timeval_inf_future;
PHP_GRPC_MAKE_STD_ZVAL(grpc_php_timeval_inf_future);
grpc_php_timeval_inf_future =
grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME) TSRMLS_CC);
zval *grpc_php_timeval_inf_future =
grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME) TSRMLS_CC);
RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future);
}
@ -243,10 +231,8 @@ PHP_METHOD(Timeval, infFuture) {
* @return Timeval Infinite past time value
*/
PHP_METHOD(Timeval, infPast) {
zval *grpc_php_timeval_inf_past;
PHP_GRPC_MAKE_STD_ZVAL(grpc_php_timeval_inf_past);
grpc_php_timeval_inf_past =
grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME) TSRMLS_CC);
zval *grpc_php_timeval_inf_past =
grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME) TSRMLS_CC);
RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past);
}

@ -78,6 +78,14 @@ message SecurityParams {
string server_host_override = 2;
}
message ChannelArg {
string name = 1;
oneof value {
string str_value = 2;
int32 int_value = 3;
}
}
message ClientConfig {
// List of targets to connect to. At least one target needs to be specified.
repeated string server_targets = 1;
@ -103,6 +111,8 @@ message ClientConfig {
// If we use an OTHER_CLIENT client_type, this string gives more detail
string other_client_api = 15;
repeated ChannelArg channel_args = 16;
}
message ClientStatus { ClientStats stats = 1; }

@ -7,9 +7,9 @@
dnl Write more examples of tests here...
dnl # --with-grpc -> add include path
PHP_ADD_INCLUDE(../../grpc/include)
PHP_ADD_INCLUDE(../../grpc/src/php/ext/grpc)
PHP_ADD_INCLUDE(../../grpc/third_party/boringssl/include)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/include)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include)
LIBS="-lpthread $LIBS"

@ -52,7 +52,7 @@
"poisson-process": "^0.2.1"
},
"engines": {
"node": ">=0.12.0"
"node": ">=1.1.0"
},
"binary": {
"module_name": "grpc_node",

@ -27,8 +27,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
cc_test(
name = "alloc_test",
srcs = ["alloc_test.c"],

@ -34,6 +34,8 @@
#ifndef GRPC_TEST_CORE_UTIL_MEMORY_COUNTERS_H
#define GRPC_TEST_CORE_UTIL_MEMORY_COUNTERS_H
#include <stddef.h>
struct grpc_memory_counters {
size_t total_size_relative;
size_t total_size_absolute;

@ -263,7 +263,8 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> {
// Setup server
ServerBuilder builder;
auto server_creds = GetServerCredentials(GetParam().credentials_type);
auto server_creds = GetCredentialsProvider()->GetServerCredentials(
GetParam().credentials_type);
builder.AddListeningPort(server_address_.str(), server_creds);
builder.RegisterService(&service_);
cq_ = builder.AddCompletionQueue();
@ -292,8 +293,8 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> {
void ResetStub() {
ChannelArguments args;
auto channel_creds =
GetChannelCredentials(GetParam().credentials_type, &args);
auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
GetParam().credentials_type, &args);
std::shared_ptr<Channel> channel =
CreateCustomChannel(server_address_.str(), channel_creds, args);
stub_ = grpc::testing::EchoTestService::NewStub(channel);
@ -901,8 +902,8 @@ TEST_P(AsyncEnd2endTest, ServerCheckDone) {
TEST_P(AsyncEnd2endTest, UnimplementedRpc) {
ChannelArguments args;
auto channel_creds =
GetChannelCredentials(GetParam().credentials_type, &args);
auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
GetParam().credentials_type, &args);
std::shared_ptr<Channel> channel =
CreateCustomChannel(server_address_.str(), channel_creds, args);
std::unique_ptr<grpc::testing::UnimplementedEchoService::Stub> stub;
@ -1413,11 +1414,15 @@ std::vector<TestScenario> CreateTestScenarios(bool test_disable_blocking,
std::vector<grpc::string> credentials_types;
std::vector<grpc::string> messages;
credentials_types.push_back(kInsecureCredentialsType);
auto sec_list = GetSecureCredentialsTypeList();
if (GetCredentialsProvider()->GetChannelCredentials(kInsecureCredentialsType,
nullptr) != nullptr) {
credentials_types.push_back(kInsecureCredentialsType);
}
auto sec_list = GetCredentialsProvider()->GetSecureCredentialsTypeList();
for (auto sec = sec_list.begin(); sec != sec_list.end(); sec++) {
credentials_types.push_back(*sec);
}
GPR_ASSERT(!credentials_types.empty());
messages.push_back("Hello");
for (int sz = 1; sz < test_big_limit; sz *= 2) {

@ -252,7 +252,8 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
// Setup server
ServerBuilder builder;
ConfigureServerBuilder(&builder);
auto server_creds = GetServerCredentials(GetParam().credentials_type);
auto server_creds = GetCredentialsProvider()->GetServerCredentials(
GetParam().credentials_type);
if (GetParam().credentials_type != kInsecureCredentialsType) {
server_creds->SetAuthMetadataProcessor(processor);
}
@ -280,8 +281,8 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
}
EXPECT_TRUE(is_server_started_);
ChannelArguments args;
auto channel_creds =
GetChannelCredentials(GetParam().credentials_type, &args);
auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
GetParam().credentials_type, &args);
if (!user_agent_prefix_.empty()) {
args.SetUserAgentPrefix(user_agent_prefix_);
}
@ -1531,11 +1532,18 @@ std::vector<TestScenario> CreateTestScenarios(bool use_proxy,
std::vector<TestScenario> scenarios;
std::vector<grpc::string> credentials_types;
if (test_secure) {
credentials_types = GetSecureCredentialsTypeList();
credentials_types =
GetCredentialsProvider()->GetSecureCredentialsTypeList();
}
if (test_insecure) {
credentials_types.push_back(kInsecureCredentialsType);
// Only add insecure credentials type when it is registered with the
// provider. User may create providers that do not have insecure.
if (GetCredentialsProvider()->GetChannelCredentials(
kInsecureCredentialsType, nullptr) != nullptr) {
credentials_types.push_back(kInsecureCredentialsType);
}
}
GPR_ASSERT(!credentials_types.empty());
for (auto it = credentials_types.begin(); it != credentials_types.end();
++it) {
scenarios.emplace_back(false, *it);
@ -1552,7 +1560,7 @@ INSTANTIATE_TEST_CASE_P(End2end, End2endTest,
INSTANTIATE_TEST_CASE_P(End2endServerTryCancel, End2endServerTryCancelTest,
::testing::ValuesIn(CreateTestScenarios(false, true,
false)));
true)));
INSTANTIATE_TEST_CASE_P(ProxyEnd2end, ProxyEnd2endTest,
::testing::ValuesIn(CreateTestScenarios(true, true,

@ -50,6 +50,7 @@
#include "test/cpp/util/test_config.h"
DEFINE_bool(use_tls, false, "Whether to use tls.");
DEFINE_string(custom_credentials_type, "", "User provided credentials type.");
DEFINE_bool(use_test_ca, false, "False to use SSL roots for google");
DEFINE_int32(server_port, 0, "Server port.");
DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");

@ -50,8 +50,10 @@
#include "src/cpp/client/secure_credentials.h"
#include "test/core/security/oauth2_utils.h"
#include "test/cpp/util/create_test_channel.h"
#include "test/cpp/util/test_credentials_provider.h"
DECLARE_bool(use_tls);
DECLARE_string(custom_credentials_type);
DECLARE_bool(use_test_ca);
DECLARE_int32(server_port);
DECLARE_string(server_host);
@ -114,8 +116,12 @@ std::shared_ptr<Channel> CreateChannelForTestCase(
creds = AccessTokenCredentials(raw_token);
GPR_ASSERT(creds);
}
return CreateTestChannel(host_port, FLAGS_server_host_override, FLAGS_use_tls,
!FLAGS_use_test_ca, creds);
if (FLAGS_custom_credentials_type.empty()) {
return CreateTestChannel(host_port, FLAGS_server_host_override,
FLAGS_use_tls, !FLAGS_use_test_ca, creds);
} else {
return CreateTestChannel(host_port, FLAGS_custom_credentials_type, creds);
}
}
} // namespace testing

@ -0,0 +1,272 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <thread>
#include <gflags/gflags.h>
#include <grpc++/channel.h>
#include <grpc++/client_context.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
#include "src/core/lib/transport/byte_stream.h"
#include "src/proto/grpc/testing/messages.grpc.pb.h"
#include "src/proto/grpc/testing/test.grpc.pb.h"
#include "test/cpp/interop/http2_client.h"
#include "src/core/lib/support/string.h"
#include "test/cpp/util/create_test_channel.h"
#include "test/cpp/util/test_config.h"
namespace grpc {
namespace testing {
namespace {
const int kLargeRequestSize = 271828;
const int kLargeResponseSize = 314159;
} // namespace
Http2Client::ServiceStub::ServiceStub(std::shared_ptr<Channel> channel)
: channel_(channel) {
stub_ = TestService::NewStub(channel);
}
TestService::Stub* Http2Client::ServiceStub::Get() { return stub_.get(); }
Http2Client::Http2Client(std::shared_ptr<Channel> channel)
: serviceStub_(channel), channel_(channel) {}
bool Http2Client::AssertStatusCode(const Status& s, StatusCode expected_code) {
if (s.error_code() == expected_code) {
return true;
}
gpr_log(GPR_ERROR, "Error status code: %d (expected: %d), message: %s",
s.error_code(), expected_code, s.error_message().c_str());
abort();
}
bool Http2Client::DoRstAfterHeader() {
gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream after header");
ClientContext context;
SimpleRequest request;
SimpleResponse response;
request.set_response_size(kLargeResponseSize);
grpc::string payload(kLargeRequestSize, '\0');
request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
AssertStatusCode(s, grpc::StatusCode::UNKNOWN);
GPR_ASSERT(!response.has_payload()); // no data should be received
gpr_log(GPR_DEBUG, "Done testing reset stream after header");
return true;
}
bool Http2Client::DoRstAfterData() {
gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream after data");
ClientContext context;
SimpleRequest request;
SimpleResponse response;
request.set_response_size(kLargeResponseSize);
grpc::string payload(kLargeRequestSize, '\0');
request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
AssertStatusCode(s, grpc::StatusCode::UNKNOWN);
GPR_ASSERT(response.has_payload()); // data should be received
gpr_log(GPR_DEBUG, "Done testing reset stream after data");
return true;
}
bool Http2Client::DoRstDuringData() {
gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream during data");
ClientContext context;
SimpleRequest request;
SimpleResponse response;
request.set_response_size(kLargeResponseSize);
grpc::string payload(kLargeRequestSize, '\0');
request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
AssertStatusCode(s, grpc::StatusCode::UNKNOWN);
GPR_ASSERT(!response.has_payload()); // no data should be received
gpr_log(GPR_DEBUG, "Done testing reset stream during data");
return true;
}
bool Http2Client::DoGoaway() {
gpr_log(GPR_DEBUG, "Sending two RPCs and expecting goaway");
int numCalls = 2;
for (int i = 0; i < numCalls; i++) {
ClientContext context;
SimpleRequest request;
SimpleResponse response;
request.set_response_size(kLargeResponseSize);
grpc::string payload(kLargeRequestSize, '\0');
request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
AssertStatusCode(s, grpc::StatusCode::OK);
GPR_ASSERT(response.payload().body() ==
grpc::string(kLargeResponseSize, '\0'));
}
gpr_log(GPR_DEBUG, "Done testing goaway");
return true;
}
bool Http2Client::DoPing() {
gpr_log(GPR_DEBUG, "Sending RPC and expecting ping");
ClientContext context;
SimpleRequest request;
SimpleResponse response;
request.set_response_size(kLargeResponseSize);
grpc::string payload(kLargeRequestSize, '\0');
request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
AssertStatusCode(s, grpc::StatusCode::OK);
GPR_ASSERT(response.payload().body() ==
grpc::string(kLargeResponseSize, '\0'));
gpr_log(GPR_DEBUG, "Done testing ping");
return true;
}
void Http2Client::MaxStreamsWorker(std::shared_ptr<grpc::Channel> channel) {
ClientContext context;
SimpleRequest request;
SimpleResponse response;
request.set_response_size(kLargeResponseSize);
grpc::string payload(kLargeRequestSize, '\0');
request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
Status s =
TestService::NewStub(channel)->UnaryCall(&context, request, &response);
AssertStatusCode(s, grpc::StatusCode::OK);
GPR_ASSERT(response.payload().body() ==
grpc::string(kLargeResponseSize, '\0'));
}
bool Http2Client::DoMaxStreams() {
gpr_log(GPR_DEBUG, "Testing max streams");
// Make an initial call on the channel to ensure the server's max streams
// setting is received
ClientContext context;
SimpleRequest request;
SimpleResponse response;
request.set_response_size(kLargeResponseSize);
grpc::string payload(kLargeRequestSize, '\0');
request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
Status s =
TestService::NewStub(channel_)->UnaryCall(&context, request, &response);
AssertStatusCode(s, grpc::StatusCode::OK);
GPR_ASSERT(response.payload().body() ==
grpc::string(kLargeResponseSize, '\0'));
std::vector<std::thread> test_threads;
for (int i = 0; i < 10; i++) {
test_threads.emplace_back(
std::thread(&Http2Client::MaxStreamsWorker, this, channel_));
}
for (auto it = test_threads.begin(); it != test_threads.end(); it++) {
it->join();
}
gpr_log(GPR_DEBUG, "Done testing max streams");
return true;
}
} // namespace testing
} // namespace grpc
DEFINE_int32(server_port, 0, "Server port.");
DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");
DEFINE_string(test_case, "rst_after_header",
"Configure different test cases. Valid options are:\n\n"
"goaway\n"
"max_streams\n"
"ping\n"
"rst_after_data\n"
"rst_after_header\n"
"rst_during_data\n");
int main(int argc, char** argv) {
grpc::testing::InitTest(&argc, &argv, true);
GPR_ASSERT(FLAGS_server_port);
const int host_port_buf_size = 1024;
char host_port[host_port_buf_size];
snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(),
FLAGS_server_port);
grpc::testing::Http2Client client(grpc::CreateTestChannel(host_port, false));
gpr_log(GPR_INFO, "Testing case: %s", FLAGS_test_case.c_str());
int ret = 0;
if (FLAGS_test_case == "rst_after_header") {
client.DoRstAfterHeader();
} else if (FLAGS_test_case == "rst_after_data") {
client.DoRstAfterData();
} else if (FLAGS_test_case == "rst_during_data") {
client.DoRstDuringData();
} else if (FLAGS_test_case == "goaway") {
client.DoGoaway();
} else if (FLAGS_test_case == "ping") {
client.DoPing();
} else if (FLAGS_test_case == "max_streams") {
client.DoMaxStreams();
} else {
const char* testcases[] = {
"goaway", "max_streams", "ping",
"rst_after_data", "rst_after_header", "rst_during_data"};
char* joined_testcases =
gpr_strjoin_sep(testcases, GPR_ARRAY_SIZE(testcases), "\n", NULL);
gpr_log(GPR_ERROR, "Unsupported test case %s. Valid options are\n%s",
FLAGS_test_case.c_str(), joined_testcases);
gpr_free(joined_testcases);
ret = 1;
}
return ret;
}

@ -0,0 +1,80 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_TEST_CPP_INTEROP_HTTP2_CLIENT_H
#define GRPC_TEST_CPP_INTEROP_HTTP2_CLIENT_H
#include <memory>
#include <grpc++/channel.h>
#include <grpc/grpc.h>
#include "src/proto/grpc/testing/messages.grpc.pb.h"
#include "src/proto/grpc/testing/test.grpc.pb.h"
namespace grpc {
namespace testing {
class Http2Client {
public:
explicit Http2Client(std::shared_ptr<Channel> channel);
~Http2Client() {}
bool DoRstAfterHeader();
bool DoRstAfterData();
bool DoRstDuringData();
bool DoGoaway();
bool DoPing();
bool DoMaxStreams();
private:
class ServiceStub {
public:
ServiceStub(std::shared_ptr<Channel> channel);
TestService::Stub* Get();
private:
std::unique_ptr<TestService::Stub> stub_;
std::shared_ptr<Channel> channel_;
};
void MaxStreamsWorker(std::shared_ptr<grpc::Channel> channel);
bool AssertStatusCode(const Status& s, StatusCode expected_code);
ServiceStub serviceStub_;
std::shared_ptr<Channel> channel_;
};
} // namespace testing
} // namespace grpc
#endif // GRPC_TEST_CPP_INTEROP_HTTP2_CLIENT_H

@ -56,6 +56,7 @@
#include "test/cpp/util/test_config.h"
DEFINE_bool(use_tls, false, "Whether to use tls.");
DEFINE_string(custom_credentials_type, "", "User provided credentials type.");
DEFINE_int32(port, 0, "Server port.");
DEFINE_int32(max_send_message_size, -1, "The maximum send message size.");

@ -39,23 +39,23 @@
#include <grpc++/security/server_credentials.h>
#include "src/core/lib/surface/call_test_only.h"
#include "test/core/end2end/data/ssl_test_data.h"
#include "test/cpp/util/test_credentials_provider.h"
DECLARE_bool(use_tls);
DECLARE_string(custom_credentials_type);
namespace grpc {
namespace testing {
std::shared_ptr<ServerCredentials> CreateInteropServerCredentials() {
if (FLAGS_use_tls) {
SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
test_server1_cert};
SslServerCredentialsOptions ssl_opts;
ssl_opts.pem_root_certs = "";
ssl_opts.pem_key_cert_pairs.push_back(pkcp);
return SslServerCredentials(ssl_opts);
if (!FLAGS_custom_credentials_type.empty()) {
return GetCredentialsProvider()->GetServerCredentials(
FLAGS_custom_credentials_type);
} else if (FLAGS_use_tls) {
return GetCredentialsProvider()->GetServerCredentials(kTlsCredentialsType);
} else {
return InsecureServerCredentials();
return GetCredentialsProvider()->GetServerCredentials(
kInsecureCredentialsType);
}
}

@ -147,6 +147,7 @@ DEFINE_bool(do_not_abort_on_transient_failures, true,
// Options from client.cc (for compatibility with interop test).
// TODO(sreek): Consolidate overlapping options
DEFINE_bool(use_tls, false, "Whether to use tls.");
DEFINE_string(custom_credentials_type, "", "User provided credentials type.");
DEFINE_bool(use_test_ca, false, "False to use SSL roots for google");
DEFINE_int32(server_port, 0, "Server port.");
DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");

@ -409,6 +409,7 @@ class ClientImpl : public Client {
// old compilers happy with using this in std::vector
ChannelArguments args;
args.SetInt("shard_to_ensure_no_subchannel_merges", shard);
set_channel_args(config, &args);
channel_ = CreateTestChannel(
target, config.security_params().server_host_override(),
config.has_security_params(), !config.security_params().use_test_ca(),
@ -423,6 +424,18 @@ class ClientImpl : public Client {
StubType* get_stub() { return stub_.get(); }
private:
void set_channel_args(const ClientConfig& config, ChannelArguments* args) {
for (auto channel_arg : config.channel_args()) {
if (channel_arg.value_case() == ChannelArg::kStrValue) {
args->SetString(channel_arg.name(), channel_arg.str_value());
} else if (channel_arg.value_case() == ChannelArg::kIntValue) {
args->SetInt(channel_arg.name(), channel_arg.int_value());
} else {
gpr_log(GPR_ERROR, "Empty channel arg value.");
}
}
}
std::shared_ptr<Channel> channel_;
std::unique_ptr<StubType> stub_;
};

@ -212,6 +212,7 @@ static bool QpsDriver() {
SearchOfferedLoad(FLAGS_initial_search_value,
FLAGS_targeted_cpu_load, scenario, &success);
gpr_log(GPR_INFO, "targeted_offered_load %f", targeted_offered_load);
GetCpuLoad(scenario, targeted_offered_load, &success);
} else {
gpr_log(GPR_ERROR, "Unimplemented search param");
}

@ -35,11 +35,37 @@
#include <grpc++/create_channel.h>
#include <grpc++/security/credentials.h>
#include <grpc/support/log.h>
#include "test/core/end2end/data/ssl_test_data.h"
#include "test/cpp/util/test_credentials_provider.h"
namespace grpc {
namespace {
const char kProdTlsCredentialsType[] = "prod_ssl";
class SslCredentialProvider : public testing::CredentialTypeProvider {
public:
std::shared_ptr<ChannelCredentials> GetChannelCredentials(
grpc::ChannelArguments* args) override {
return SslCredentials(SslCredentialsOptions());
}
std::shared_ptr<ServerCredentials> GetServerCredentials() override {
return nullptr;
}
};
gpr_once g_once_init_add_prod_ssl_provider = GPR_ONCE_INIT;
// Register ssl with non-test roots type to the credentials provider.
void AddProdSslType() {
testing::GetCredentialsProvider()->AddSecureType(
kProdTlsCredentialsType, std::unique_ptr<testing::CredentialTypeProvider>(
new SslCredentialProvider));
}
} // namespace
// When ssl is enabled, if server is empty, override_hostname is used to
// create channel. Otherwise, connect to server and override hostname if
// override_hostname is provided.
@ -61,16 +87,22 @@ std::shared_ptr<Channel> CreateTestChannel(
const std::shared_ptr<CallCredentials>& creds,
const ChannelArguments& args) {
ChannelArguments channel_args(args);
std::shared_ptr<ChannelCredentials> channel_creds;
if (enable_ssl) {
const char* roots_certs = use_prod_roots ? "" : test_root_cert;
SslCredentialsOptions ssl_opts = {roots_certs, "", ""};
std::shared_ptr<ChannelCredentials> channel_creds =
SslCredentials(ssl_opts);
if (!server.empty() && !override_hostname.empty()) {
channel_args.SetSslTargetNameOverride(override_hostname);
if (use_prod_roots) {
gpr_once_init(&g_once_init_add_prod_ssl_provider, &AddProdSslType);
channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials(
kProdTlsCredentialsType, &channel_args);
if (!server.empty() && !override_hostname.empty()) {
channel_args.SetSslTargetNameOverride(override_hostname);
}
} else {
// override_hostname is discarded as the provider handles it.
channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials(
testing::kTlsCredentialsType, &channel_args);
}
GPR_ASSERT(channel_creds != nullptr);
const grpc::string& connect_to =
server.empty() ? override_hostname : server;
if (creds.get()) {
@ -103,4 +135,18 @@ std::shared_ptr<Channel> CreateTestChannel(const grpc::string& server,
return CreateTestChannel(server, "foo.test.google.fr", enable_ssl, false);
}
std::shared_ptr<Channel> CreateTestChannel(
const grpc::string& server, const grpc::string& credential_type,
const std::shared_ptr<CallCredentials>& creds) {
ChannelArguments channel_args;
std::shared_ptr<ChannelCredentials> channel_creds =
testing::GetCredentialsProvider()->GetChannelCredentials(credential_type,
&channel_args);
GPR_ASSERT(channel_creds != nullptr);
if (creds.get()) {
channel_creds = CompositeChannelCredentials(channel_creds, creds);
}
return CreateCustomChannel(server, channel_creds, channel_args);
}
} // namespace grpc

@ -59,6 +59,10 @@ std::shared_ptr<Channel> CreateTestChannel(
const std::shared_ptr<CallCredentials>& creds,
const ChannelArguments& args);
std::shared_ptr<Channel> CreateTestChannel(
const grpc::string& server, const grpc::string& credential_type,
const std::shared_ptr<CallCredentials>& creds);
} // namespace grpc
#endif // GRPC_TEST_CPP_UTIL_CREATE_TEST_CHANNEL_H

@ -43,25 +43,9 @@
#include "test/core/end2end/data/ssl_test_data.h"
namespace grpc {
namespace testing {
namespace {
using grpc::testing::CredentialTypeProvider;
// Provide test credentials. Thread-safe.
class CredentialsProvider {
public:
virtual ~CredentialsProvider() {}
virtual void AddSecureType(
const grpc::string& type,
std::unique_ptr<CredentialTypeProvider> type_provider) = 0;
virtual std::shared_ptr<ChannelCredentials> GetChannelCredentials(
const grpc::string& type, ChannelArguments* args) = 0;
virtual std::shared_ptr<ServerCredentials> GetServerCredentials(
const grpc::string& type) = 0;
virtual std::vector<grpc::string> GetSecureCredentialsTypeList() = 0;
};
class DefaultCredentialsProvider : public CredentialsProvider {
public:
~DefaultCredentialsProvider() override {}
@ -145,37 +129,21 @@ class DefaultCredentialsProvider : public CredentialsProvider {
added_secure_type_providers_;
};
gpr_once g_once_init_provider = GPR_ONCE_INIT;
CredentialsProvider* g_provider = nullptr;
void CreateDefaultProvider() { g_provider = new DefaultCredentialsProvider; }
CredentialsProvider* GetProvider() {
gpr_once_init(&g_once_init_provider, &CreateDefaultProvider);
return g_provider;
}
} // namespace
namespace testing {
void AddSecureType(const grpc::string& type,
std::unique_ptr<CredentialTypeProvider> type_provider) {
GetProvider()->AddSecureType(type, std::move(type_provider));
}
std::shared_ptr<ChannelCredentials> GetChannelCredentials(
const grpc::string& type, ChannelArguments* args) {
return GetProvider()->GetChannelCredentials(type, args);
}
std::shared_ptr<ServerCredentials> GetServerCredentials(
const grpc::string& type) {
return GetProvider()->GetServerCredentials(type);
CredentialsProvider* GetCredentialsProvider() {
if (g_provider == nullptr) {
g_provider = new DefaultCredentialsProvider;
}
return g_provider;
}
std::vector<grpc::string> GetSecureCredentialsTypeList() {
return GetProvider()->GetSecureCredentialsTypeList();
void SetCredentialsProvider(CredentialsProvider* provider) {
// For now, forbids overriding provider.
GPR_ASSERT(g_provider == nullptr);
g_provider = provider;
}
} // namespace testing

@ -59,23 +59,39 @@ class CredentialTypeProvider {
virtual std::shared_ptr<ServerCredentials> GetServerCredentials() = 0;
};
// Add a secure type in addition to the defaults above
// (kInsecureCredentialsType, kTlsCredentialsType) that can be returned from the
// functions below.
void AddSecureType(const grpc::string& type,
std::unique_ptr<CredentialTypeProvider> type_provider);
// Provide channel credentials according to the given type. Alter the channel
// arguments if needed.
std::shared_ptr<ChannelCredentials> GetChannelCredentials(
const grpc::string& type, ChannelArguments* args);
// Provide server credentials according to the given type.
std::shared_ptr<ServerCredentials> GetServerCredentials(
const grpc::string& type);
// Provide a list of secure credentials type.
std::vector<grpc::string> GetSecureCredentialsTypeList();
// Provide test credentials. Thread-safe.
class CredentialsProvider {
public:
virtual ~CredentialsProvider() {}
// Add a secure type in addition to the defaults. The default provider has
// (kInsecureCredentialsType, kTlsCredentialsType).
virtual void AddSecureType(
const grpc::string& type,
std::unique_ptr<CredentialTypeProvider> type_provider) = 0;
// Provide channel credentials according to the given type. Alter the channel
// arguments if needed. Return nullptr if type is not registered.
virtual std::shared_ptr<ChannelCredentials> GetChannelCredentials(
const grpc::string& type, ChannelArguments* args) = 0;
// Provide server credentials according to the given type.
// Return nullptr if type is not registered.
virtual std::shared_ptr<ServerCredentials> GetServerCredentials(
const grpc::string& type) = 0;
// Provide a list of secure credentials type.
virtual std::vector<grpc::string> GetSecureCredentialsTypeList() = 0;
};
// Get the current provider. Create a default one if not set.
// Not thread-safe.
CredentialsProvider* GetCredentialsProvider();
// Set the global provider. Takes ownership. The previous set provider will be
// destroyed.
// Not thread-safe.
void SetCredentialsProvider(CredentialsProvider* provider);
} // namespace testing
} // namespace grpc

@ -27,7 +27,7 @@
@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set node_versions=0.12.0 1.0.0 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 7.0.0
set node_versions=1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 7.0.0
set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm

@ -42,7 +42,7 @@ mkdir -p artifacts
npm update
node_versions=( 0.12.0 1.0.0 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 7.0.0 )
node_versions=( 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 7.0.0 )
for version in ${node_versions[@]}
do

@ -2772,6 +2772,23 @@
"third_party": false,
"type": "target"
},
{
"deps": [
"grpc",
"grpc++",
"grpc++_test_config",
"grpc++_test_util",
"grpc_test_util",
"http2_client_main"
],
"headers": [],
"is_filegroup": false,
"language": "c++",
"name": "http2_client",
"src": [],
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
@ -5388,6 +5405,33 @@
"third_party": false,
"type": "lib"
},
{
"deps": [
"grpc",
"grpc++",
"grpc++_test_config",
"grpc++_test_util",
"grpc_test_util"
],
"headers": [
"src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h",
"test/cpp/interop/http2_client.h"
],
"is_filegroup": false,
"language": "c++",
"name": "http2_client_main",
"src": [
"test/cpp/interop/http2_client.cc",
"test/cpp/interop/http2_client.h"
],
"third_party": false,
"type": "lib"
},
{
"deps": [
"gpr",
@ -5447,6 +5491,7 @@
"gpr",
"grpc",
"grpc++",
"grpc++_test_util",
"grpc_test_util"
],
"headers": [

@ -115,9 +115,11 @@ def _flatten_result_inplace(scenario_result):
scenario_result['scenario']['clientConfig'] = json.dumps(scenario_result['scenario']['clientConfig'])
scenario_result['scenario']['serverConfig'] = json.dumps(scenario_result['scenario']['serverConfig'])
scenario_result['latencies'] = json.dumps(scenario_result['latencies'])
scenario_result['serverCpuStats'] = []
for stats in scenario_result['serverStats']:
stats.pop('totalCpuTime', None)
stats.pop('idleCpuTime', None)
scenario_result['serverCpuStats'].append(dict())
scenario_result['serverCpuStats'][-1]['totalCpuTime'] = stats.pop('totalCpuTime', None)
scenario_result['serverCpuStats'][-1]['idleCpuTime'] = stats.pop('idleCpuTime', None)
for stats in scenario_result['clientStats']:
stats['latencies'] = json.dumps(stats['latencies'])
stats.pop('requestResults', None)
@ -125,7 +127,7 @@ def _flatten_result_inplace(scenario_result):
scenario_result['clientSuccess'] = json.dumps(scenario_result['clientSuccess'])
scenario_result['serverSuccess'] = json.dumps(scenario_result['serverSuccess'])
scenario_result['requestResults'] = json.dumps(scenario_result.get('requestResults', []))
scenario_result['summary'].pop('serverCpuUsage', None)
scenario_result['serverCpuUsage'] = scenario_result['summary'].pop('serverCpuUsage', None)
scenario_result['summary'].pop('successfulRequestsPerSecond', None)
scenario_result['summary'].pop('failedRequestsPerSecond', None)

@ -213,5 +213,27 @@
"name": "requestResults",
"type": "STRING",
"mode": "NULLABLE"
},
{
"name": "serverCpuStats",
"type": "RECORD",
"mode": "REPEATED",
"fields": [
{
"name": "totalCpuTime",
"type": "INTEGER",
"mode": "NULLABLE"
},
{
"name": "idleCpuTime",
"type": "INTEGER",
"mode": "NULLABLE"
}
]
},
{
"name": "serverCpuUsage",
"type": "FLOAT",
"mode": "NULLABLE"
}
]

@ -169,6 +169,9 @@ class JavaLanguage:
def client_cmd(self, args):
return ['./run-test-client.sh'] + args
def client_cmd_http2interop(self, args):
return ['./run-http2-client.sh'] + args
def cloud_to_prod_env(self):
return {}
@ -217,6 +220,33 @@ class GoLanguage:
def __str__(self):
return 'go'
class Http2Server:
"""Represents the HTTP/2 Interop Test server
This pretends to be a language in order to be built and run, but really it
isn't.
"""
def __init__(self):
self.server_cwd = None
self.safename = str(self)
def server_cmd(self, args):
return ['python test/http2_test/http2_test_server.py']
def cloud_to_prod_env(self):
return {}
def global_env(self):
return {}
def unimplemented_test_cases(self):
return _TEST_CASES
def unimplemented_test_cases_server(self):
return _TEST_CASES
def __str__(self):
return 'http2'
class Http2Client:
"""Represents the HTTP/2 Interop Test
@ -375,6 +405,11 @@ class PythonLanguage:
'--args="{}"'.format(' '.join(args))
]
def client_cmd_http2interop(self, args):
return [ 'py27/bin/python',
'src/python/grpcio_tests/tests/http2/_negative_http2_client.py',
] + args
def cloud_to_prod_env(self):
return {}
@ -429,7 +464,10 @@ _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", "framing"]
_HTTP2_TEST_CASES = ['tls', 'framing']
_HTTP2_BADSERVER_TEST_CASES = ['rst_after_header', 'rst_after_data', 'rst_during_data',
'goaway', 'ping', 'max_streams']
DOCKER_WORKDIR_ROOT = '/var/local/git/grpc'
@ -550,13 +588,25 @@ def cloud_to_prod_jobspec(language, test_case, server_host_name,
def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
server_port, docker_image=None):
"""Creates jobspec for cloud-to-cloud interop test"""
cmdline = bash_cmdline(language.client_cmd([
interop_only_options = [
'--server_host_override=foo.test.google.fr',
'--use_tls=true',
'--use_test_ca=true',
]
common_options = [
'--test_case=%s' % test_case,
'--server_host=%s' % server_host,
'--server_port=%s' % server_port]))
]
if test_case in _HTTP2_BADSERVER_TEST_CASES:
# We are running the http2_badserver_interop test. Adjust command line accordingly.
offset = sorted(_HTTP2_BADSERVER_TEST_CASES).index(test_case)
client_options = common_options + ['--server_port=%s' %
(int(server_port)+offset)]
cmdline = bash_cmdline(language.client_cmd_http2interop(client_options))
else:
client_options = interop_only_options + common_options + ['--server_port=%s' % server_port]
cmdline = bash_cmdline(language.client_cmd(client_options))
cwd = language.client_cwd
environ = language.global_env()
if docker_image:
@ -590,13 +640,30 @@ def server_jobspec(language, docker_image):
cmdline = bash_cmdline(
language.server_cmd(['--port=%s' % _DEFAULT_SERVER_PORT]))
environ = language.global_env()
if language.safename == 'http2':
# we are running the http2 interop server. Open next N ports beginning
# with the server port. These ports are used for http2 interop test
# (one test case per port). We also attach the docker container running
# the server to local network, so we don't have to mess with port mapping
port_args = [
'-p', str(_DEFAULT_SERVER_PORT+0),
'-p', str(_DEFAULT_SERVER_PORT+1),
'-p', str(_DEFAULT_SERVER_PORT+2),
'-p', str(_DEFAULT_SERVER_PORT+3),
'-p', str(_DEFAULT_SERVER_PORT+4),
'-p', str(_DEFAULT_SERVER_PORT+5),
'-p', str(_DEFAULT_SERVER_PORT+6),
'--net=host',
]
else:
port_args = ['-p', str(_DEFAULT_SERVER_PORT)]
docker_cmdline = docker_run_cmdline(cmdline,
image=docker_image,
cwd=language.server_cwd,
environ=environ,
docker_args=['-p', str(_DEFAULT_SERVER_PORT),
'--name', container_name])
docker_args=port_args +
['--name', container_name])
server_job = jobset.JobSpec(
cmdline=docker_cmdline,
environ=environ,
@ -730,7 +797,12 @@ argp.add_argument('--http2_interop',
default=False,
action='store_const',
const=True,
help='Enable HTTP/2 interop tests')
help='Enable HTTP/2 client edge case testing. (Bad client, good server)')
argp.add_argument('--http2_badserver_interop',
default=False,
action='store_const',
const=True,
help='Enable HTTP/2 server edge case testing. (Good client, bad server)')
args = argp.parse_args()
@ -757,6 +829,7 @@ languages = set(_LANGUAGES[l]
for x in args.language))
http2Interop = Http2Client() if args.http2_interop else None
http2InteropServer = Http2Server() if args.http2_badserver_interop else None
docker_images={}
if args.use_docker:
@ -766,6 +839,9 @@ if args.use_docker:
if args.http2_interop:
languages_to_build.add(http2Interop)
if args.http2_badserver_interop:
languages_to_build.add(http2InteropServer)
build_jobs = []
for l in languages_to_build:
job = build_interop_image_jobspec(l)
@ -797,6 +873,14 @@ try:
server_jobs[lang] = job
server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
if args.http2_badserver_interop:
# launch a HTTP2 server emulator that creates edge cases
lang = str(http2InteropServer)
spec = server_jobspec(http2InteropServer, docker_images.get(lang))
job = dockerjob.DockerJob(spec)
server_jobs[lang] = job
server_addresses[lang] = ('localhost', _DEFAULT_SERVER_PORT)
jobs = []
if args.cloud_to_prod:
for server_host_name in args.prod_servers:
@ -840,17 +924,18 @@ try:
skip_server = [] # test cases unimplemented by server
if server_language:
skip_server = server_language.unimplemented_test_cases_server()
for language in languages:
for test_case in _TEST_CASES:
if not test_case in language.unimplemented_test_cases():
if not test_case in skip_server:
test_job = cloud_to_cloud_jobspec(language,
test_case,
server_name,
server_host,
server_port,
docker_image=docker_images.get(str(language)))
jobs.append(test_job)
if not args.http2_badserver_interop:
for language in languages:
for test_case in _TEST_CASES:
if not test_case in language.unimplemented_test_cases():
if not test_case in skip_server:
test_job = cloud_to_cloud_jobspec(language,
test_case,
server_name,
server_host,
server_port,
docker_image=docker_images.get(str(language)))
jobs.append(test_job)
if args.http2_interop:
for test_case in _HTTP2_TEST_CASES:
@ -865,6 +950,17 @@ try:
docker_image=docker_images.get(str(http2Interop)))
jobs.append(test_job)
if args.http2_badserver_interop:
for language in languages:
for test_case in _HTTP2_BADSERVER_TEST_CASES:
test_job = cloud_to_cloud_jobspec(language,
test_case,
server_name,
server_host,
server_port,
docker_image=docker_images.get(str(language)))
jobs.append(test_job)
if not jobs:
print('No jobs to run.')
for image in docker_images.itervalues():

@ -113,7 +113,7 @@ def create_qpsworker_job(language, shortname=None, port=10000, remote_host=None,
def create_scenario_jobspec(scenario_json, workers, remote_host=None,
bq_result_table=None):
bq_result_table=None, server_cpu_load=0):
"""Runs one scenario using QPS driver."""
# setting QPS_WORKERS env variable here makes sure it works with SSH too.
cmd = 'QPS_WORKERS="%s" ' % ','.join(workers)
@ -121,7 +121,9 @@ def create_scenario_jobspec(scenario_json, workers, remote_host=None,
cmd += 'BQ_RESULT_TABLE="%s" ' % bq_result_table
cmd += 'tools/run_tests/performance/run_qps_driver.sh '
cmd += '--scenarios_json=%s ' % pipes.quote(json.dumps({'scenarios': [scenario_json]}))
cmd += '--scenario_result_file=scenario_result.json'
cmd += '--scenario_result_file=scenario_result.json '
if server_cpu_load != 0:
cmd += '--search_param=offered_load --initial_search_value=1000 --targeted_cpu_load=%d --stride=500 --error_tolerance=0.01' % server_cpu_load
if remote_host:
user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, remote_host)
cmd = 'ssh %s "cd ~/performance_workspace/grpc/ && "%s' % (user_at_host, pipes.quote(cmd))
@ -129,7 +131,7 @@ def create_scenario_jobspec(scenario_json, workers, remote_host=None,
return jobset.JobSpec(
cmdline=[cmd],
shortname='qps_json_driver.%s' % scenario_json['name'],
timeout_seconds=3*60,
timeout_seconds=12*60,
shell=True,
verbose_success=True)
@ -318,7 +320,7 @@ Scenario = collections.namedtuple('Scenario', 'jobspec workers name')
def create_scenarios(languages, workers_by_lang, remote_host=None, regex='.*',
category='all', bq_result_table=None,
netperf=False, netperf_hosts=[]):
netperf=False, netperf_hosts=[], server_cpu_load=0):
"""Create jobspecs for scenarios to run."""
all_workers = [worker
for workers in workers_by_lang.values()
@ -379,7 +381,8 @@ def create_scenarios(languages, workers_by_lang, remote_host=None, regex='.*',
create_scenario_jobspec(scenario_json,
[w.host_and_port for w in workers],
remote_host=remote_host,
bq_result_table=bq_result_table),
bq_result_table=bq_result_table,
server_cpu_load=server_cpu_load),
workers,
scenario_json['name'])
scenarios.append(scenario)
@ -461,6 +464,9 @@ argp.add_argument('--netperf',
action='store_const',
const=True,
help='Run netperf benchmark as one of the scenarios.')
argp.add_argument('--server_cpu_load',
default=0, type=int,
help='Select a targeted server cpu load to run. 0 means ignore this flag')
argp.add_argument('-x', '--xml_report', default='report.xml', type=str,
help='Name of XML report file to generate.')
argp.add_argument('--perf_args',
@ -490,7 +496,6 @@ argp.add_argument('--skip_generate_flamegraphs',
'May be useful if "perf_args" arguments do not make sense for '
'generating flamegraphs (e.g., "--perf_args=stat ...")'))
args = argp.parse_args()
languages = set(scenario_config.LANGUAGES[l]
@ -540,7 +545,8 @@ scenarios = create_scenarios(languages,
category=args.category,
bq_result_table=args.bq_result_table,
netperf=args.netperf,
netperf_hosts=args.remote_worker_host)
netperf_hosts=args.remote_worker_host,
server_cpu_load=args.server_cpu_load)
if not scenarios:
raise Exception('No scenarios to run')

@ -0,0 +1,206 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{8008C126-4B35-5A76-A795-39DA13DA57F4}</ProjectGuid>
<IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
<IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
<PlatformToolset>v100</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(SolutionDir)\..\vsprojects\global.props" />
<Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<TargetName>http2_client_main</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<TargetName>http2_client_main</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<TreatWarningAsError>true</TreatWarningAsError>
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
<MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<TreatWarningAsError>true</TreatWarningAsError>
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
<MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<TreatWarningAsError>true</TreatWarningAsError>
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
<MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<TreatWarningAsError>true</TreatWarningAsError>
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
<MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="$(SolutionDir)\..\test\cpp\interop\http2_client.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\empty.pb.cc">
</ClCompile>
<ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\empty.pb.h">
</ClInclude>
<ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\empty.grpc.pb.cc">
</ClCompile>
<ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\empty.grpc.pb.h">
</ClInclude>
<ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.pb.cc">
</ClCompile>
<ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.pb.h">
</ClInclude>
<ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.grpc.pb.cc">
</ClCompile>
<ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.grpc.pb.h">
</ClInclude>
<ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\test.pb.cc">
</ClCompile>
<ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\test.pb.h">
</ClInclude>
<ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\test.grpc.pb.cc">
</ClCompile>
<ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\test.grpc.pb.h">
</ClInclude>
<ClCompile Include="$(SolutionDir)\..\test\cpp\interop\http2_client.cc">
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_util\grpc++_test_util.vcxproj">
<Project>{0BE77741-552A-929B-A497-4EF7ECE17A64}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
<Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
<Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
<Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_config\grpc++_test_config.vcxproj">
<Project>{3F7D093D-11F9-C4BC-BEB7-18EB28E3F290}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
</Target>
</Project>

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\empty.proto">
<Filter>src\proto\grpc\testing</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.proto">
<Filter>src\proto\grpc\testing</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\test.proto">
<Filter>src\proto\grpc\testing</Filter>
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\cpp\interop\http2_client.cc">
<Filter>test\cpp\interop</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(SolutionDir)\..\test\cpp\interop\http2_client.h">
<Filter>test\cpp\interop</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="src">
<UniqueIdentifier>{8f01743f-58cf-2127-20d1-21303c8e0e8e}</UniqueIdentifier>
</Filter>
<Filter Include="src\proto">
<UniqueIdentifier>{219dd0bc-d605-d0fa-cca4-460276dd64cf}</UniqueIdentifier>
</Filter>
<Filter Include="src\proto\grpc">
<UniqueIdentifier>{7ee50971-dbc6-3240-e6a2-a432dac43e90}</UniqueIdentifier>
</Filter>
<Filter Include="src\proto\grpc\testing">
<UniqueIdentifier>{66289b19-9541-151c-03a1-771101833b4e}</UniqueIdentifier>
</Filter>
<Filter Include="test">
<UniqueIdentifier>{18fdd193-31a2-a622-980e-df055c23af50}</UniqueIdentifier>
</Filter>
<Filter Include="test\cpp">
<UniqueIdentifier>{f6da8892-ac51-d835-468a-b3b093df4baa}</UniqueIdentifier>
</Filter>
<Filter Include="test\cpp\interop">
<UniqueIdentifier>{e32cff29-3247-cece-56cf-8fd16a1a79fe}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

@ -154,6 +154,9 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_util\grpc++_test_util.vcxproj">
<Project>{0BE77741-552A-929B-A497-4EF7ECE17A64}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
<Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
</ProjectReference>

Loading…
Cancel
Save