Imported Upstream version 1.31.1 upstream/1.31.1
authorDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 23 Sep 2020 01:42:47 +0000 (10:42 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 23 Sep 2020 01:42:47 +0000 (10:42 +0900)
58 files changed:
BUILD
CMakeLists.txt
Makefile
build_handwritten.yaml
gRPC-C++.podspec
gRPC-Core.podspec
gRPC-ProtoRPC.podspec
gRPC-RxLibrary.podspec
gRPC.podspec
package.xml
src/compiler/ruby_generator_string-inl.h
src/cpp/common/version_cc.cc
src/csharp/Grpc.Core.Api/VersionInfo.cs
src/csharp/Grpc.IntegrationTesting/Messages.cs
src/csharp/Grpc.IntegrationTesting/Test.cs
src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
src/csharp/Grpc.IntegrationTesting/XdsInteropClient.cs
src/csharp/Grpc.IntegrationTesting/XdsInteropClientTest.cs
src/csharp/build/dependencies.props
src/csharp/build_unitypackage.bat
src/objective-c/!ProtoCompiler-gRPCCppPlugin.podspec
src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
src/objective-c/GRPCClient/version.h
src/objective-c/tests/version.h
src/php/composer.json
src/php/ext/grpc/version.h
src/python/grpcio/grpc/_grpcio_metadata.py
src/python/grpcio/grpc_version.py
src/python/grpcio_channelz/grpc_version.py
src/python/grpcio_health_checking/grpc_version.py
src/python/grpcio_reflection/grpc_version.py
src/python/grpcio_status/grpc_version.py
src/python/grpcio_testing/grpc_version.py
src/python/grpcio_tests/grpc_version.py
src/ruby/bin/math_services_pb.rb
src/ruby/end2end/package_with_underscore_checker.rb
src/ruby/lib/grpc/generic/client_stub.rb
src/ruby/lib/grpc/version.rb
src/ruby/pb/grpc/health/v1/health_services_pb.rb
src/ruby/pb/src/proto/grpc/testing/messages_pb.rb
src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
src/ruby/qps/src/proto/grpc/testing/benchmark_service_services_pb.rb
src/ruby/qps/src/proto/grpc/testing/messages_pb.rb
src/ruby/qps/src/proto/grpc/testing/report_qps_scenario_service_services_pb.rb
src/ruby/qps/src/proto/grpc/testing/worker_service_services_pb.rb
src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto [new file with mode: 0644]
src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto [new file with mode: 0644]
src/ruby/spec/pb/codegen/package_option_spec.rb
src/ruby/spec/user_agent_spec.rb [new file with mode: 0644]
src/ruby/tools/version.rb
tools/distrib/python/grpcio_tools/grpc_version.py
tools/doxygen/Doxyfile.c++
tools/doxygen/Doxyfile.c++.internal
tools/doxygen/Doxyfile.objc
tools/doxygen/Doxyfile.objc.internal
tools/doxygen/Doxyfile.php
tools/internal_ci/linux/grpc_xds_csharp_test_in_docker.sh
tools/run_tests/run_xds_tests.py

diff --git a/BUILD b/BUILD
index ecb149a..7b94d4a 100644 (file)
--- a/BUILD
+++ b/BUILD
@@ -79,7 +79,7 @@ g_stands_for = "galore"
 
 core_version = "11.0.0"
 
-version = "1.31.0"
+version = "1.31.1"
 
 GPR_PUBLIC_HDRS = [
     "include/grpc/support/alloc.h",
index 33f76f0..a067308 100644 (file)
 cmake_minimum_required(VERSION 3.5.1)
 
 set(PACKAGE_NAME          "grpc")
-set(PACKAGE_VERSION       "1.31.0")
+set(PACKAGE_VERSION       "1.31.1")
 set(gRPC_CORE_VERSION     "11.0.0")
 set(gRPC_CORE_SOVERSION   "11")
-set(gRPC_CPP_VERSION      "1.31.0")
+set(gRPC_CPP_VERSION      "1.31.1")
 set(gRPC_CPP_SOVERSION    "1")
-set(gRPC_CSHARP_VERSION   "2.31.0")
+set(gRPC_CSHARP_VERSION   "2.31.1")
 set(gRPC_CSHARP_SOVERSION "2")
 set(PACKAGE_STRING        "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 set(PACKAGE_TARNAME       "${PACKAGE_NAME}-${PACKAGE_VERSION}")
index ad36296..fdb1b84 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -450,8 +450,8 @@ Q = @
 endif
 
 CORE_VERSION = 11.0.0
-CPP_VERSION = 1.31.0
-CSHARP_VERSION = 2.31.0
+CPP_VERSION = 1.31.1
+CSHARP_VERSION = 2.31.1
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
index 006ba4c..45b3a4d 100644 (file)
@@ -15,7 +15,7 @@ settings:
   core_version: 11.0.0
   csharp_major_version: 2
   g_stands_for: galore
-  version: 1.31.0
+  version: 1.31.1
 targets:
 - name: check_epollexclusive
   build: tool
index 16175ac..7b12421 100644 (file)
@@ -22,7 +22,7 @@
 Pod::Spec.new do |s|
   s.name     = 'gRPC-C++'
   # TODO (mxyan): use version that match gRPC version when pod is stabilized
-  version = '1.31.0'
+  version = '1.31.1'
   s.version  = version
   s.summary  = 'gRPC C++ library'
   s.homepage = 'https://grpc.io'
index 545381b..0ab44ba 100644 (file)
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
-  version = '1.31.0'
+  version = '1.31.1'
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'https://grpc.io'
index 9065aa7..14d51e6 100644 (file)
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.31.0'
+  version = '1.31.1'
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'https://grpc.io'
index fdcd508..0879c39 100644 (file)
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
-  version = '1.31.0'
+  version = '1.31.1'
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'https://grpc.io'
index 74e6506..1dc678b 100644 (file)
@@ -20,7 +20,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  version = '1.31.0'
+  version = '1.31.1'
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'https://grpc.io'
index 2ca7237..96f0640 100644 (file)
@@ -13,8 +13,8 @@
  <date>2019-09-24</date>
  <time>16:06:07</time>
  <version>
-  <release>1.31.0</release>
-  <api>1.31.0</api>
+  <release>1.31.1</release>
+  <api>1.31.1</api>
  </version>
  <stability>
   <release>stable</release>
@@ -22,7 +22,7 @@
  </stability>
  <license>Apache 2.0</license>
  <notes>
-- gRPC Core 1.31.0 update
+- gRPC Core 1.31.1 update
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
index b3e1938..968f795 100644 (file)
@@ -124,7 +124,7 @@ inline std::string RubyTypeOf(const grpc::protobuf::Descriptor* descriptor) {
     ReplacePrefix(&proto_type, ".", "");  // remove the leading . (no package)
     proto_type = RubyPackage(descriptor->file()) + "." + proto_type;
   }
-  std::string res(proto_type);
+  std::string res("." + proto_type);
   if (res.find('.') == std::string::npos) {
     return res;
   } else {
index 2106a7e..af24028 100644 (file)
@@ -22,5 +22,5 @@
 #include <grpcpp/grpcpp.h>
 
 namespace grpc {
-std::string Version() { return "1.31.0"; }
+std::string Version() { return "1.31.1"; }
 }  // namespace grpc
index 7a09417..30a6f07 100644 (file)
@@ -33,11 +33,11 @@ namespace Grpc.Core
         /// <summary>
         /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
         /// </summary>
-        public const string CurrentAssemblyFileVersion = "2.31.0.0";
+        public const string CurrentAssemblyFileVersion = "2.31.1.0";
 
         /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "2.31.0";
+        public const string CurrentVersion = "2.31.1";
     }
 }
index 6911a44..a1f3534 100644 (file)
@@ -58,14 +58,22 @@ namespace Grpc.Testing {
             "eF9yZWNvbm5lY3RfYmFja29mZl9tcxgBIAEoBSIzCg1SZWNvbm5lY3RJbmZv",
             "Eg4KBnBhc3NlZBgBIAEoCBISCgpiYWNrb2ZmX21zGAIgAygFIkEKGExvYWRC",
             "YWxhbmNlclN0YXRzUmVxdWVzdBIQCghudW1fcnBjcxgBIAEoBRITCgt0aW1l",
-            "b3V0X3NlYxgCIAEoBSKzAQoZTG9hZEJhbGFuY2VyU3RhdHNSZXNwb25zZRJN",
+            "b3V0X3NlYxgCIAEoBSKLBAoZTG9hZEJhbGFuY2VyU3RhdHNSZXNwb25zZRJN",
             "CgxycGNzX2J5X3BlZXIYASADKAsyNy5ncnBjLnRlc3RpbmcuTG9hZEJhbGFu",
             "Y2VyU3RhdHNSZXNwb25zZS5ScGNzQnlQZWVyRW50cnkSFAoMbnVtX2ZhaWx1",
-            "cmVzGAIgASgFGjEKD1JwY3NCeVBlZXJFbnRyeRILCgNrZXkYASABKAkSDQoF",
-            "dmFsdWUYAiABKAU6AjgBKh8KC1BheWxvYWRUeXBlEhAKDENPTVBSRVNTQUJM",
-            "RRAAKm8KD0dycGNsYlJvdXRlVHlwZRIdChlHUlBDTEJfUk9VVEVfVFlQRV9V",
-            "TktOT1dOEAASHgoaR1JQQ0xCX1JPVVRFX1RZUEVfRkFMTEJBQ0sQARIdChlH",
-            "UlBDTEJfUk9VVEVfVFlQRV9CQUNLRU5EEAJiBnByb3RvMw=="));
+            "cmVzGAIgASgFElEKDnJwY3NfYnlfbWV0aG9kGAMgAygLMjkuZ3JwYy50ZXN0",
+            "aW5nLkxvYWRCYWxhbmNlclN0YXRzUmVzcG9uc2UuUnBjc0J5TWV0aG9kRW50",
+            "cnkamQEKClJwY3NCeVBlZXISWAoMcnBjc19ieV9wZWVyGAEgAygLMkIuZ3Jw",
+            "Yy50ZXN0aW5nLkxvYWRCYWxhbmNlclN0YXRzUmVzcG9uc2UuUnBjc0J5UGVl",
+            "ci5ScGNzQnlQZWVyRW50cnkaMQoPUnBjc0J5UGVlckVudHJ5EgsKA2tleRgB",
+            "IAEoCRINCgV2YWx1ZRgCIAEoBToCOAEaMQoPUnBjc0J5UGVlckVudHJ5EgsK",
+            "A2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoBToCOAEaZwoRUnBjc0J5TWV0aG9k",
+            "RW50cnkSCwoDa2V5GAEgASgJEkEKBXZhbHVlGAIgASgLMjIuZ3JwYy50ZXN0",
+            "aW5nLkxvYWRCYWxhbmNlclN0YXRzUmVzcG9uc2UuUnBjc0J5UGVlcjoCOAEq",
+            "HwoLUGF5bG9hZFR5cGUSEAoMQ09NUFJFU1NBQkxFEAAqbwoPR3JwY2xiUm91",
+            "dGVUeXBlEh0KGUdSUENMQl9ST1VURV9UWVBFX1VOS05PV04QABIeChpHUlBD",
+            "TEJfUk9VVEVfVFlQRV9GQUxMQkFDSxABEh0KGUdSUENMQl9ST1VURV9UWVBF",
+            "X0JBQ0tFTkQQAmIGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), typeof(global::Grpc.Testing.GrpclbRouteType), }, null, new pbr::GeneratedClrTypeInfo[] {
@@ -82,7 +90,8 @@ namespace Grpc.Testing {
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ReconnectParams), global::Grpc.Testing.ReconnectParams.Parser, new[]{ "MaxReconnectBackoffMs" }, null, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ReconnectInfo), global::Grpc.Testing.ReconnectInfo.Parser, new[]{ "Passed", "BackoffMs" }, null, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.LoadBalancerStatsRequest), global::Grpc.Testing.LoadBalancerStatsRequest.Parser, new[]{ "NumRpcs", "TimeoutSec" }, null, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.LoadBalancerStatsResponse), global::Grpc.Testing.LoadBalancerStatsResponse.Parser, new[]{ "RpcsByPeer", "NumFailures" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { null, })
+            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.LoadBalancerStatsResponse), global::Grpc.Testing.LoadBalancerStatsResponse.Parser, new[]{ "RpcsByPeer", "NumFailures", "RpcsByMethod" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.LoadBalancerStatsResponse.Types.RpcsByPeer), global::Grpc.Testing.LoadBalancerStatsResponse.Types.RpcsByPeer.Parser, new[]{ "RpcsByPeer_" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { null, }),
+            null, null, })
           }));
     }
     #endregion
@@ -2706,6 +2715,7 @@ namespace Grpc.Testing {
     public LoadBalancerStatsResponse(LoadBalancerStatsResponse other) : this() {
       rpcsByPeer_ = other.rpcsByPeer_.Clone();
       numFailures_ = other.numFailures_;
+      rpcsByMethod_ = other.rpcsByMethod_.Clone();
       _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
     }
 
@@ -2741,6 +2751,16 @@ namespace Grpc.Testing {
       }
     }
 
+    /// <summary>Field number for the "rpcs_by_method" field.</summary>
+    public const int RpcsByMethodFieldNumber = 3;
+    private static readonly pbc::MapField<string, global::Grpc.Testing.LoadBalancerStatsResponse.Types.RpcsByPeer>.Codec _map_rpcsByMethod_codec
+        = new pbc::MapField<string, global::Grpc.Testing.LoadBalancerStatsResponse.Types.RpcsByPeer>.Codec(pb::FieldCodec.ForString(10, ""), pb::FieldCodec.ForMessage(18, global::Grpc.Testing.LoadBalancerStatsResponse.Types.RpcsByPeer.Parser), 26);
+    private readonly pbc::MapField<string, global::Grpc.Testing.LoadBalancerStatsResponse.Types.RpcsByPeer> rpcsByMethod_ = new pbc::MapField<string, global::Grpc.Testing.LoadBalancerStatsResponse.Types.RpcsByPeer>();
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public pbc::MapField<string, global::Grpc.Testing.LoadBalancerStatsResponse.Types.RpcsByPeer> RpcsByMethod {
+      get { return rpcsByMethod_; }
+    }
+
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     public override bool Equals(object other) {
       return Equals(other as LoadBalancerStatsResponse);
@@ -2756,6 +2776,7 @@ namespace Grpc.Testing {
       }
       if (!RpcsByPeer.Equals(other.RpcsByPeer)) return false;
       if (NumFailures != other.NumFailures) return false;
+      if (!RpcsByMethod.Equals(other.RpcsByMethod)) return false;
       return Equals(_unknownFields, other._unknownFields);
     }
 
@@ -2764,6 +2785,7 @@ namespace Grpc.Testing {
       int hash = 1;
       hash ^= RpcsByPeer.GetHashCode();
       if (NumFailures != 0) hash ^= NumFailures.GetHashCode();
+      hash ^= RpcsByMethod.GetHashCode();
       if (_unknownFields != null) {
         hash ^= _unknownFields.GetHashCode();
       }
@@ -2782,6 +2804,7 @@ namespace Grpc.Testing {
         output.WriteRawTag(16);
         output.WriteInt32(NumFailures);
       }
+      rpcsByMethod_.WriteTo(output, _map_rpcsByMethod_codec);
       if (_unknownFields != null) {
         _unknownFields.WriteTo(output);
       }
@@ -2794,6 +2817,7 @@ namespace Grpc.Testing {
       if (NumFailures != 0) {
         size += 1 + pb::CodedOutputStream.ComputeInt32Size(NumFailures);
       }
+      size += rpcsByMethod_.CalculateSize(_map_rpcsByMethod_codec);
       if (_unknownFields != null) {
         size += _unknownFields.CalculateSize();
       }
@@ -2809,6 +2833,7 @@ namespace Grpc.Testing {
       if (other.NumFailures != 0) {
         NumFailures = other.NumFailures;
       }
+      rpcsByMethod_.Add(other.rpcsByMethod_);
       _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
     }
 
@@ -2828,9 +2853,144 @@ namespace Grpc.Testing {
             NumFailures = input.ReadInt32();
             break;
           }
+          case 26: {
+            rpcsByMethod_.AddEntriesFrom(input, _map_rpcsByMethod_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the LoadBalancerStatsResponse message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static partial class Types {
+      public sealed partial class RpcsByPeer : pb::IMessage<RpcsByPeer> {
+        private static readonly pb::MessageParser<RpcsByPeer> _parser = new pb::MessageParser<RpcsByPeer>(() => new RpcsByPeer());
+        private pb::UnknownFieldSet _unknownFields;
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public static pb::MessageParser<RpcsByPeer> Parser { get { return _parser; } }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Grpc.Testing.LoadBalancerStatsResponse.Descriptor.NestedTypes[0]; }
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public RpcsByPeer() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public RpcsByPeer(RpcsByPeer other) : this() {
+          rpcsByPeer_ = other.rpcsByPeer_.Clone();
+          _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public RpcsByPeer Clone() {
+          return new RpcsByPeer(this);
+        }
+
+        /// <summary>Field number for the "rpcs_by_peer" field.</summary>
+        public const int RpcsByPeer_FieldNumber = 1;
+        private static readonly pbc::MapField<string, int>.Codec _map_rpcsByPeer_codec
+            = new pbc::MapField<string, int>.Codec(pb::FieldCodec.ForString(10, ""), pb::FieldCodec.ForInt32(16, 0), 10);
+        private readonly pbc::MapField<string, int> rpcsByPeer_ = new pbc::MapField<string, int>();
+        /// <summary>
+        /// The number of completed RPCs for each peer.
+        /// </summary>
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public pbc::MapField<string, int> RpcsByPeer_ {
+          get { return rpcsByPeer_; }
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public override bool Equals(object other) {
+          return Equals(other as RpcsByPeer);
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public bool Equals(RpcsByPeer other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (!RpcsByPeer_.Equals(other.RpcsByPeer_)) return false;
+          return Equals(_unknownFields, other._unknownFields);
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public override int GetHashCode() {
+          int hash = 1;
+          hash ^= RpcsByPeer_.GetHashCode();
+          if (_unknownFields != null) {
+            hash ^= _unknownFields.GetHashCode();
+          }
+          return hash;
         }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public void WriteTo(pb::CodedOutputStream output) {
+          rpcsByPeer_.WriteTo(output, _map_rpcsByPeer_codec);
+          if (_unknownFields != null) {
+            _unknownFields.WriteTo(output);
+          }
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public int CalculateSize() {
+          int size = 0;
+          size += rpcsByPeer_.CalculateSize(_map_rpcsByPeer_codec);
+          if (_unknownFields != null) {
+            size += _unknownFields.CalculateSize();
+          }
+          return size;
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public void MergeFrom(RpcsByPeer other) {
+          if (other == null) {
+            return;
+          }
+          rpcsByPeer_.Add(other.rpcsByPeer_);
+          _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+                break;
+              case 10: {
+                rpcsByPeer_.AddEntriesFrom(input, _map_rpcsByPeer_codec);
+                break;
+              }
+            }
+          }
+        }
+
       }
+
     }
+    #endregion
 
   }
 
index 992908f..8967af6 100644 (file)
@@ -50,7 +50,10 @@ namespace Grpc.Testing {
             "RW1wdHkaGy5ncnBjLnRlc3RpbmcuUmVjb25uZWN0SW5mbzJ/ChhMb2FkQmFs",
             "YW5jZXJTdGF0c1NlcnZpY2USYwoOR2V0Q2xpZW50U3RhdHMSJi5ncnBjLnRl",
             "c3RpbmcuTG9hZEJhbGFuY2VyU3RhdHNSZXF1ZXN0GicuZ3JwYy50ZXN0aW5n",
-            "LkxvYWRCYWxhbmNlclN0YXRzUmVzcG9uc2UiAGIGcHJvdG8z"));
+            "LkxvYWRCYWxhbmNlclN0YXRzUmVzcG9uc2UiADKLAQoWWGRzVXBkYXRlSGVh",
+            "bHRoU2VydmljZRI2CgpTZXRTZXJ2aW5nEhMuZ3JwYy50ZXN0aW5nLkVtcHR5",
+            "GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EjkKDVNldE5vdFNlcnZpbmcSEy5ncnBj",
+            "LnRlc3RpbmcuRW1wdHkaEy5ncnBjLnRlc3RpbmcuRW1wdHliBnByb3RvMw=="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Grpc.Testing.EmptyReflection.Descriptor, global::Grpc.Testing.MessagesReflection.Descriptor, },
           new pbr::GeneratedClrTypeInfo(null, null, null));
index 5f63fd9..ffa8388 100644 (file)
@@ -950,5 +950,132 @@ namespace Grpc.Testing {
     }
 
   }
+  /// <summary>
+  /// A service to remotely control health status of an xDS test server.
+  /// </summary>
+  public static partial class XdsUpdateHealthService
+  {
+    static readonly string __ServiceName = "grpc.testing.XdsUpdateHealthService";
+
+    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_grpc_testing_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+
+    static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_SetServing = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
+        grpc::MethodType.Unary,
+        __ServiceName,
+        "SetServing",
+        __Marshaller_grpc_testing_Empty,
+        __Marshaller_grpc_testing_Empty);
+
+    static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_SetNotServing = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
+        grpc::MethodType.Unary,
+        __ServiceName,
+        "SetNotServing",
+        __Marshaller_grpc_testing_Empty,
+        __Marshaller_grpc_testing_Empty);
+
+    /// <summary>Service descriptor</summary>
+    public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+    {
+      get { return global::Grpc.Testing.TestReflection.Descriptor.Services[4]; }
+    }
+
+    /// <summary>Base class for server-side implementations of XdsUpdateHealthService</summary>
+    [grpc::BindServiceMethod(typeof(XdsUpdateHealthService), "BindService")]
+    public abstract partial class XdsUpdateHealthServiceBase
+    {
+      public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> SetServing(global::Grpc.Testing.Empty request, grpc::ServerCallContext context)
+      {
+        throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+      }
+
+      public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> SetNotServing(global::Grpc.Testing.Empty request, grpc::ServerCallContext context)
+      {
+        throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+      }
+
+    }
+
+    /// <summary>Client for XdsUpdateHealthService</summary>
+    public partial class XdsUpdateHealthServiceClient : grpc::ClientBase<XdsUpdateHealthServiceClient>
+    {
+      /// <summary>Creates a new client for XdsUpdateHealthService</summary>
+      /// <param name="channel">The channel to use to make remote calls.</param>
+      public XdsUpdateHealthServiceClient(grpc::ChannelBase channel) : base(channel)
+      {
+      }
+      /// <summary>Creates a new client for XdsUpdateHealthService that uses a custom <c>CallInvoker</c>.</summary>
+      /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
+      public XdsUpdateHealthServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker)
+      {
+      }
+      /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+      protected XdsUpdateHealthServiceClient() : base()
+      {
+      }
+      /// <summary>Protected constructor to allow creation of configured clients.</summary>
+      /// <param name="configuration">The client configuration.</param>
+      protected XdsUpdateHealthServiceClient(ClientBaseConfiguration configuration) : base(configuration)
+      {
+      }
+
+      public virtual global::Grpc.Testing.Empty SetServing(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return SetServing(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      public virtual global::Grpc.Testing.Empty SetServing(global::Grpc.Testing.Empty request, grpc::CallOptions options)
+      {
+        return CallInvoker.BlockingUnaryCall(__Method_SetServing, null, options, request);
+      }
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> SetServingAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return SetServingAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> SetServingAsync(global::Grpc.Testing.Empty request, grpc::CallOptions options)
+      {
+        return CallInvoker.AsyncUnaryCall(__Method_SetServing, null, options, request);
+      }
+      public virtual global::Grpc.Testing.Empty SetNotServing(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return SetNotServing(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      public virtual global::Grpc.Testing.Empty SetNotServing(global::Grpc.Testing.Empty request, grpc::CallOptions options)
+      {
+        return CallInvoker.BlockingUnaryCall(__Method_SetNotServing, null, options, request);
+      }
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> SetNotServingAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return SetNotServingAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> SetNotServingAsync(global::Grpc.Testing.Empty request, grpc::CallOptions options)
+      {
+        return CallInvoker.AsyncUnaryCall(__Method_SetNotServing, null, options, request);
+      }
+      /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
+      protected override XdsUpdateHealthServiceClient NewInstance(ClientBaseConfiguration configuration)
+      {
+        return new XdsUpdateHealthServiceClient(configuration);
+      }
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+    public static grpc::ServerServiceDefinition BindService(XdsUpdateHealthServiceBase serviceImpl)
+    {
+      return grpc::ServerServiceDefinition.CreateBuilder()
+          .AddMethod(__Method_SetServing, serviceImpl.SetServing)
+          .AddMethod(__Method_SetNotServing, serviceImpl.SetNotServing).Build();
+    }
+
+    /// <summary>Register service method with a service binder with or without implementation. Useful when customizing the  service binding logic.
+    /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+    /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+    public static void BindService(grpc::ServiceBinderBase serviceBinder, XdsUpdateHealthServiceBase serviceImpl)
+    {
+      serviceBinder.AddMethod(__Method_SetServing, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(serviceImpl.SetServing));
+      serviceBinder.AddMethod(__Method_SetNotServing, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(serviceImpl.SetNotServing));
+    }
+
+  }
 }
 #endregion
index b9d7799..0ad6c4b 100644 (file)
@@ -39,7 +39,7 @@ namespace Grpc.IntegrationTesting
 
             [Option("qps", Default = 1)]
 
-            // The desired QPS per channel.
+            // The desired QPS per channel, for each type of RPC.
             public int Qps { get; set; }
 
             [Option("server", Default = "localhost:8080")]
@@ -53,18 +53,37 @@ namespace Grpc.IntegrationTesting
 
             [Option("print_response", Default = false)]
             public bool PrintResponse { get; set; }
+
+            // Types of RPCs to make, ',' separated string. RPCs can be EmptyCall or UnaryCall
+            [Option("rpc", Default = "UnaryCall")]
+            public string Rpc { get; set; }
+
+            // The metadata to send with each RPC, in the format EmptyCall:key1:value1,UnaryCall:key2:value2
+            [Option("metadata", Default = null)]
+            public string Metadata { get; set; }
+        }
+
+        internal enum RpcType
+        {
+            UnaryCall,
+            EmptyCall
         }
 
         ClientOptions options;
 
         StatsWatcher statsWatcher = new StatsWatcher();
 
+        List<RpcType> rpcs;
+        Dictionary<RpcType, Metadata> metadata;
+
         // make watcher accessible by tests
         internal StatsWatcher StatsWatcher => statsWatcher;
 
         internal XdsInteropClient(ClientOptions options)
         {
             this.options = options;
+            this.rpcs = ParseRpcArgument(this.options.Rpc);
+            this.metadata = ParseMetadataArgument(this.options.Metadata);
         }
 
         public static void Run(string[] args)
@@ -124,8 +143,11 @@ namespace Grpc.IntegrationTesting
             var stopwatch = Stopwatch.StartNew();
             while (!cancellationToken.IsCancellationRequested)
             {
-                inflightTasks.Add(RunSingleRpcAsync(client, cancellationToken));
-                rpcsStarted++;
+                foreach (var rpcType in rpcs)
+                {
+                    inflightTasks.Add(RunSingleRpcAsync(client, cancellationToken, rpcType));
+                    rpcsStarted++;
+                }
 
                 // only cleanup calls that have already completed, calls that are still inflight will be cleaned up later.
                 await CleanupCompletedTasksAsync(inflightTasks);
@@ -133,7 +155,7 @@ namespace Grpc.IntegrationTesting
                 Console.WriteLine($"Currently {inflightTasks.Count} in-flight RPCs");
 
                 // if needed, wait a bit before we start the next RPC.
-                int nextDueInMillis = (int) Math.Max(0, (1000 * rpcsStarted / options.Qps) - stopwatch.ElapsedMilliseconds);
+                int nextDueInMillis = (int) Math.Max(0, (1000 * rpcsStarted / options.Qps / rpcs.Count) - stopwatch.ElapsedMilliseconds);
                 if (nextDueInMillis > 0)
                 {
                     await Task.Delay(nextDueInMillis);
@@ -146,25 +168,61 @@ namespace Grpc.IntegrationTesting
             Console.WriteLine($"Channel shutdown {channelId}");
         }
 
-        private async Task RunSingleRpcAsync(TestService.TestServiceClient client, CancellationToken cancellationToken)
+        private async Task RunSingleRpcAsync(TestService.TestServiceClient client, CancellationToken cancellationToken, RpcType rpcType)
         {
             long rpcId = statsWatcher.RpcIdGenerator.Increment();
             try
             {
-                Console.WriteLine($"Starting RPC {rpcId}.");
-                var response = await client.UnaryCallAsync(new SimpleRequest(),
-                    new CallOptions(cancellationToken: cancellationToken, deadline: DateTime.UtcNow.AddSeconds(options.RpcTimeoutSec)));
-                
-                statsWatcher.OnRpcComplete(rpcId, response.Hostname);
-                if (options.PrintResponse)
+                Console.WriteLine($"Starting RPC {rpcId} of type {rpcType}");
+
+                // metadata to send with the RPC
+                var headers = new Metadata();
+                if (metadata.ContainsKey(rpcType))
                 {
-                    Console.WriteLine($"Got response {response}");
+                    headers = metadata[rpcType];
+                    if (headers.Count > 0)
+                    {
+                        var printableHeaders = "[" + string.Join(", ", headers) + "]";
+                        Console.WriteLine($"Will send metadata {printableHeaders}");
+                    }
                 }
-                Console.WriteLine($"RPC {rpcId} succeeded ");
+
+                if (rpcType == RpcType.UnaryCall)
+                {
+
+                    var call = client.UnaryCallAsync(new SimpleRequest(),
+                        new CallOptions(headers: headers, cancellationToken: cancellationToken, deadline: DateTime.UtcNow.AddSeconds(options.RpcTimeoutSec)));
+
+                    var response = await call;
+                    var hostname = (await call.ResponseHeadersAsync).GetValue("hostname") ?? response.Hostname;
+                    statsWatcher.OnRpcComplete(rpcId, rpcType, hostname);
+                    if (options.PrintResponse)
+                    {
+                        Console.WriteLine($"Got response {response}");
+                    }
+                }
+                else if (rpcType == RpcType.EmptyCall)
+                {
+                    var call = client.EmptyCallAsync(new Empty(),
+                        new CallOptions(headers: headers, cancellationToken: cancellationToken, deadline: DateTime.UtcNow.AddSeconds(options.RpcTimeoutSec)));
+
+                    var response = await call;
+                    var hostname = (await call.ResponseHeadersAsync).GetValue("hostname");
+                    statsWatcher.OnRpcComplete(rpcId, rpcType, hostname);
+                    if (options.PrintResponse)
+                    {
+                        Console.WriteLine($"Got response {response}");
+                    }
+                }
+                else
+                {
+                    throw new InvalidOperationException($"Unsupported RPC type ${rpcType}");
+                }
+                Console.WriteLine($"RPC {rpcId} succeeded");
             }
             catch (RpcException ex)
             {
-                statsWatcher.OnRpcComplete(rpcId, null);
+                statsWatcher.OnRpcComplete(rpcId, rpcType, null);
                 Console.WriteLine($"RPC {rpcId} failed: {ex}");
             }
         }
@@ -186,6 +244,66 @@ namespace Grpc.IntegrationTesting
                 tasks.Remove(task);
             }
         }
+
+        private static List<RpcType> ParseRpcArgument(string rpcArg)
+        {
+            var result = new List<RpcType>();
+            foreach (var part in rpcArg.Split(','))
+            {
+                result.Add(ParseRpc(part));
+            }
+            return result;
+        }
+
+        private static RpcType ParseRpc(string rpc)
+        {
+            switch (rpc)
+            {
+                case "UnaryCall":
+                    return RpcType.UnaryCall;
+                case "EmptyCall":
+                    return RpcType.EmptyCall;
+                default:
+                    throw new ArgumentException($"Unknown RPC: \"{rpc}\"");
+            }
+        }
+
+        private static Dictionary<RpcType, Metadata> ParseMetadataArgument(string metadataArg)
+        {
+            var rpcMetadata = new Dictionary<RpcType, Metadata>();
+            if (string.IsNullOrEmpty(metadataArg))
+            {
+                return rpcMetadata;
+            }
+
+            foreach (var metadata in metadataArg.Split(','))
+            {
+                var parts = metadata.Split(':');
+                if (parts.Length != 3)
+                {
+                    throw new ArgumentException($"Invalid metadata: \"{metadata}\"");
+                }
+                var rpc = ParseRpc(parts[0]);
+                var key = parts[1];
+                var value = parts[2];
+
+                var md = new Metadata { {key, value} };
+
+                if (rpcMetadata.ContainsKey(rpc))
+                {
+                    var existingMetadata = rpcMetadata[rpc];
+                    foreach (var entry in md)
+                    {
+                        existingMetadata.Add(entry);
+                    }
+                }
+                else
+                {
+                    rpcMetadata.Add(rpc, md);
+                }
+            }
+            return rpcMetadata;
+        }
     }
 
     internal class StatsWatcher
@@ -198,6 +316,7 @@ namespace Grpc.IntegrationTesting
         private int rpcsCompleted;
         private int rpcsNoHostname;
         private Dictionary<string, int> rpcsByHostname;
+        private Dictionary<string, Dictionary<string, int>> rpcsByMethod;
 
         public AtomicCounter RpcIdGenerator => rpcIdGenerator;
 
@@ -206,7 +325,7 @@ namespace Grpc.IntegrationTesting
             Reset();
         }
 
-        public void OnRpcComplete(long rpcId, string responseHostname)
+        public void OnRpcComplete(long rpcId, XdsInteropClient.RpcType rpcType, string responseHostname)
         {
             lock (myLock)
             {
@@ -221,11 +340,24 @@ namespace Grpc.IntegrationTesting
                 }
                 else 
                 {
+                    // update rpcsByHostname
                     if (!rpcsByHostname.ContainsKey(responseHostname))
                     {
                         rpcsByHostname[responseHostname] = 0;
                     }
                     rpcsByHostname[responseHostname] += 1;
+
+                    // update rpcsByMethod
+                    var method = rpcType.ToString();
+                    if (!rpcsByMethod.ContainsKey(method))
+                    {
+                        rpcsByMethod[method] = new Dictionary<string, int>();
+                    }
+                    if (!rpcsByMethod[method].ContainsKey(responseHostname))
+                    {
+                        rpcsByMethod[method][responseHostname] = 0;
+                    }
+                    rpcsByMethod[method][responseHostname] += 1;
                 }
                 rpcsCompleted += 1;
 
@@ -245,6 +377,7 @@ namespace Grpc.IntegrationTesting
                 rpcsCompleted = 0;
                 rpcsNoHostname = 0;
                 rpcsByHostname = new Dictionary<string, int>();
+                rpcsByMethod = new Dictionary<string, Dictionary<string, int>>();
             }
         }
 
@@ -269,6 +402,14 @@ namespace Grpc.IntegrationTesting
                         // we collected enough RPCs, or timed out waiting
                         var response = new LoadBalancerStatsResponse { NumFailures = rpcsNoHostname };
                         response.RpcsByPeer.Add(rpcsByHostname);
+                        
+                        response.RpcsByMethod.Clear();
+                        foreach (var methodEntry in rpcsByMethod)
+                        {
+                            var rpcsByPeer = new LoadBalancerStatsResponse.Types.RpcsByPeer();
+                            rpcsByPeer.RpcsByPeer_.Add(methodEntry.Value);
+                            response.RpcsByMethod[methodEntry.Key] = rpcsByPeer;
+                        }
                         Reset();
                         return response;
                     }
index be4e696..4025d80 100644 (file)
@@ -59,6 +59,7 @@ namespace Grpc.IntegrationTesting
                 NumChannels = 1,
                 Qps = 1,
                 RpcTimeoutSec = 10,
+                Rpc = "UnaryCall",
                 Server = $"{Host}:{backendServer.Ports.Single().BoundPort}",
             });
 
@@ -89,7 +90,7 @@ namespace Grpc.IntegrationTesting
             string backendName = "backend1";
             backendService.UnaryHandler = (request, context) =>
             {
-                return Task.FromResult(new SimpleResponse { Hostname = backendName});
+                return Task.FromResult(new SimpleResponse { Hostname = backendName });
             };
 
             var cancellationTokenSource = new CancellationTokenSource();
@@ -104,6 +105,9 @@ namespace Grpc.IntegrationTesting
             Assert.AreEqual(0, stats.NumFailures);
             Assert.AreEqual(backendName, stats.RpcsByPeer.Keys.Single());
             Assert.AreEqual(5, stats.RpcsByPeer[backendName]);
+            Assert.AreEqual("UnaryCall", stats.RpcsByMethod.Keys.Single());
+            Assert.AreEqual(backendName, stats.RpcsByMethod["UnaryCall"].RpcsByPeer_.Keys.Single());
+            Assert.AreEqual(5, stats.RpcsByMethod["UnaryCall"].RpcsByPeer_[backendName]);
 
             await Task.Delay(100);
 
@@ -116,6 +120,36 @@ namespace Grpc.IntegrationTesting
             Assert.AreEqual(0, stats2.NumFailures);
             Assert.AreEqual(backendName, stats2.RpcsByPeer.Keys.Single());
             Assert.AreEqual(3, stats2.RpcsByPeer[backendName]);
+            Assert.AreEqual("UnaryCall", stats2.RpcsByMethod.Keys.Single());
+            Assert.AreEqual(backendName, stats2.RpcsByMethod["UnaryCall"].RpcsByPeer_.Keys.Single());
+            Assert.AreEqual(3, stats2.RpcsByMethod["UnaryCall"].RpcsByPeer_[backendName]);
+            
+            cancellationTokenSource.Cancel();
+            await runChannelsTask;
+        }
+
+        [Test]
+        public async Task HostnameReadFromResponseHeaders()
+        {
+            string correctBackendName = "backend1";
+            backendService.UnaryHandler = async (request, context) =>
+            {
+                await context.WriteResponseHeadersAsync(new Metadata { {"hostname", correctBackendName} });
+                return new SimpleResponse { Hostname = "wrong_hostname" };
+            };
+
+            var cancellationTokenSource = new CancellationTokenSource();
+            var runChannelsTask = xdsInteropClient.RunChannelsAsync(cancellationTokenSource.Token);
+
+            var stats = await lbStatsClient.GetClientStatsAsync(new LoadBalancerStatsRequest
+            {
+                NumRpcs = 3,
+                TimeoutSec = 10,
+            }, deadline: DateTime.UtcNow.AddSeconds(30));
+
+            Assert.AreEqual(0, stats.NumFailures);
+            Assert.AreEqual(correctBackendName, stats.RpcsByPeer.Keys.Single());
+            Assert.AreEqual(3, stats.RpcsByPeer[correctBackendName]);
             
             cancellationTokenSource.Cancel();
             await runChannelsTask;
@@ -124,11 +158,17 @@ namespace Grpc.IntegrationTesting
         public class BackendServiceImpl : TestService.TestServiceBase
         {
             public UnaryServerMethod<SimpleRequest, SimpleResponse> UnaryHandler { get; set; }
+            public UnaryServerMethod<Empty, Empty> EmptyHandler { get; set; }
 
             public override Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
             {
                 return UnaryHandler(request, context);
             }
+
+            public override Task<Empty> EmptyCall(Empty request, ServerCallContext context)
+            {
+                return EmptyHandler(request, context);
+            }
         }
     }
 }
index de02dfb..7f6f0f7 100644 (file)
@@ -1,7 +1,7 @@
 <!-- This file is generated -->
 <Project>
   <PropertyGroup>
-    <GrpcCsharpVersion>2.31.0</GrpcCsharpVersion>
+    <GrpcCsharpVersion>2.31.1</GrpcCsharpVersion>
     <GoogleProtobufVersion>3.12.2</GoogleProtobufVersion>
   </PropertyGroup>
 </Project>
index 3384a91..fed939a 100644 (file)
@@ -13,7 +13,7 @@
 @rem limitations under the License.
 
 @rem Current package versions
-set VERSION=2.31.0
+set VERSION=2.31.1
 
 @rem Adjust the location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
index dcd2a8d..68e8dd2 100644 (file)
@@ -42,7 +42,7 @@ Pod::Spec.new do |s|
   # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
   # before them.
   s.name     = '!ProtoCompiler-gRPCCppPlugin'
-  v = '1.31.0'
+  v = '1.31.1'
   s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates C++ files from .proto services.'
   s.description = <<-DESC
index 793f9fb..5fad584 100644 (file)
@@ -42,7 +42,7 @@ Pod::Spec.new do |s|
   # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
   # before them.
   s.name     = '!ProtoCompiler-gRPCPlugin'
-  v = '1.31.0'
+  v = '1.31.1'
   s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
   s.description = <<-DESC
index 65d53ae..ee1a905 100644 (file)
@@ -22,4 +22,4 @@
 // instead. This file can be regenerated from the template by running
 // `tools/buildgen/generate_projects.sh`.
 
-#define GRPC_OBJC_VERSION_STRING @"1.31.0"
+#define GRPC_OBJC_VERSION_STRING @"1.31.1"
index 5663103..782a600 100644 (file)
@@ -22,5 +22,5 @@
 // instead. This file can be regenerated from the template by running
 // `tools/buildgen/generate_projects.sh`.
 
-#define GRPC_OBJC_VERSION_STRING @"1.31.0"
+#define GRPC_OBJC_VERSION_STRING @"1.31.1"
 #define GRPC_C_VERSION_STRING @"11.0.0"
index 4a61a9a..1c26885 100644 (file)
@@ -2,7 +2,7 @@
   "name": "grpc/grpc-dev",
   "description": "gRPC library for PHP - for Development use only",
   "license": "Apache-2.0",
-  "version": "1.31.0",
+  "version": "1.31.1",
   "require": {
     "php": ">=5.5.0",
     "google/protobuf": "^v3.3.0"
index c529fc0..d08ec47 100644 (file)
@@ -20,6 +20,6 @@
 #ifndef VERSION_H
 #define VERSION_H
 
-#define PHP_GRPC_VERSION "1.31.0"
+#define PHP_GRPC_VERSION "1.31.1"
 
 #endif /* VERSION_H */
index 8b78219..9767869 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!!
 
-__version__ = """1.31.0"""
+__version__ = """1.31.1"""
index df98793..afeebde 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-VERSION = '1.31.0'
+VERSION = '1.31.1'
index 668ae3b..8e8a9f0 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/grpc_version.py.template`!!!
 
-VERSION = '1.31.0'
+VERSION = '1.31.1'
index d29cbb3..9532584 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
 
-VERSION = '1.31.0'
+VERSION = '1.31.1'
index 78e74f7..9e99890 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
 
-VERSION = '1.31.0'
+VERSION = '1.31.1'
index c7752ec..cdc41d4 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_status/grpc_version.py.template`!!!
 
-VERSION = '1.31.0'
+VERSION = '1.31.1'
index aa1e817..dfc9dc8 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!!
 
-VERSION = '1.31.0'
+VERSION = '1.31.1'
index 6fd3bee..2f8cde9 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
 
-VERSION = '1.31.0'
+VERSION = '1.31.1'
index e6f32e3..961117c 100644 (file)
@@ -31,19 +31,19 @@ module Math
 
       # Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
       # and remainder.
-      rpc :Div, DivArgs, DivReply
+      rpc :Div, ::Math::DivArgs, ::Math::DivReply
       # DivMany accepts an arbitrary number of division args from the client stream
       # and sends back the results in the reply stream.  The stream continues until
       # the client closes its end; the server does the same after sending all the
       # replies.  The stream ends immediately if either end aborts.
-      rpc :DivMany, stream(DivArgs), stream(DivReply)
+      rpc :DivMany, stream(::Math::DivArgs), stream(::Math::DivReply)
       # Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
       # generates up to limit numbers; otherwise it continues until the call is
       # canceled.  Unlike Fib above, Fib has no final FibReply.
-      rpc :Fib, FibArgs, stream(Num)
+      rpc :Fib, ::Math::FibArgs, stream(::Math::Num)
       # Sum sums a stream of numbers, returning the final result once the stream
       # is closed.
-      rpc :Sum, stream(Num), Num
+      rpc :Sum, stream(::Math::Num), ::Math::Num
     end
 
     Stub = Service.rpc_stub_class
index 27ea00f..043e621 100644 (file)
@@ -43,8 +43,8 @@ def main
   end
 
   correct_modularized_rpc = 'rpc :TestOne, ' \
-                            'Grpc::Testing::PackageWithUnderscore::Data::Request, ' \
-                            'Grpc::Testing::PackageWithUnderscore::Data::Response'
+                            '::Grpc::Testing::PackageWithUnderscore::Data::Request, ' \
+                            '::Grpc::Testing::PackageWithUnderscore::Data::Response'
 
   return if got.include?(correct_modularized_rpc)
 
index b193f5c..1884dcb 100644 (file)
@@ -100,7 +100,7 @@ module GRPC
                    channel_args: {},
                    interceptors: [])
       @ch = ClientStub.setup_channel(channel_override, host, creds,
-                                     channel_args)
+                                     channel_args.dup)
       alt_host = channel_args[Core::Channel::SSL_TARGET]
       @host = alt_host.nil? ? host : alt_host
       @propagate_mask = propagate_mask
index 7eef11a..06c0e29 100644 (file)
@@ -14,5 +14,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '1.31.0'
+  VERSION = '1.31.1'
 end
index 5992f1c..351e7e1 100644 (file)
@@ -36,7 +36,7 @@ module Grpc
 
           # If the requested service is unknown, the call will fail with status
           # NOT_FOUND.
-          rpc :Check, HealthCheckRequest, HealthCheckResponse
+          rpc :Check, ::Grpc::Health::V1::HealthCheckRequest, ::Grpc::Health::V1::HealthCheckResponse
           # Performs a watch for the serving status of the requested service.
           # The server will immediately send back a message indicating the current
           # serving status.  It will then subsequently send a new message whenever
@@ -52,7 +52,7 @@ module Grpc
           # should assume this method is not supported and should not retry the
           # call.  If the call terminates with any other status (including OK),
           # clients should retry the call with appropriate exponential backoff.
-          rpc :Watch, HealthCheckRequest, stream(HealthCheckResponse)
+          rpc :Watch, ::Grpc::Health::V1::HealthCheckRequest, stream(::Grpc::Health::V1::HealthCheckResponse)
         end
 
         Stub = Service.rpc_stub_class
index f492ccf..d902ae0 100644 (file)
@@ -71,6 +71,10 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
     add_message "grpc.testing.LoadBalancerStatsResponse" do
       map :rpcs_by_peer, :string, :int32, 1
       optional :num_failures, :int32, 2
+      map :rpcs_by_method, :string, :message, 3, "grpc.testing.LoadBalancerStatsResponse.RpcsByPeer"
+    end
+    add_message "grpc.testing.LoadBalancerStatsResponse.RpcsByPeer" do
+      map :rpcs_by_peer, :string, :int32, 1
     end
     add_enum "grpc.testing.PayloadType" do
       value :COMPRESSABLE, 0
@@ -99,6 +103,7 @@ module Grpc
     ReconnectInfo = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass
     LoadBalancerStatsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.LoadBalancerStatsRequest").msgclass
     LoadBalancerStatsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.LoadBalancerStatsResponse").msgclass
+    LoadBalancerStatsResponse::RpcsByPeer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.LoadBalancerStatsResponse.RpcsByPeer").msgclass
     PayloadType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule
     GrpclbRouteType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.GrpclbRouteType").enummodule
   end
index 8138bd0..115acd0 100644 (file)
@@ -36,31 +36,31 @@ module Grpc
         self.service_name = 'grpc.testing.TestService'
 
         # One empty request followed by one empty response.
-        rpc :EmptyCall, Empty, Empty
+        rpc :EmptyCall, ::Grpc::Testing::Empty, ::Grpc::Testing::Empty
         # One request followed by one response.
-        rpc :UnaryCall, SimpleRequest, SimpleResponse
+        rpc :UnaryCall, ::Grpc::Testing::SimpleRequest, ::Grpc::Testing::SimpleResponse
         # One request followed by one response. Response has cache control
         # headers set such that a caching HTTP proxy (such as GFE) can
         # satisfy subsequent requests.
-        rpc :CacheableUnaryCall, SimpleRequest, SimpleResponse
+        rpc :CacheableUnaryCall, ::Grpc::Testing::SimpleRequest, ::Grpc::Testing::SimpleResponse
         # One request followed by a sequence of responses (streamed download).
         # The server returns the payload with client desired type and sizes.
-        rpc :StreamingOutputCall, StreamingOutputCallRequest, stream(StreamingOutputCallResponse)
+        rpc :StreamingOutputCall, ::Grpc::Testing::StreamingOutputCallRequest, stream(::Grpc::Testing::StreamingOutputCallResponse)
         # A sequence of requests followed by one response (streamed upload).
         # The server returns the aggregated size of client payload as the result.
-        rpc :StreamingInputCall, stream(StreamingInputCallRequest), StreamingInputCallResponse
+        rpc :StreamingInputCall, stream(::Grpc::Testing::StreamingInputCallRequest), ::Grpc::Testing::StreamingInputCallResponse
         # A sequence of requests with each request served by the server immediately.
         # As one request could lead to multiple responses, this interface
         # demonstrates the idea of full duplexing.
-        rpc :FullDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
+        rpc :FullDuplexCall, stream(::Grpc::Testing::StreamingOutputCallRequest), stream(::Grpc::Testing::StreamingOutputCallResponse)
         # A sequence of requests followed by a sequence of responses.
         # The server buffers all the client requests and then serves them in order. A
         # stream of responses are returned to the client when the server starts with
         # first request.
-        rpc :HalfDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
+        rpc :HalfDuplexCall, stream(::Grpc::Testing::StreamingOutputCallRequest), stream(::Grpc::Testing::StreamingOutputCallResponse)
         # The test server will not implement this method. It will be used
         # to test the behavior when clients call unimplemented methods.
-        rpc :UnimplementedCall, Empty, Empty
+        rpc :UnimplementedCall, ::Grpc::Testing::Empty, ::Grpc::Testing::Empty
       end
 
       Stub = Service.rpc_stub_class
@@ -77,7 +77,7 @@ module Grpc
         self.service_name = 'grpc.testing.UnimplementedService'
 
         # A call that no server should implement
-        rpc :UnimplementedCall, Empty, Empty
+        rpc :UnimplementedCall, ::Grpc::Testing::Empty, ::Grpc::Testing::Empty
       end
 
       Stub = Service.rpc_stub_class
@@ -92,8 +92,8 @@ module Grpc
         self.unmarshal_class_method = :decode
         self.service_name = 'grpc.testing.ReconnectService'
 
-        rpc :Start, ReconnectParams, Empty
-        rpc :Stop, Empty, ReconnectInfo
+        rpc :Start, ::Grpc::Testing::ReconnectParams, ::Grpc::Testing::Empty
+        rpc :Stop, ::Grpc::Testing::Empty, ::Grpc::Testing::ReconnectInfo
       end
 
       Stub = Service.rpc_stub_class
@@ -109,7 +109,23 @@ module Grpc
         self.service_name = 'grpc.testing.LoadBalancerStatsService'
 
         # Gets the backend distribution for RPCs sent by a test client.
-        rpc :GetClientStats, LoadBalancerStatsRequest, LoadBalancerStatsResponse
+        rpc :GetClientStats, ::Grpc::Testing::LoadBalancerStatsRequest, ::Grpc::Testing::LoadBalancerStatsResponse
+      end
+
+      Stub = Service.rpc_stub_class
+    end
+    module XdsUpdateHealthService
+      # A service to remotely control health status of an xDS test server.
+      class Service
+
+        include GRPC::GenericService
+
+        self.marshal_class_method = :encode
+        self.unmarshal_class_method = :decode
+        self.service_name = 'grpc.testing.XdsUpdateHealthService'
+
+        rpc :SetServing, ::Grpc::Testing::Empty, ::Grpc::Testing::Empty
+        rpc :SetNotServing, ::Grpc::Testing::Empty, ::Grpc::Testing::Empty
       end
 
       Stub = Service.rpc_stub_class
index 65e5a75..63e2d5d 100644 (file)
@@ -34,20 +34,20 @@ module Grpc
 
         # One request followed by one response.
         # The server returns the client payload as-is.
-        rpc :UnaryCall, SimpleRequest, SimpleResponse
+        rpc :UnaryCall, ::Grpc::Testing::SimpleRequest, ::Grpc::Testing::SimpleResponse
         # Repeated sequence of one request followed by one response.
         # Should be called streaming ping-pong
         # The server returns the client payload as-is on each response
-        rpc :StreamingCall, stream(SimpleRequest), stream(SimpleResponse)
+        rpc :StreamingCall, stream(::Grpc::Testing::SimpleRequest), stream(::Grpc::Testing::SimpleResponse)
         # Single-sided unbounded streaming from client to server
         # The server returns the client payload as-is once the client does WritesDone
-        rpc :StreamingFromClient, stream(SimpleRequest), SimpleResponse
+        rpc :StreamingFromClient, stream(::Grpc::Testing::SimpleRequest), ::Grpc::Testing::SimpleResponse
         # Single-sided unbounded streaming from server to client
         # The server repeatedly returns the client payload as-is
-        rpc :StreamingFromServer, SimpleRequest, stream(SimpleResponse)
+        rpc :StreamingFromServer, ::Grpc::Testing::SimpleRequest, stream(::Grpc::Testing::SimpleResponse)
         # Two-sided unbounded streaming between server to client
         # Both sides send the content of their own choice to the other
-        rpc :StreamingBothWays, stream(SimpleRequest), stream(SimpleResponse)
+        rpc :StreamingBothWays, stream(::Grpc::Testing::SimpleRequest), stream(::Grpc::Testing::SimpleResponse)
       end
 
       Stub = Service.rpc_stub_class
index f492ccf..d902ae0 100644 (file)
@@ -71,6 +71,10 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
     add_message "grpc.testing.LoadBalancerStatsResponse" do
       map :rpcs_by_peer, :string, :int32, 1
       optional :num_failures, :int32, 2
+      map :rpcs_by_method, :string, :message, 3, "grpc.testing.LoadBalancerStatsResponse.RpcsByPeer"
+    end
+    add_message "grpc.testing.LoadBalancerStatsResponse.RpcsByPeer" do
+      map :rpcs_by_peer, :string, :int32, 1
     end
     add_enum "grpc.testing.PayloadType" do
       value :COMPRESSABLE, 0
@@ -99,6 +103,7 @@ module Grpc
     ReconnectInfo = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass
     LoadBalancerStatsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.LoadBalancerStatsRequest").msgclass
     LoadBalancerStatsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.LoadBalancerStatsResponse").msgclass
+    LoadBalancerStatsResponse::RpcsByPeer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.LoadBalancerStatsResponse.RpcsByPeer").msgclass
     PayloadType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule
     GrpclbRouteType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.GrpclbRouteType").enummodule
   end
index ddc81be..5e41cfe 100644 (file)
@@ -33,7 +33,7 @@ module Grpc
         self.service_name = 'grpc.testing.ReportQpsScenarioService'
 
         # Report results of a QPS test benchmark scenario.
-        rpc :ReportScenario, ScenarioResult, Void
+        rpc :ReportScenario, ::Grpc::Testing::ScenarioResult, ::Grpc::Testing::Void
       end
 
       Stub = Service.rpc_stub_class
index a7ecc95..049db47 100644 (file)
@@ -38,18 +38,18 @@ module Grpc
         # stats. Closing the stream will initiate shutdown of the test server
         # and once the shutdown has finished, the OK status is sent to terminate
         # this RPC.
-        rpc :RunServer, stream(ServerArgs), stream(ServerStatus)
+        rpc :RunServer, stream(::Grpc::Testing::ServerArgs), stream(::Grpc::Testing::ServerStatus)
         # Start client with specified workload.
         # First request sent specifies the ClientConfig followed by ClientStatus
         # response. After that, a "Mark" can be sent anytime to request the latest
         # stats. Closing the stream will initiate shutdown of the test client
         # and once the shutdown has finished, the OK status is sent to terminate
         # this RPC.
-        rpc :RunClient, stream(ClientArgs), stream(ClientStatus)
+        rpc :RunClient, stream(::Grpc::Testing::ClientArgs), stream(::Grpc::Testing::ClientStatus)
         # Just return the core count - unary call
-        rpc :CoreCount, CoreRequest, CoreResponse
+        rpc :CoreCount, ::Grpc::Testing::CoreRequest, ::Grpc::Testing::CoreResponse
         # Quit this worker
-        rpc :QuitWorker, Void, Void
+        rpc :QuitWorker, ::Grpc::Testing::Void, ::Grpc::Testing::Void
       end
 
       Stub = Service.rpc_stub_class
diff --git a/src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto b/src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto
new file mode 100644 (file)
index 0000000..15dd8f0
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2020 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package same_name;
+
+service SameName {
+  rpc Health(Request) returns (Status);
+}
+
+message Status {
+  string msg = 1;
+}
+
+message Request {}
diff --git a/src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto b/src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto
new file mode 100644 (file)
index 0000000..9ce631c
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2020 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package other_name;
+
+option ruby_package = "SameName2";
+
+service SameName2 {
+  rpc Health(Request) returns (Status);
+}
+
+message Status {
+  string msg = 1;
+}
+
+message Request {}
index a4668ac..f64b4f6 100644 (file)
@@ -48,6 +48,26 @@ describe 'Code Generation Options' do
       expect(services[:NestedMessageTest].output).to eq(RPC::Test::New::Package::Options::Bar::Baz)
     end
   end
+
+  it 'should generate when package and service has same name' do
+    with_protos(['grpc/testing/same_package_service_name.proto']) do
+      expect { SameName::SameName::Service }.to raise_error(NameError)
+      expect(require('grpc/testing/same_package_service_name_services_pb')).to be_truthy
+      expect { SameName::SameName::Service }.to_not raise_error
+      expect { SameName::Request }.to_not raise_error
+      expect { SameName::Status }.to_not raise_error
+    end
+  end
+
+  it 'should generate when ruby_package and service has same name' do
+    with_protos(['grpc/testing/same_ruby_package_service_name.proto']) do
+      expect { SameName2::SameName2::Service }.to raise_error(NameError)
+      expect(require('grpc/testing/same_ruby_package_service_name_services_pb')).to be_truthy
+      expect { SameName2::SameName2::Service }.to_not raise_error
+      expect { SameName2::Request }.to_not raise_error
+      expect { SameName2::Status }.to_not raise_error
+    end
+  end
 end
 
 def with_protos(file_paths)
diff --git a/src/ruby/spec/user_agent_spec.rb b/src/ruby/spec/user_agent_spec.rb
new file mode 100644 (file)
index 0000000..a5aa206
--- /dev/null
@@ -0,0 +1,74 @@
+# Copyright 2020 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'spec_helper'
+
+# a test service that checks the cert of its peer
+class UserAgentEchoService
+  include GRPC::GenericService
+  rpc :an_rpc, EchoMsg, EchoMsg
+
+  def an_rpc(_req, call)
+    EchoMsg.new(msg: call.metadata['user-agent'])
+  end
+end
+
+UserAgentEchoServiceStub = UserAgentEchoService.rpc_stub_class
+
+describe 'user agent' do
+  RpcServer = GRPC::RpcServer
+
+  before(:all) do
+    server_opts = {
+      poll_period: 1
+    }
+    @srv = new_rpc_server_for_testing(**server_opts)
+    @port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
+    @srv.handle(UserAgentEchoService)
+    @srv_thd = Thread.new { @srv.run }
+    @srv.wait_till_running
+  end
+
+  after(:all) do
+    expect(@srv.stopped?).to be(false)
+    @srv.stop
+    @srv_thd.join
+  end
+
+  it 'client sends expected user agent' do
+    stub = UserAgentEchoServiceStub.new("localhost:#{@port}",
+                                        :this_channel_is_insecure,
+                                        {})
+    response = stub.an_rpc(EchoMsg.new)
+    expected_user_agent_prefix = "grpc-ruby/#{GRPC::VERSION}"
+    expect(response.msg.start_with?(expected_user_agent_prefix)).to be true
+    # check that the expected user agent prefix occurs in the real user agent exactly once
+    expect(response.msg.split(expected_user_agent_prefix).size).to eq 2
+  end
+
+  it 'user agent header does not grow when the same channel args hash is used across multiple stubs' do
+    shared_channel_args_hash = {}
+    10.times do
+      stub = UserAgentEchoServiceStub.new("localhost:#{@port}",
+                                          :this_channel_is_insecure,
+                                          channel_args: shared_channel_args_hash)
+      response = stub.an_rpc(EchoMsg.new)
+      puts "got echo response: #{response.msg}"
+      expected_user_agent_prefix = "grpc-ruby/#{GRPC::VERSION}"
+      expect(response.msg.start_with?(expected_user_agent_prefix)).to be true
+      # check that the expected user agent prefix occurs in the real user agent exactly once
+      expect(response.msg.split(expected_user_agent_prefix).size).to eq 2
+    end
+  end
+end
index 4f01bb0..ef98346 100644 (file)
@@ -14,6 +14,6 @@
 
 module GRPC
   module Tools
-    VERSION = '1.31.0'
+    VERSION = '1.31.1'
   end
 end
index 4136af4..cc8b71b 100644 (file)
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION = '1.31.0'
+VERSION = '1.31.1'
index 1310bc7..dc10fc2 100644 (file)
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC C++"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.31.0
+PROJECT_NUMBER         = 1.31.1
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
index b2f2ea3..6db2b11 100644 (file)
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC C++"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.31.0
+PROJECT_NUMBER         = 1.31.1
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
index b9f5b03..5684828 100644 (file)
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC Objective-C"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.31.0
+PROJECT_NUMBER         = 1.31.1
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
index b14ee16..635095c 100644 (file)
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC Objective-C"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.31.0
+PROJECT_NUMBER         = 1.31.1
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
index 58d2788..6d25c6d 100644 (file)
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC PHP"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.31.0
+PROJECT_NUMBER         = 1.31.1
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
index 85ddb2c..f9c9a8a 100755 (executable)
@@ -48,12 +48,17 @@ touch "$TOOLS_DIR"/src/proto/grpc/testing/__init__.py
 
 python tools/run_tests/run_tests.py -l csharp -c opt --build_only
 
+# Test cases "path_matching" and "header_matching" are not included in "all",
+# because not all interop clients in all languages support these new tests.
+#
+# TODO(jtattermusch): remove "path_matching" and "header_matching" from
+# --test_case after they are added into "all".
 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='dotnet exec src/csharp/Grpc.IntegrationTesting.XdsClient/bin/Release/netcoreapp2.1/Grpc.IntegrationTesting.XdsClient.dll -- --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps}'
+    --client_cmd='dotnet exec src/csharp/Grpc.IntegrationTesting.XdsClient/bin/Release/netcoreapp2.1/Grpc.IntegrationTesting.XdsClient.dll -- --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {rpcs_to_send} {metadata_to_send}'
index 6908067..a5d6fa5 100755 (executable)
@@ -1715,9 +1715,29 @@ try:
                 metadata_to_send = '--metadata="EmptyCall:{key}:{value}"'.format(
                     key=_TEST_METADATA_KEY, value=_TEST_METADATA_VALUE)
             else:
-                metadata_to_send = '--metadata=""'
+                # Setting the arg explicitly to empty with '--metadata=""'
+                # makes C# client fail
+                # (see https://github.com/commandlineparser/commandline/issues/412),
+                # so instead we just rely on clients using the default when
+                # metadata arg is not specified.
+                metadata_to_send = ''
 
             if test_case in _TESTS_TO_FAIL_ON_RPC_FAILURE:
+                # TODO(ericgribkoff) Unconditional wait is recommended by TD
+                # team when reusing backend resources after config changes
+                # between test cases, as we are doing here. This should address
+                # flakiness issues with these tests; other attempts to deflake
+                # (such as waiting for the first successful RPC before failing
+                # on any subsequent failures) were insufficient because, due to
+                # propagation delays, we may initially see an RPC succeed to the
+                # expected backends but due to a stale configuration: e.g., test
+                # A (1) routes traffic to MIG A, then (2) switches to MIG B,
+                # then (3) back to MIG A. Test B begins running and sees RPCs
+                # going to MIG A, as expected. However, due to propagation
+                # delays, Test B is actually seeing the stale config from step
+                # (1), and then fails when it gets update (2) unexpectedly
+                # switching to MIG B.
+                time.sleep(200)
                 fail_on_failed_rpc = '--fail_on_failed_rpc=true'
             else:
                 fail_on_failed_rpc = '--fail_on_failed_rpc=false'