Merge branch 'master' into server-context

pull/23916/head
Karthik Ravi Shankar 5 years ago
commit c6f2c3206a
  1. 1
      include/grpcpp/server_impl.h
  2. 14
      src/compiler/php_generator.cc
  3. 3
      src/core/ext/filters/client_channel/client_channel_channelz.h
  4. 1
      src/core/ext/filters/client_channel/lb_policy/xds/eds.cc
  5. 1
      src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
  6. 42
      src/core/ext/transport/cronet/transport/cronet_transport.cc
  7. 48
      src/core/ext/xds/xds_api.cc
  8. 11
      src/core/ext/xds/xds_api.h
  9. 6
      src/core/ext/xds/xds_client.cc
  10. 6
      src/core/ext/xds/xds_client.h
  11. 1
      src/core/lib/iomgr/endpoint.h
  12. 4
      src/objective-c/tests/CronetTests/CoreCronetEnd2EndTests.mm
  13. 8
      src/php/tests/generated_code/Math/MathClient.php
  14. 2
      src/php/tests/interop/Grpc/Testing/LoadBalancerStatsServiceClient.php
  15. 4
      src/php/tests/interop/Grpc/Testing/ReconnectServiceClient.php
  16. 16
      src/php/tests/interop/Grpc/Testing/TestServiceClient.php
  17. 2
      src/php/tests/interop/Grpc/Testing/UnimplementedServiceClient.php
  18. 4
      src/php/tests/interop/Grpc/Testing/XdsUpdateHealthServiceClient.php
  19. 156
      src/python/grpcio_tests/tests_py3_only/interop/xds_interop_client.py
  20. 4
      test/cpp/common/BUILD
  21. 10
      test/cpp/end2end/BUILD
  22. 8
      tools/bazel.rc
  23. 3
      tools/internal_ci/linux/grpc_bazel_build_in_docker.sh
  24. 5
      tools/internal_ci/linux/grpc_bazel_test_in_docker.sh
  25. 2
      tools/internal_ci/linux/grpc_flaky_network_in_docker.sh
  26. 2
      tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh
  27. 8
      tools/internal_ci/linux/grpc_xds_bazel_python_test_in_docker.sh
  28. 6
      tools/internal_ci/macos/grpc_run_bazel_isolated_tests.sh
  29. 43
      tools/run_tests/run_microbenchmark.py
  30. 48
      tools/run_tests/run_xds_tests.py

@ -54,7 +54,6 @@ class ExternalConnectionAcceptorImpl;
} // namespace grpc
namespace grpc_impl {
class HealthCheckServiceInterface;
class ServerInitializer;
/// Represents a gRPC server.

@ -78,10 +78,15 @@ void PrintMethod(const MethodDescriptor* method, Printer* out) {
out->Print("/**\n");
out->Print(GetPHPComments(method, " *").c_str());
if (method->client_streaming()) {
if (method->server_streaming()) {
vars["return_type_id"] = "\\Grpc\\BidiStreamingCall";
} else {
vars["return_type_id"] = "\\Grpc\\ClientStreamingCall";
}
out->Print(vars,
" * @param array $$metadata metadata\n"
" * @param array $$options call options\n"
" * @return \\$output_type_id$\n */\n"
" * @return $return_type_id$\n */\n"
"public function $name$($$metadata = [], "
"$$options = []) {\n");
out->Indent();
@ -96,11 +101,16 @@ void PrintMethod(const MethodDescriptor* method, Printer* out) {
"['\\$output_type_id$','decode'],\n"
"$$metadata, $$options);\n");
} else {
if (method->server_streaming()) {
vars["return_type_id"] = "\\Grpc\\ServerStreamingCall";
} else {
vars["return_type_id"] = "\\Grpc\\UnaryCall";
}
out->Print(vars,
" * @param \\$input_type_id$ $$argument input argument\n"
" * @param array $$metadata metadata\n"
" * @param array $$options call options\n"
" * @return \\$output_type_id$\n */\n"
" * @return $return_type_id$\n */\n"
"public function $name$(\\$input_type_id$ $$argument,\n"
" $$metadata = [], $$options = []) {\n");
out->Indent();

@ -29,9 +29,6 @@
#include "src/core/lib/channel/channelz.h"
namespace grpc_core {
class Subchannel;
namespace channelz {
class SubchannelNode : public BaseNode {

@ -457,7 +457,6 @@ void EdsLb::UpdateLocked(UpdateArgs args) {
grpc_error* error = GRPC_ERROR_NONE;
xds_client_ = MakeOrphanable<XdsClient>(
work_serializer(), interested_parties(), GetEdsResourceName(),
std::vector<grpc_resolved_address>{},
nullptr /* service config watcher */, *args_, &error);
// TODO(roth): If we decide that we care about EDS-only mode, add
// proper error handling here.

@ -191,7 +191,6 @@ void XdsResolver::StartLocked() {
grpc_error* error = GRPC_ERROR_NONE;
xds_client_ = MakeOrphanable<XdsClient>(
work_serializer(), interested_parties_, server_name_,
std::vector<grpc_resolved_address>{},
absl::make_unique<ListenerWatcher>(Ref()), *args_, &error);
if (error != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR,

@ -295,31 +295,6 @@ static void null_and_maybe_free_read_buffer(stream_obj* s) {
s->state.rs.read_buffer = nullptr;
}
static void maybe_flush_read(stream_obj* s) {
/* To enter flush read state (discarding all the buffered messages in
* transport layer), two conditions must be satisfied: 1) non-zero grpc status
* has been received, and 2) an op requesting the status code
* (RECV_TRAILING_METADATA) is issued by the user. (See
* doc/status_ordering.md) */
/* Whenever the evaluation of any of the two condition is changed, we check
* whether we should enter the flush read state. */
if (s->state.pending_recv_trailing_metadata && s->state.fail_state) {
if (!s->state.flush_read && !s->state.rs.read_stream_closed) {
CRONET_LOG(GPR_DEBUG, "%p: Flush read", s);
s->state.flush_read = true;
null_and_maybe_free_read_buffer(s);
s->state.rs.read_buffer =
static_cast<char*>(gpr_malloc(GRPC_FLUSH_READ_SIZE));
if (!s->state.pending_read_from_cronet) {
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
bidirectional_stream_read(s->cbs, s->state.rs.read_buffer,
GRPC_FLUSH_READ_SIZE);
s->state.pending_read_from_cronet = true;
}
}
}
}
static void read_grpc_header(stream_obj* s) {
s->state.rs.read_buffer = s->state.rs.grpc_header_bytes;
s->state.rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
@ -359,7 +334,6 @@ static void add_to_storage(struct stream_obj* s,
}
if (op->recv_trailing_metadata) {
s->state.pending_recv_trailing_metadata = true;
maybe_flush_read(s);
}
CRONET_LOG(GPR_DEBUG, "adding new op %p. %d in the queue.", new_op,
storage->num_pending_ops);
@ -569,11 +543,10 @@ static void on_response_headers_received(
for (size_t i = 0; i < headers->count; i++) {
if (0 == strcmp("grpc-status", headers->headers[i].key)) {
on_response_trailers_received(stream, headers);
/* Do an extra read for a trailer-only stream with grpc_status = 0
to trigger on_succeeded() callback */
if (0 == strcmp(headers->headers[i].value, "0")) {
read_grpc_header(s);
}
/* Do an extra read for a trailer-only stream to trigger on_succeeded()
* callback */
read_grpc_header(s);
return;
}
}
@ -670,13 +643,6 @@ static void on_response_trailers_received(
if (trailers->count > 0) {
s->state.rs.trailing_metadata_valid = true;
}
for (size_t i = 0; i < trailers->count; i++) {
if (0 == strcmp(trailers->headers[i].key, "grpc-status") &&
0 != strcmp(trailers->headers[i].value, "0")) {
s->state.fail_state = true;
maybe_flush_read(s);
}
}
s->state.state_callback_received[OP_RECV_TRAILING_METADATA] = true;
/* Send a EOS when server terminates the stream (testServerFinishesRequest) to
* trigger on_succeeded */

@ -24,7 +24,6 @@
#include <cstdlib>
#include <string>
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
@ -40,7 +39,6 @@
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
@ -465,7 +463,6 @@ void PopulateNode(upb_arena* arena, const XdsBootstrap* bootstrap,
const std::string& build_version,
const std::string& user_agent_name,
const std::string& server_name,
const std::vector<grpc_resolved_address>& listening_addresses,
envoy_config_core_v3_Node* node_msg) {
const XdsBootstrap::Node* node = bootstrap->node();
if (node != nullptr) {
@ -513,21 +510,6 @@ void PopulateNode(upb_arena* arena, const XdsBootstrap* bootstrap,
if (!bootstrap->server().ShouldUseV3()) {
PopulateBuildVersion(arena, node_msg, build_version);
}
for (const grpc_resolved_address& address : listening_addresses) {
std::string address_str = grpc_sockaddr_to_string(&address, false);
absl::string_view addr_str;
absl::string_view port_str;
GPR_ASSERT(SplitHostPort(address_str, &addr_str, &port_str));
uint32_t port;
GPR_ASSERT(absl::SimpleAtoi(port_str, &port));
auto* addr_msg =
envoy_config_core_v3_Node_add_listening_addresses(node_msg, arena);
auto* socket_addr_msg =
envoy_config_core_v3_Address_mutable_socket_address(addr_msg, arena);
envoy_config_core_v3_SocketAddress_set_address(
socket_addr_msg, upb_strview_make(addr_str.data(), addr_str.size()));
envoy_config_core_v3_SocketAddress_set_port_value(socket_addr_msg, port);
}
envoy_config_core_v3_Node_set_user_agent_name(
node_msg,
upb_strview_make(user_agent_name.data(), user_agent_name.size()));
@ -646,29 +628,6 @@ void AddNodeLogFields(const envoy_config_core_v3_Node* node,
fields->emplace_back(
absl::StrCat(" build_version: \"", build_version, "\""));
}
// listening_addresses
size_t num_listening_addresses;
const envoy_config_core_v3_Address* const* listening_addresses =
envoy_config_core_v3_Node_listening_addresses(node,
&num_listening_addresses);
for (size_t i = 0; i < num_listening_addresses; ++i) {
fields->emplace_back(" listening_address {");
const auto* socket_addr_msg =
envoy_config_core_v3_Address_socket_address(listening_addresses[i]);
if (socket_addr_msg != nullptr) {
fields->emplace_back(" socket_address {");
AddStringField(
" address",
envoy_config_core_v3_SocketAddress_address(socket_addr_msg), fields);
if (envoy_config_core_v3_SocketAddress_has_port_value(socket_addr_msg)) {
fields->emplace_back(absl::StrCat(
" port_value: ",
envoy_config_core_v3_SocketAddress_port_value(socket_addr_msg)));
}
fields->emplace_back(" }");
}
fields->emplace_back(" }");
}
// user_agent_name
AddStringField(" user_agent_name",
envoy_config_core_v3_Node_user_agent_name(node), fields);
@ -771,8 +730,7 @@ grpc_slice XdsApi::CreateAdsRequest(
const std::string& type_url,
const std::set<absl::string_view>& resource_names,
const std::string& version, const std::string& nonce, grpc_error* error,
bool populate_node,
const std::vector<grpc_resolved_address>& listening_addresses) {
bool populate_node) {
upb::Arena arena;
// Create a request.
envoy_service_discovery_v3_DiscoveryRequest* request =
@ -813,7 +771,7 @@ grpc_slice XdsApi::CreateAdsRequest(
envoy_service_discovery_v3_DiscoveryRequest_mutable_node(request,
arena.ptr());
PopulateNode(arena.ptr(), bootstrap_, build_version_, user_agent_name_, "",
listening_addresses, node_msg);
node_msg);
}
// Add resource_names.
for (const auto& resource_name : resource_names) {
@ -2239,7 +2197,7 @@ grpc_slice XdsApi::CreateLrsInitialRequest(const std::string& server_name) {
envoy_service_load_stats_v3_LoadStatsRequest_mutable_node(request,
arena.ptr());
PopulateNode(arena.ptr(), bootstrap_, build_version_, user_agent_name_,
server_name, {}, node_msg);
server_name, node_msg);
envoy_config_core_v3_Node_add_client_features(
node_msg, upb_strview_makez("envoy.lrs.supports_send_all_clusters"),
arena.ptr());

@ -295,12 +295,11 @@ class XdsApi {
// Creates an ADS request.
// Takes ownership of \a error.
grpc_slice CreateAdsRequest(
const std::string& type_url,
const std::set<absl::string_view>& resource_names,
const std::string& version, const std::string& nonce, grpc_error* error,
bool populate_node,
const std::vector<grpc_resolved_address>& listening_addresses);
grpc_slice CreateAdsRequest(const std::string& type_url,
const std::set<absl::string_view>& resource_names,
const std::string& version,
const std::string& nonce, grpc_error* error,
bool populate_node);
// Parses an ADS response.
// If the response can't be parsed at the top level, the resulting

@ -679,6 +679,7 @@ XdsClient::ChannelState::AdsCallState::AdsCallState(
// activity in xds_client()->interested_parties_, which is comprised of
// the polling entities from client_channel.
GPR_ASSERT(xds_client() != nullptr);
GPR_ASSERT(!xds_client()->server_name_.empty());
// Create a call with the specified method name.
const auto& method =
xds_client()->bootstrap_->server().ShouldUseV3()
@ -805,8 +806,7 @@ void XdsClient::ChannelState::AdsCallState::SendMessageLocked(
ResourceNamesForRequest(type_url);
request_payload_slice = xds_client()->api_.CreateAdsRequest(
type_url, resource_names, state.version, state.nonce,
GRPC_ERROR_REF(state.error), !sent_initial_message_,
xds_client()->listening_addresses_);
GRPC_ERROR_REF(state.error), !sent_initial_message_);
if (type_url != XdsApi::kLdsTypeUrl && type_url != XdsApi::kRdsTypeUrl &&
type_url != XdsApi::kCdsTypeUrl && type_url != XdsApi::kEdsTypeUrl) {
state_map_.erase(type_url);
@ -1752,7 +1752,6 @@ grpc_millis GetRequestTimeout(const grpc_channel_args& args) {
XdsClient::XdsClient(std::shared_ptr<WorkSerializer> work_serializer,
grpc_pollset_set* interested_parties,
absl::string_view server_name,
std::vector<grpc_resolved_address> listening_addresses,
std::unique_ptr<ListenerWatcherInterface> watcher,
const grpc_channel_args& channel_args, grpc_error** error)
: InternallyRefCounted<XdsClient>(&grpc_xds_client_trace),
@ -1763,7 +1762,6 @@ XdsClient::XdsClient(std::shared_ptr<WorkSerializer> work_serializer,
XdsBootstrap::ReadFromFile(this, &grpc_xds_client_trace, error)),
api_(this, &grpc_xds_client_trace, bootstrap_.get()),
server_name_(server_name),
listening_addresses_(std::move(listening_addresses)),
listener_watcher_(std::move(watcher)) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
gpr_log(GPR_INFO, "[xds_client %p] creating xds client", this);

@ -20,7 +20,6 @@
#include <grpc/support/port_platform.h>
#include <set>
#include <vector>
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
@ -33,7 +32,6 @@
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/work_serializer.h"
namespace grpc_core {
@ -78,13 +76,10 @@ class XdsClient : public InternallyRefCounted<XdsClient> {
virtual void OnResourceDoesNotExist() = 0;
};
// gRPC client should populate server_name.
// gRPC server should populate listening_addresses.
// If *error is not GRPC_ERROR_NONE after construction, then there was
// an error initializing the client.
XdsClient(std::shared_ptr<WorkSerializer> work_serializer,
grpc_pollset_set* interested_parties, absl::string_view server_name,
std::vector<grpc_resolved_address> listening_addresses,
std::unique_ptr<ListenerWatcherInterface> watcher,
const grpc_channel_args& channel_args, grpc_error** error);
~XdsClient();
@ -256,7 +251,6 @@ class XdsClient : public InternallyRefCounted<XdsClient> {
XdsApi api_;
const std::string server_name_;
const std::vector<grpc_resolved_address> listening_addresses_;
std::unique_ptr<ListenerWatcherInterface> listener_watcher_;
// The channel for communicating with the xds server.

@ -35,7 +35,6 @@
typedef struct grpc_endpoint grpc_endpoint;
typedef struct grpc_endpoint_vtable grpc_endpoint_vtable;
class Timestamps;
struct grpc_endpoint_vtable {
void (*read)(grpc_endpoint* ep, grpc_slice_buffer* slices, grpc_closure* cb,

@ -347,6 +347,10 @@ static char *roots_filename;
[self testIndividualCase:(char *)"server_finishes_request"];
}
- (void)testServerStreaming {
[self testIndividualCase:(char *)"server_streaming"];
}
- (void)testShutdownFinishesCalls {
[self testIndividualCase:(char *)"shutdown_finishes_calls"];
}

@ -37,7 +37,7 @@ class MathClient extends \Grpc\BaseStub {
* @param \Math\DivArgs $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Math\DivReply
* @return \Grpc\UnaryCall
*/
public function Div(\Math\DivArgs $argument,
$metadata = [], $options = []) {
@ -54,7 +54,7 @@ class MathClient extends \Grpc\BaseStub {
* replies. The stream ends immediately if either end aborts.
* @param array $metadata metadata
* @param array $options call options
* @return \Math\DivReply
* @return \Grpc\BidiStreamingCall
*/
public function DivMany($metadata = [], $options = []) {
return $this->_bidiRequest('/math.Math/DivMany',
@ -69,7 +69,7 @@ class MathClient extends \Grpc\BaseStub {
* @param \Math\FibArgs $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Math\Num
* @return \Grpc\ServerStreamingCall
*/
public function Fib(\Math\FibArgs $argument,
$metadata = [], $options = []) {
@ -84,7 +84,7 @@ class MathClient extends \Grpc\BaseStub {
* is closed.
* @param array $metadata metadata
* @param array $options call options
* @return \Math\Num
* @return \Grpc\ClientStreamingCall
*/
public function Sum($metadata = [], $options = []) {
return $this->_clientStreamRequest('/math.Math/Sum',

@ -40,7 +40,7 @@ class LoadBalancerStatsServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\LoadBalancerStatsRequest $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\LoadBalancerStatsResponse
* @return \Grpc\UnaryCall
*/
public function GetClientStats(\Grpc\Testing\LoadBalancerStatsRequest $argument,
$metadata = [], $options = []) {

@ -39,7 +39,7 @@ class ReconnectServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\ReconnectParams $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\EmptyMessage
* @return \Grpc\UnaryCall
*/
public function Start(\Grpc\Testing\ReconnectParams $argument,
$metadata = [], $options = []) {
@ -53,7 +53,7 @@ class ReconnectServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\EmptyMessage $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\ReconnectInfo
* @return \Grpc\UnaryCall
*/
public function Stop(\Grpc\Testing\EmptyMessage $argument,
$metadata = [], $options = []) {

@ -41,7 +41,7 @@ class TestServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\EmptyMessage $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\EmptyMessage
* @return \Grpc\UnaryCall
*/
public function EmptyCall(\Grpc\Testing\EmptyMessage $argument,
$metadata = [], $options = []) {
@ -56,7 +56,7 @@ class TestServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\SimpleRequest $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\SimpleResponse
* @return \Grpc\UnaryCall
*/
public function UnaryCall(\Grpc\Testing\SimpleRequest $argument,
$metadata = [], $options = []) {
@ -73,7 +73,7 @@ class TestServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\SimpleRequest $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\SimpleResponse
* @return \Grpc\UnaryCall
*/
public function CacheableUnaryCall(\Grpc\Testing\SimpleRequest $argument,
$metadata = [], $options = []) {
@ -89,7 +89,7 @@ class TestServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\StreamingOutputCallRequest $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\StreamingOutputCallResponse
* @return \Grpc\ServerStreamingCall
*/
public function StreamingOutputCall(\Grpc\Testing\StreamingOutputCallRequest $argument,
$metadata = [], $options = []) {
@ -104,7 +104,7 @@ class TestServiceClient extends \Grpc\BaseStub {
* The server returns the aggregated size of client payload as the result.
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\StreamingInputCallResponse
* @return \Grpc\ClientStreamingCall
*/
public function StreamingInputCall($metadata = [], $options = []) {
return $this->_clientStreamRequest('/grpc.testing.TestService/StreamingInputCall',
@ -118,7 +118,7 @@ class TestServiceClient extends \Grpc\BaseStub {
* demonstrates the idea of full duplexing.
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\StreamingOutputCallResponse
* @return \Grpc\BidiStreamingCall
*/
public function FullDuplexCall($metadata = [], $options = []) {
return $this->_bidiRequest('/grpc.testing.TestService/FullDuplexCall',
@ -133,7 +133,7 @@ class TestServiceClient extends \Grpc\BaseStub {
* first request.
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\StreamingOutputCallResponse
* @return \Grpc\BidiStreamingCall
*/
public function HalfDuplexCall($metadata = [], $options = []) {
return $this->_bidiRequest('/grpc.testing.TestService/HalfDuplexCall',
@ -147,7 +147,7 @@ class TestServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\EmptyMessage $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\EmptyMessage
* @return \Grpc\UnaryCall
*/
public function UnimplementedCall(\Grpc\Testing\EmptyMessage $argument,
$metadata = [], $options = []) {

@ -41,7 +41,7 @@ class UnimplementedServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\EmptyMessage $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\EmptyMessage
* @return \Grpc\UnaryCall
*/
public function UnimplementedCall(\Grpc\Testing\EmptyMessage $argument,
$metadata = [], $options = []) {

@ -39,7 +39,7 @@ class XdsUpdateHealthServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\EmptyMessage $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\EmptyMessage
* @return \Grpc\UnaryCall
*/
public function SetServing(\Grpc\Testing\EmptyMessage $argument,
$metadata = [], $options = []) {
@ -53,7 +53,7 @@ class XdsUpdateHealthServiceClient extends \Grpc\BaseStub {
* @param \Grpc\Testing\EmptyMessage $argument input argument
* @param array $metadata metadata
* @param array $options call options
* @return \Grpc\Testing\EmptyMessage
* @return \Grpc\UnaryCall
*/
public function SetNotServing(\Grpc\Testing\EmptyMessage $argument,
$metadata = [], $options = []) {

@ -19,7 +19,7 @@ import threading
import time
import sys
from typing import DefaultDict, Dict, List, Mapping, Set
from typing import DefaultDict, Dict, List, Mapping, Set, Sequence, Tuple
import collections
from concurrent import futures
@ -37,12 +37,20 @@ formatter = logging.Formatter(fmt='%(asctime)s: %(levelname)-8s %(message)s')
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
_SUPPORTED_METHODS = (
"UnaryCall",
"EmptyCall",
)
PerMethodMetadataType = Mapping[str, Sequence[Tuple[str, str]]]
class _StatsWatcher:
_start: int
_end: int
_rpcs_needed: int
_rpcs_by_peer: DefaultDict[str, int]
_rpcs_by_method: DefaultDict[str, DefaultDict[str, int]]
_no_remote_peer: int
_lock: threading.Lock
_condition: threading.Condition
@ -52,10 +60,12 @@ class _StatsWatcher:
self._end = end
self._rpcs_needed = end - start
self._rpcs_by_peer = collections.defaultdict(int)
self._rpcs_by_method = collections.defaultdict(
lambda: collections.defaultdict(int))
self._condition = threading.Condition()
self._no_remote_peer = 0
def on_rpc_complete(self, request_id: int, peer: str) -> None:
def on_rpc_complete(self, request_id: int, peer: str, method: str) -> None:
"""Records statistics for a single RPC."""
if self._start <= request_id < self._end:
with self._condition:
@ -63,6 +73,7 @@ class _StatsWatcher:
self._no_remote_peer += 1
else:
self._rpcs_by_peer[peer] += 1
self._rpcs_by_method[method][peer] += 1
self._rpcs_needed -= 1
self._condition.notify()
@ -75,6 +86,9 @@ class _StatsWatcher:
response = messages_pb2.LoadBalancerStatsResponse()
for peer, count in self._rpcs_by_peer.items():
response.rpcs_by_peer[peer] = count
for method, count_by_peer in self._rpcs_by_method.items():
for peer, count in count_by_peer.items():
response.rpcs_by_method[method].rpcs_by_peer[peer] = count
response.num_failures = self._no_remote_peer + self._rpcs_needed
return response
@ -116,15 +130,25 @@ class _LoadBalancerStatsServicer(test_pb2_grpc.LoadBalancerStatsServiceServicer
return response
def _start_rpc(request_id: int, stub: test_pb2_grpc.TestServiceStub,
timeout: float, futures: Mapping[int, grpc.Future]) -> None:
logger.info(f"Sending request to backend: {request_id}")
future = stub.UnaryCall.future(messages_pb2.SimpleRequest(),
timeout=timeout)
futures[request_id] = future
def _start_rpc(method: str, metadata: Sequence[Tuple[str, str]],
request_id: int, stub: test_pb2_grpc.TestServiceStub,
timeout: float,
futures: Mapping[int, Tuple[grpc.Future, str]]) -> None:
logger.info(f"Sending {method} request to backend: {request_id}")
if method == "UnaryCall":
future = stub.UnaryCall.future(messages_pb2.SimpleRequest(),
metadata=metadata,
timeout=timeout)
elif method == "EmptyCall":
future = stub.EmptyCall.future(empty_pb2.Empty(),
metadata=metadata,
timeout=timeout)
else:
raise ValueError(f"Unrecognized method '{method}'.")
futures[request_id] = (future, method)
def _on_rpc_done(rpc_id: int, future: grpc.Future,
def _on_rpc_done(rpc_id: int, future: grpc.Future, method: str,
print_response: bool) -> None:
exception = future.exception()
hostname = ""
@ -135,8 +159,13 @@ def _on_rpc_done(rpc_id: int, future: grpc.Future,
logger.error(exception)
else:
response = future.result()
logger.info(f"Got result {rpc_id}")
hostname = response.hostname
hostname = None
for metadatum in future.initial_metadata():
if metadatum[0] == "hostname":
hostname = metadatum[1]
break
else:
hostname = response.hostname
if print_response:
if future.code() == grpc.StatusCode.OK:
logger.info("Successful response.")
@ -144,33 +173,35 @@ def _on_rpc_done(rpc_id: int, future: grpc.Future,
logger.info(f"RPC failed: {call}")
with _global_lock:
for watcher in _watchers:
watcher.on_rpc_complete(rpc_id, hostname)
watcher.on_rpc_complete(rpc_id, hostname, method)
def _remove_completed_rpcs(futures: Mapping[int, grpc.Future],
print_response: bool) -> None:
logger.debug("Removing completed RPCs")
done = []
for future_id, future in futures.items():
for future_id, (future, method) in futures.items():
if future.done():
_on_rpc_done(future_id, future, args.print_response)
_on_rpc_done(future_id, future, method, args.print_response)
done.append(future_id)
for rpc_id in done:
del futures[rpc_id]
def _cancel_all_rpcs(futures: Mapping[int, grpc.Future]) -> None:
def _cancel_all_rpcs(futures: Mapping[int, Tuple[grpc.Future, str]]) -> None:
logger.info("Cancelling all remaining RPCs")
for future in futures.values():
for future, _ in futures.values():
future.cancel()
def _run_single_channel(args: argparse.Namespace):
def _run_single_channel(method: str, metadata: Sequence[Tuple[str, str]],
qps: int, server: str, rpc_timeout_sec: int,
print_response: bool):
global _global_rpc_id # pylint: disable=global-statement
duration_per_query = 1.0 / float(args.qps)
with grpc.insecure_channel(args.server) as channel:
duration_per_query = 1.0 / float(qps)
with grpc.insecure_channel(server) as channel:
stub = test_pb2_grpc.TestServiceStub(channel)
futures: Dict[int, grpc.Future] = {}
futures: Dict[int, Tuple[grpc.Future, str]] = {}
while not _stop_event.is_set():
request_id = None
with _global_lock:
@ -178,8 +209,9 @@ def _run_single_channel(args: argparse.Namespace):
_global_rpc_id += 1
start = time.time()
end = start + duration_per_query
_start_rpc(request_id, stub, float(args.rpc_timeout_sec), futures)
_remove_completed_rpcs(futures, args.print_response)
_start_rpc(method, metadata, request_id, stub,
float(rpc_timeout_sec), futures)
_remove_completed_rpcs(futures, print_response)
logger.debug(f"Currently {len(futures)} in-flight RPCs")
now = time.time()
while now < end:
@ -188,22 +220,75 @@ def _run_single_channel(args: argparse.Namespace):
_cancel_all_rpcs(futures)
def _run(args: argparse.Namespace) -> None:
class _MethodHandle:
"""An object grouping together threads driving RPCs for a method."""
_channel_threads: List[threading.Thread]
def __init__(self, method: str, metadata: Sequence[Tuple[str, str]],
num_channels: int, qps: int, server: str, rpc_timeout_sec: int,
print_response: bool):
"""Creates and starts a group of threads running the indicated method."""
self._channel_threads = []
for i in range(num_channels):
thread = threading.Thread(target=_run_single_channel,
args=(
method,
metadata,
qps,
server,
rpc_timeout_sec,
print_response,
))
thread.start()
self._channel_threads.append(thread)
def stop(self):
"""Joins all threads referenced by the handle."""
for channel_thread in self._channel_threads:
channel_thread.join()
def _run(args: argparse.Namespace, methods: Sequence[str],
per_method_metadata: PerMethodMetadataType) -> None:
logger.info("Starting python xDS Interop Client.")
global _global_server # pylint: disable=global-statement
channel_threads: List[threading.Thread] = []
for i in range(args.num_channels):
thread = threading.Thread(target=_run_single_channel, args=(args,))
thread.start()
channel_threads.append(thread)
method_handles = []
for method in methods:
method_handles.append(
_MethodHandle(method, per_method_metadata.get(method, []),
args.num_channels, args.qps, args.server,
args.rpc_timeout_sec, args.print_response))
_global_server = grpc.server(futures.ThreadPoolExecutor())
_global_server.add_insecure_port(f"0.0.0.0:{args.stats_port}")
test_pb2_grpc.add_LoadBalancerStatsServiceServicer_to_server(
_LoadBalancerStatsServicer(), _global_server)
_global_server.start()
_global_server.wait_for_termination()
for i in range(args.num_channels):
thread.join()
for method_handle in method_handles:
method_handle.stop()
def parse_metadata_arg(metadata_arg: str) -> PerMethodMetadataType:
metadata = metadata_arg.split(",") if args.metadata else []
per_method_metadata = collections.defaultdict(list)
for metadatum in metadata:
elems = metadatum.split(":")
if len(elems) != 3:
raise ValueError(
f"'{metadatum}' was not in the form 'METHOD:KEY:VALUE'")
if elems[0] not in _SUPPORTED_METHODS:
raise ValueError(f"Unrecognized method '{elems[0]}'")
per_method_metadata[elems[0]].append((elems[1], elems[2]))
return per_method_metadata
def parse_rpc_arg(rpc_arg: str) -> Sequence[str]:
methods = rpc_arg.split(",")
if set(methods) - set(_SUPPORTED_METHODS):
raise ValueError("--rpc supported methods: {}".format(
", ".join(_SUPPORTED_METHODS)))
return methods
if __name__ == "__main__":
@ -243,6 +328,15 @@ if __name__ == "__main__":
default=None,
type=str,
help="A file to log to.")
rpc_help = "A comma-delimited list of RPC methods to run. Must be one of "
rpc_help += ", ".join(_SUPPORTED_METHODS)
rpc_help += "."
parser.add_argument("--rpc", default="UnaryCall", type=str, help=rpc_help)
metadata_help = (
"A comma-delimited list of 3-tuples of the form " +
"METHOD:KEY:VALUE, e.g. " +
"EmptyCall:key1:value1,UnaryCall:key2:value2,EmptyCall:k3:v3")
parser.add_argument("--metadata", default="", type=str, help=metadata_help)
args = parser.parse_args()
signal.signal(signal.SIGINT, _handle_sigint)
if args.verbose:
@ -251,4 +345,4 @@ if __name__ == "__main__":
file_handler = logging.FileHandler(args.log_file, mode='a')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
_run(args)
_run(args, parse_rpc_arg(args.rpc), parse_metadata_arg(args.metadata))

@ -50,7 +50,11 @@ grpc_cc_test(
"gtest",
],
tags = [
# Test manipulates system time and requires root while running so it is only
# run on demand ("manual") and when no other tests are running ("exclusive").
# It also means that the test won't work with setups like bazel RBE.
"manual",
"exclusive",
"no_windows",
],
deps = [

@ -670,7 +670,11 @@ grpc_cc_test(
"gtest",
],
tags = [
# Test manipulates network settings (e.g. using iptables) while running so it is only
# run on demand ("manual") and when no other tests are running ("exclusive").
# It also means that the test won't work with setups like bazel RBE.
"manual",
"exclusive",
"no_test_ios",
],
deps = [
@ -750,10 +754,14 @@ grpc_cc_test(
"gtest",
],
tags = [
# Test requires root and manipulates network settings while running so it is only
# run on demand ("manual") and when no other tests are running ("exclusive").
# It also means that the test won't work with setups like bazel RBE.
"manual",
"exclusive",
"no_test_android",
"no_test_ios",
], # test requires root, won't work with bazel RBE
],
deps = [
":test_service_impl",
"//:gpr",

@ -95,3 +95,11 @@ build:python_poller_engine --test_env="GRPC_ASYNCIO_ENGINE=poller"
build:counters --compilation_mode=opt
build:counters --copt=-Wframe-larger-than=16384
build:counters --copt=-DGPR_LOW_LEVEL_COUNTERS
# "mutrace" config is based on a legacy config provided by the Makefile (see definition in build_handwritten.yaml).
# It is only used in microbenchmarks (see tools/run_tests/run_microbenchmark.py)
# TODO(jtattermusch): get rid of the "mutrace" config when possible
build:mutrace --copt=-O3
build:mutrace --copt=-fno-omit-frame-pointer
build:mutrace --copt=-DNDEBUG
build:mutrace --linkopt=-rdynamic

@ -24,4 +24,5 @@ git clone /var/local/jenkins/grpc /var/local/git/grpc
&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
${name}')
cd /var/local/git/grpc
bazel build --spawn_strategy=standalone --genrule_strategy=standalone :all test/... examples/...
bazel build :all //test/... //examples/...

@ -23,5 +23,6 @@ git clone /var/local/jenkins/grpc /var/local/git/grpc
(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
${name}')
cd /var/local/git/grpc/test
bazel test --spawn_strategy=standalone --genrule_strategy=standalone ...
cd /var/local/git/grpc
bazel test //test/...

@ -28,4 +28,4 @@ cd /var/local/git/grpc/test/cpp/end2end
# iptables is used to drop traffic between client and server
apt-get install -y iptables
bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=all --test_timeout=1200 :flaky_network_test --test_env=GRPC_TRACE=http --test_env=GRPC_VERBOSITY=DEBUG
bazel test --test_output=all --test_timeout=1200 :flaky_network_test --test_env=GRPC_TRACE=http --test_env=GRPC_VERBOSITY=DEBUG

@ -25,7 +25,7 @@ git clone /var/local/jenkins/grpc /var/local/git/grpc
${name}')
cd /var/local/git/grpc/test
TEST_TARGETS="//src/python/... //tools/distrib/python/grpcio_tools/... //examples/python/..."
BAZEL_FLAGS="--spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors"
BAZEL_FLAGS="--test_output=errors"
bazel test ${BAZEL_FLAGS} ${TEST_TARGETS}
bazel test --config=python_single_threaded_unary_stream ${BAZEL_FLAGS} ${TEST_TARGETS}
bazel test --config=python_poller_engine ${BAZEL_FLAGS} ${TEST_TARGETS}

@ -48,12 +48,14 @@ touch "$TOOLS_DIR"/src/proto/grpc/testing/__init__.py
bazel build //src/python/grpcio_tests/tests_py3_only/interop:xds_interop_client
# Test cases "path_matching" and "header_matching" are not included in "all",
# because not all interop clients in all languages support these new tests.
GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_routing_lb,cds_lb,eds_lb,priority_lb,weighted_target_lb,lrs_lb "$PYTHON" \
tools/run_tests/run_xds_tests.py \
--test_case=all \
--test_case="all,path_matching,header_matching" \
--project_id=grpc-testing \
--source_image=projects/grpc-testing/global/images/xds-test-server \
--source_image=projects/grpc-testing/global/images/xds-test-server-2 \
--path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
--gcp_suffix=$(date '+%s') \
--verbose \
--client_cmd='bazel run //src/python/grpcio_tests/tests_py3_only/interop:xds_interop_client -- --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} --verbose'
--client_cmd='bazel run //src/python/grpcio_tests/tests_py3_only/interop:xds_interop_client -- --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} --verbose {rpcs_to_send} {metadata_to_send}'

@ -21,14 +21,16 @@ cd $(dirname $0)/../../..
./tools/run_tests/start_port_server.py
# run cfstream_test separately because it messes with the network
tools/bazel test $RUN_TESTS_FLAGS --spawn_strategy=standalone --genrule_strategy=standalone --test_output=all --copt="-DGRPC_CFSTREAM=1" //test/cpp/end2end:cfstream_test
# The "local" execution strategy is required because the test runs sudo and that doesn't work in a sandboxed environment (the default on mac)
tools/bazel test $RUN_TESTS_FLAGS --spawn_strategy=local --genrule_strategy=local --test_output=all --copt="-DGRPC_CFSTREAM=1" //test/cpp/end2end:cfstream_test
# Make sure time is in sync before running time_jump_test because the test does
# NTP sync before exiting. Bazel gets confused if test end time < start time.
sudo sntp -sS pool.ntp.org
# run time_jump_test separately because it changes system time
tools/bazel test $RUN_TESTS_FLAGS --spawn_strategy=standalone --genrule_strategy=standalone --test_output=all //test/cpp/common:time_jump_test
# The "local" execution strategy is required because the test runs sudo and that doesn't work in a sandboxed environment (the default on mac)
tools/bazel test $RUN_TESTS_FLAGS --spawn_strategy=local --genrule_strategy=local --test_output=all //test/cpp/common:time_jump_test
# kill port_server.py to prevent the build from hanging
ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9

@ -74,6 +74,15 @@ def text(txt):
index_html += "<p><pre>%s</pre></p>\n" % cgi.escape(txt)
def _bazel_build_benchmark(bm_name, cfg):
"""Build given benchmark with bazel"""
subprocess.check_call([
'tools/bazel', 'build',
'--config=%s' % cfg,
'//test/cpp/microbenchmarks:%s' % bm_name
])
def collect_latency(bm_name, args):
"""generate latency profiles"""
benchmarks = []
@ -81,16 +90,15 @@ def collect_latency(bm_name, args):
cleanup = []
heading('Latency Profiles: %s' % bm_name)
subprocess.check_call([
'make', bm_name, 'CONFIG=basicprof', '-j',
'%d' % multiprocessing.cpu_count()
])
for line in subprocess.check_output(
['bins/basicprof/%s' % bm_name, '--benchmark_list_tests']).splitlines():
_bazel_build_benchmark(bm_name, 'basicprof')
for line in subprocess.check_output([
'bazel-bin/test/cpp/microbenchmarks/%s' % bm_name,
'--benchmark_list_tests'
]).splitlines():
link(line, '%s.txt' % fnize(line))
benchmarks.append(
jobset.JobSpec([
'bins/basicprof/%s' % bm_name,
'bazel-bin/test/cpp/microbenchmarks/%s' % bm_name,
'--benchmark_filter=^%s$' % line, '--benchmark_min_time=0.05'
],
environ={
@ -133,21 +141,20 @@ def collect_latency(bm_name, args):
def collect_perf(bm_name, args):
"""generate flamegraphs"""
heading('Flamegraphs: %s' % bm_name)
subprocess.check_call([
'make', bm_name, 'CONFIG=mutrace', '-j',
'%d' % multiprocessing.cpu_count()
])
_bazel_build_benchmark(bm_name, 'mutrace')
benchmarks = []
profile_analysis = []
cleanup = []
for line in subprocess.check_output(
['bins/mutrace/%s' % bm_name, '--benchmark_list_tests']).splitlines():
for line in subprocess.check_output([
'bazel-bin/test/cpp/microbenchmarks/%s' % bm_name,
'--benchmark_list_tests'
]).splitlines():
link(line, '%s.svg' % fnize(line))
benchmarks.append(
jobset.JobSpec([
'perf', 'record', '-o',
'%s-perf.data' % fnize(line), '-g', '-F', '997',
'bins/mutrace/%s' % bm_name,
'bazel-bin/test/cpp/microbenchmarks/%s' % bm_name,
'--benchmark_filter=^%s$' % line, '--benchmark_min_time=10'
],
shortname='perf-%s' % fnize(line)))
@ -183,13 +190,9 @@ def collect_perf(bm_name, args):
def run_summary(bm_name, cfg, base_json_name):
subprocess.check_call([
'make', bm_name,
'CONFIG=%s' % cfg, '-j',
'%d' % multiprocessing.cpu_count()
])
_bazel_build_benchmark(bm_name, cfg)
cmd = [
'bins/%s/%s' % (cfg, bm_name),
'bazel-bin/test/cpp/microbenchmarks/%s' % bm_name,
'--benchmark_out=%s.%s.json' % (base_json_name, cfg),
'--benchmark_out_format=json'
]

@ -27,6 +27,7 @@ import subprocess
import sys
import tempfile
import time
import threading
from oauth2client.client import GoogleCredentials
@ -63,6 +64,9 @@ _TEST_CASES = [
# TODO: Move them into _TEST_CASES when support is ready in all languages.
_ADDITIONAL_TEST_CASES = ['path_matching', 'header_matching']
_LOGGING_THREAD_TIMEOUT_SECS = 0.5
_CLIENT_PROCESS_TIMEOUT_SECS = 2.0
def parse_test_cases(arg):
if arg == '':
@ -1799,6 +1803,38 @@ try:
env=client_env,
stderr=subprocess.STDOUT,
stdout=test_log_file)
client_logged = threading.Event()
def _log_client(client_process, client_logged):
# NOTE(rbellevi): Runs on another thread and logs the
# client's output as soon as it terminates. This enables
# authors of client binaries to debug simple failures quickly.
# This thread is responsible for closing the test_log file.
# NOTE(rbellevi): We use Popen.poll and a sleep because
# Popen.wait() is implemented using a busy loop itself. This
# is the best we can do without resorting to
# asyncio.create_subprocess_exec.
while client_process.poll() is None:
time.sleep(_LOGGING_THREAD_TIMEOUT_SECS)
test_log_file.close()
if args.log_client_output:
banner = "#" * 40
logger.info(banner)
logger.info('Client output:')
logger.info(banner)
with open(test_log_filename, 'r') as client_output:
logger.info(client_output.read())
client_logged.set()
logging_thread = threading.Thread(target=_log_client,
args=(
client_process,
client_logged,
),
daemon=True)
logging_thread.start()
if test_case == 'backends_restart':
test_backends_restart(gcp, backend_service, instance_group)
elif test_case == 'change_backend_service':
@ -1856,17 +1892,17 @@ try:
result.state = 'FAILED'
result.message = str(e)
finally:
if client_process and not client_process.returncode:
if client_process and client_process.returncode is None:
client_process.terminate()
test_log_file.close()
# Workaround for Python 3, as report_utils will invoke decode() on
# result.message, which has a default value of ''.
result.message = result.message.encode('UTF-8')
test_results[test_case] = [result]
if args.log_client_output:
logger.info('Client output:')
with open(test_log_filename, 'r') as client_output:
logger.info(client_output.read())
if not client_logged.wait(timeout=_CLIENT_PROCESS_TIMEOUT_SECS):
logger.info(
"Client process failed to terminate. Killing it.")
client_process.kill()
client_logged.wait(timeout=_CLIENT_PROCESS_TIMEOUT_SECS)
if not os.path.exists(_TEST_LOG_BASE_DIR):
os.makedirs(_TEST_LOG_BASE_DIR)
report_utils.render_junit_xml_report(test_results,

Loading…
Cancel
Save