aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp
diff options
context:
space:
mode:
Diffstat (limited to 'src/csharp')
-rw-r--r--src/csharp/.nuget/packages.config6
-rw-r--r--src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs2
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.csproj51
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.nuspec2
-rw-r--r--src/csharp/Grpc.Auth/app.config19
-rw-r--r--src/csharp/Grpc.Auth/packages.config8
-rw-r--r--src/csharp/Grpc.Core.Tests/CallOptionsTest.cs16
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelTest.cs43
-rw-r--r--src/csharp/Grpc.Core.Tests/ClientServerTest.cs89
-rw-r--r--src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs10
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj33
-rw-r--r--src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs10
-rw-r--r--src/csharp/Grpc.Core.Tests/HalfcloseTest.cs97
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs201
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs600
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs184
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs10
-rw-r--r--src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs16
-rw-r--r--src/csharp/Grpc.Core.Tests/NUnitMain.cs59
-rw-r--r--src/csharp/Grpc.Core.Tests/PInvokeTest.cs8
-rw-r--r--src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/SanityTest.cs28
-rw-r--r--src/csharp/Grpc.Core.Tests/packages.config5
-rw-r--r--src/csharp/Grpc.Core/AsyncAuthInterceptor.cs2
-rw-r--r--src/csharp/Grpc.Core/CallCredentials.cs2
-rw-r--r--src/csharp/Grpc.Core/CallInvocationDetails.cs2
-rw-r--r--src/csharp/Grpc.Core/CallInvoker.cs84
-rw-r--r--src/csharp/Grpc.Core/CallOptions.cs53
-rw-r--r--src/csharp/Grpc.Core/Channel.cs49
-rw-r--r--src/csharp/Grpc.Core/ChannelCredentials.cs2
-rw-r--r--src/csharp/Grpc.Core/ChannelOptions.cs2
-rw-r--r--src/csharp/Grpc.Core/ClientBase.cs161
-rw-r--r--src/csharp/Grpc.Core/ContextPropagationToken.cs2
-rw-r--r--src/csharp/Grpc.Core/DefaultCallInvoker.cs112
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj15
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.nuspec8
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.targets (renamed from src/csharp/grpc.native.csharp/grpc.native.csharp.targets)0
-rw-r--r--src/csharp/Grpc.Core/GrpcEnvironment.cs87
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs111
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs150
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallServer.cs94
-rw-r--r--src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs105
-rw-r--r--src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/CallError.cs (renamed from src/csharp/Grpc.Core/Internal/Enums.cs)41
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs35
-rw-r--r--src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs11
-rw-r--r--src/csharp/Grpc.Core/Internal/ClientRequestStream.cs8
-rw-r--r--src/csharp/Grpc.Core/Internal/ClientResponseStream.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/ClientSideStatus.cs70
-rw-r--r--src/csharp/Grpc.Core/Internal/ClockType.cs53
-rw-r--r--src/csharp/Grpc.Core/Internal/CompletionQueueEvent.cs19
-rw-r--r--src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs18
-rw-r--r--src/csharp/Grpc.Core/Internal/CompletionRegistry.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs72
-rw-r--r--src/csharp/Grpc.Core/Internal/INativeCall.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/InterceptingCallInvoker.cs134
-rw-r--r--src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs7
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeExtension.cs46
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMethods.cs111
-rw-r--r--src/csharp/Grpc.Core/Internal/PlatformApis.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCallHandler.cs115
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerRequestStream.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerResponseStream.cs15
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerRpcNew.cs (renamed from src/csharp/Grpc.Core/Internal/AsyncCompletion.cs)77
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs29
-rw-r--r--src/csharp/Grpc.Core/Internal/Timespec.cs39
-rw-r--r--src/csharp/Grpc.Core/Internal/UnimplementedCallInvoker.cs75
-rw-r--r--src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs26
-rw-r--r--src/csharp/Grpc.Core/KeyCertificatePair.cs2
-rw-r--r--src/csharp/Grpc.Core/Logging/ConsoleLogger.cs95
-rw-r--r--src/csharp/Grpc.Core/Logging/TextWriterLogger.cs176
-rw-r--r--src/csharp/Grpc.Core/Marshaller.cs2
-rw-r--r--src/csharp/Grpc.Core/Metadata.cs2
-rw-r--r--src/csharp/Grpc.Core/Method.cs2
-rw-r--r--src/csharp/Grpc.Core/Profiling/Profilers.cs2
-rw-r--r--src/csharp/Grpc.Core/Properties/AssemblyInfo.cs6
-rw-r--r--src/csharp/Grpc.Core/Server.cs53
-rw-r--r--src/csharp/Grpc.Core/ServerCredentials.cs2
-rw-r--r--src/csharp/Grpc.Core/ServerPort.cs2
-rw-r--r--src/csharp/Grpc.Core/Utils/GrpcPreconditions.cs2
-rw-r--r--src/csharp/Grpc.Core/Version.cs5
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs15
-rw-r--r--src/csharp/Grpc.Examples.MathClient/MathClient.cs4
-rw-r--r--src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj20
-rw-r--r--src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs4
-rw-r--r--src/csharp/Grpc.Examples.Tests/NUnitMain.cs59
-rw-r--r--src/csharp/Grpc.Examples.Tests/packages.config11
-rw-r--r--src/csharp/Grpc.Examples/Grpc.Examples.csproj5
-rw-r--r--src/csharp/Grpc.Examples/Math.cs12
-rw-r--r--src/csharp/Grpc.Examples/MathExamples.cs52
-rw-r--r--src/csharp/Grpc.Examples/MathGrpc.cs295
-rw-r--r--src/csharp/Grpc.Examples/MathServiceImpl.cs41
-rw-r--r--src/csharp/Grpc.Examples/packages.config4
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj25
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs11
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs33
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs59
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/packages.config5
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj2
-rw-r--r--src/csharp/Grpc.HealthCheck/Health.cs24
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthGrpc.cs111
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs6
-rw-r--r--src/csharp/Grpc.HealthCheck/packages.config2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj39
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/app.config19
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/packages.config8
-rw-r--r--src/csharp/Grpc.IntegrationTesting.QpsWorker/app.config4
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj39
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/app.config19
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/packages.config8
-rw-r--r--src/csharp/Grpc.IntegrationTesting.StressClient/.gitignore3
-rw-r--r--src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj60
-rw-r--r--src/csharp/Grpc.IntegrationTesting.StressClient/Program.cs45
-rw-r--r--src/csharp/Grpc.IntegrationTesting.StressClient/Properties/AssemblyInfo.cs11
-rw-r--r--src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs17
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ClientRunners.cs291
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Control.cs1830
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Empty.cs4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs106
-rw-r--r--src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs (renamed from src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs)69
-rw-r--r--src/csharp/Grpc.IntegrationTesting/GenericService.cs71
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj72
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Histogram.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InterarrivalTimers.cs148
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs110
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Messages.cs213
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs8
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Metrics.cs452
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs242
-rw-r--r--src/csharp/Grpc.IntegrationTesting/NUnitMain.cs59
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Payloads.cs10
-rw-r--r--src/csharp/Grpc.IntegrationTesting/QpsWorker.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs16
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ServerRunners.cs67
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Services.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs496
-rw-r--r--src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Stats.cs10
-rw-r--r--src/csharp/Grpc.IntegrationTesting/StressTestClient.cs318
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Test.cs10
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestCredentials.cs33
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs632
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs204
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs16
-rw-r--r--src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs14
-rw-r--r--src/csharp/Grpc.IntegrationTesting/app.config19
-rw-r--r--src/csharp/Grpc.IntegrationTesting/packages.config13
-rw-r--r--src/csharp/Grpc.sln8
-rw-r--r--src/csharp/README.md15
-rw-r--r--src/csharp/build_packages.bat46
-rw-r--r--src/csharp/buildall.bat35
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c54
-rwxr-xr-xsrc/csharp/generate_proto_csharp.sh4
-rw-r--r--src/csharp/grpc.native.csharp/README.md22
-rw-r--r--src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec2
-rw-r--r--src/csharp/tests.json25
165 files changed, 8093 insertions, 2663 deletions
diff --git a/src/csharp/.nuget/packages.config b/src/csharp/.nuget/packages.config
index 89a310ac56..6154b3561f 100644
--- a/src/csharp/.nuget/packages.config
+++ b/src/csharp/.nuget/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="NUnit.Runners" version="2.6.4" />
- <package id="OpenCover" version="4.6.166" />
- <package id="ReportGenerator" version="2.3.2.0" />
+ <package id="NUnit.ConsoleRunner" version="3.2.0" />
+ <package id="OpenCover" version="4.6.519" />
+ <package id="ReportGenerator" version="2.4.4.0" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
index 1837f5c74b..96d6ee87ae 100644
--- a/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
+++ b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index 8dd12b50ef..3acea7d2f8 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -9,7 +9,7 @@
<AssemblyName>Grpc.Auth</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<DocumentationFile>bin\$(Configuration)\Grpc.Auth.Xml</DocumentationFile>
- <NuGetPackageImportStamp>4f8487a9</NuGetPackageImportStamp>
+ <NuGetPackageImportStamp>455903a2</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -39,43 +39,30 @@
<AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="Google.Apis.Auth, Version=1.10.0.25333, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.10.0\lib\net40\Google.Apis.Auth.dll</HintPath>
+ <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.10.0.25333, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Core, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.10.0\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Core.1.11.1\lib\net45\Google.Apis.Core.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Core, Version=1.10.0.25331, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Core.1.10.0\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
- <Reference Include="BouncyCastle.Crypto">
- <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
- </Reference>
- <Reference Include="Microsoft.Threading.Tasks">
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
- </Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions">
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
- </Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
- </Reference>
- <Reference Include="Newtonsoft.Json">
- <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
- </Reference>
- <Reference Include="System.Net.Http.Extensions">
- <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
- </Reference>
- <Reference Include="System.Net.Http.Primitives">
- <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
- </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@@ -93,15 +80,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <None Include="app.config" />
<None Include="Grpc.Auth.nuspec" />
<None Include="packages.config" />
</ItemGroup>
- <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
- <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
- <PropertyGroup>
- <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
- </PropertyGroup>
- <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
- </Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
index f1f8f7c709..4baed3704c 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
@@ -15,7 +15,7 @@
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags>
<dependencies>
- <dependency id="Google.Apis.Auth" version="1.9.3" />
+ <dependency id="Google.Apis.Auth" version="1.11.1" />
<dependency id="Grpc.Core" version="$version$" />
</dependencies>
</metadata>
diff --git a/src/csharp/Grpc.Auth/app.config b/src/csharp/Grpc.Auth/app.config
deleted file mode 100644
index 84d7534d65..0000000000
--- a/src/csharp/Grpc.Auth/app.config
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
- <runtime>
- <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Google.Apis.Core" publicKeyToken="4b01fa6e34db77ab" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-1.9.2.38523" newVersion="1.9.2.38523" />
- </dependentAssembly>
- </assemblyBinding>
- </runtime>
-</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config
index 5fe8ca616c..c20d9ceed6 100644
--- a/src/csharp/Grpc.Auth/packages.config
+++ b/src/csharp/Grpc.Auth/packages.config
@@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
- <package id="Google.Apis.Auth" version="1.10.0" targetFramework="net45" />
- <package id="Google.Apis.Core" version="1.10.0" targetFramework="net45" />
- <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
- <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
- <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
- <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.11.1" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.11.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs b/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
index a3a613be74..99a2d47e6e 100644
--- a/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
@@ -54,10 +54,20 @@ namespace Grpc.Core.Tests
var deadline = DateTime.UtcNow;
Assert.AreEqual(deadline, options.WithDeadline(deadline).Deadline.Value);
- var token = new CancellationTokenSource().Token;
- Assert.AreEqual(token, options.WithCancellationToken(token).CancellationToken);
+ var cancellationToken = new CancellationTokenSource().Token;
+ Assert.AreEqual(cancellationToken, options.WithCancellationToken(cancellationToken).CancellationToken);
+
+ var writeOptions = new WriteOptions();
+ Assert.AreSame(writeOptions, options.WithWriteOptions(writeOptions).WriteOptions);
+
+ var propagationToken = new ContextPropagationToken(CallSafeHandle.NullInstance, DateTime.UtcNow,
+ CancellationToken.None, ContextPropagationOptions.Default);
+ Assert.AreSame(propagationToken, options.WithPropagationToken(propagationToken).PropagationToken);
+
+ var credentials = new FakeCallCredentials();
+ Assert.AreSame(credentials, options.WithCredentials(credentials).Credentials);
- // Change original instance is unchanged.
+ // Check that the original instance is unchanged.
Assert.IsNull(options.Headers);
Assert.IsNull(options.Deadline);
Assert.AreEqual(CancellationToken.None, options.CancellationToken);
diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
index ed0ec14df5..850d70ce92 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
@@ -32,6 +32,7 @@
#endregion
using System;
+using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
@@ -70,7 +71,7 @@ namespace Grpc.Core.Tests
public void WaitForStateChangedAsync_InvalidArgument()
{
var channel = new Channel("localhost", ChannelCredentials.Insecure);
- Assert.Throws(typeof(ArgumentException), () => channel.WaitForStateChangedAsync(ChannelState.FatalFailure));
+ Assert.ThrowsAsync(typeof(ArgumentException), async () => await channel.WaitForStateChangedAsync(ChannelState.FatalFailure));
channel.ShutdownAsync().Wait();
}
@@ -87,7 +88,45 @@ namespace Grpc.Core.Tests
{
var channel = new Channel("localhost", ChannelCredentials.Insecure);
channel.ShutdownAsync().Wait();
- Assert.Throws(typeof(InvalidOperationException), () => channel.ShutdownAsync().GetAwaiter().GetResult());
+ Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await channel.ShutdownAsync());
+ }
+
+ [Test]
+ public async Task ShutdownTokenCancelledAfterShutdown()
+ {
+ var channel = new Channel("localhost", ChannelCredentials.Insecure);
+ Assert.IsFalse(channel.ShutdownToken.IsCancellationRequested);
+ var shutdownTask = channel.ShutdownAsync();
+ Assert.IsTrue(channel.ShutdownToken.IsCancellationRequested);
+ await shutdownTask;
+ }
+
+ [Test]
+ public async Task StateIsFatalFailureAfterShutdown()
+ {
+ var channel = new Channel("localhost", ChannelCredentials.Insecure);
+ await channel.ShutdownAsync();
+ Assert.AreEqual(ChannelState.FatalFailure, channel.State);
+ }
+
+ [Test]
+ public async Task ShutdownFinishesWaitForStateChangedAsync()
+ {
+ var channel = new Channel("localhost", ChannelCredentials.Insecure);
+ var stateChangedTask = channel.WaitForStateChangedAsync(ChannelState.Idle);
+ var shutdownTask = channel.ShutdownAsync();
+ await stateChangedTask;
+ await shutdownTask;
+ }
+
+ [Test]
+ public async Task OperationsThrowAfterShutdown()
+ {
+ var channel = new Channel("localhost", ChannelCredentials.Insecure);
+ await channel.ShutdownAsync();
+ Assert.ThrowsAsync(typeof(ObjectDisposedException), async () => await channel.WaitForStateChangedAsync(ChannelState.Idle));
+ Assert.Throws(typeof(ObjectDisposedException), () => { var x = channel.ResolvedTarget; });
+ Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await channel.ConnectAsync());
}
}
}
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index 77f6a63156..dcdddc769e 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -93,7 +93,7 @@ namespace Grpc.Core.Tests
var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode);
- var ex2 = Assert.Throws<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
+ var ex2 = Assert.ThrowsAsync<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
Assert.AreEqual(StatusCode.Unknown, ex2.Status.StatusCode);
}
@@ -108,7 +108,7 @@ namespace Grpc.Core.Tests
var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode);
- var ex2 = Assert.Throws<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
+ var ex2 = Assert.ThrowsAsync<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode);
}
@@ -124,7 +124,7 @@ namespace Grpc.Core.Tests
var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode);
- var ex2 = Assert.Throws<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
+ var ex2 = Assert.ThrowsAsync<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode);
}
@@ -167,6 +167,37 @@ namespace Grpc.Core.Tests
}
[Test]
+ public async Task ServerStreamingCall_EndOfStreamIsIdempotent()
+ {
+ helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) =>
+ {
+ });
+
+ var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
+
+ Assert.IsFalse(await call.ResponseStream.MoveNext());
+ Assert.IsFalse(await call.ResponseStream.MoveNext());
+ }
+
+ [Test]
+ public async Task ServerStreamingCall_ErrorCanBeAwaitedTwice()
+ {
+ helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) =>
+ {
+ context.Status = new Status(StatusCode.InvalidArgument, "");
+ });
+
+ var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
+
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
+ Assert.AreEqual(StatusCode.InvalidArgument, ex.Status.StatusCode);
+
+ // attempting MoveNext again should result in throwing the same exception.
+ var ex2 = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
+ Assert.AreEqual(StatusCode.InvalidArgument, ex2.Status.StatusCode);
+ }
+
+ [Test]
public async Task DuplexStreamingCall()
{
helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
@@ -204,8 +235,54 @@ namespace Grpc.Core.Tests
await barrier.Task; // make sure the handler has started.
cts.Cancel();
- var ex = Assert.Throws<RpcException>(async () => await call.ResponseAsync);
- Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
+ try
+ {
+ // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
+ await call.ResponseAsync;
+ Assert.Fail();
+ }
+ catch (RpcException ex)
+ {
+ Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
+ }
+ }
+
+ [Test]
+ public async Task ClientStreamingCall_ServerSideReadAfterCancelNotificationReturnsNull()
+ {
+ var handlerStartedBarrier = new TaskCompletionSource<object>();
+ var cancelNotificationReceivedBarrier = new TaskCompletionSource<object>();
+ var successTcs = new TaskCompletionSource<string>();
+
+ helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
+ {
+ handlerStartedBarrier.SetResult(null);
+
+ // wait for cancellation to be delivered.
+ context.CancellationToken.Register(() => cancelNotificationReceivedBarrier.SetResult(null));
+ await cancelNotificationReceivedBarrier.Task;
+
+ var moveNextResult = await requestStream.MoveNext();
+ successTcs.SetResult(!moveNextResult ? "SUCCESS" : "FAIL");
+ return "";
+ });
+
+ var cts = new CancellationTokenSource();
+ var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
+
+ await handlerStartedBarrier.Task;
+ cts.Cancel();
+
+ try
+ {
+ await call.ResponseAsync;
+ Assert.Fail();
+ }
+ catch (RpcException ex)
+ {
+ Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
+ }
+ Assert.AreEqual("SUCCESS", await successTcs.Task);
}
[Test]
@@ -290,7 +367,7 @@ namespace Grpc.Core.Tests
return request;
});
- Assert.Throws(typeof(TaskCanceledException),
+ Assert.ThrowsAsync(typeof(TaskCanceledException),
async () => await channel.WaitForStateChangedAsync(channel.State, DateTime.UtcNow.AddMilliseconds(10)));
var stateChangedTask = channel.WaitForStateChangedAsync(channel.State);
diff --git a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
index 90c510ec61..6a156293ad 100644
--- a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
@@ -105,7 +105,15 @@ namespace Grpc.Core.Tests
var parentCall = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
await readyToCancelTcs.Task;
cts.Cancel();
- Assert.Throws(typeof(RpcException), async () => await parentCall);
+ try
+ {
+ // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
+ await parentCall;
+ Assert.Fail();
+ }
+ catch (RpcException)
+ {
+ }
Assert.AreEqual("CHILD_CALL_CANCELLED", await successTcs.Task);
}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 7e73c4f181..47131fc454 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -4,7 +4,7 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{86EC5CB4-4EA2-40A2-8057-86542A0353BB}</ProjectGuid>
- <OutputType>Library</OutputType>
+ <OutputType>Exe</OutputType>
<RootNamespace>Grpc.Core.Tests</RootNamespace>
<AssemblyName>Grpc.Core.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
@@ -35,29 +35,18 @@
<AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="nunit.core">
- <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll</HintPath>
- <Private>False</Private>
- </Reference>
- <Reference Include="nunit.core.interfaces">
- <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll</HintPath>
- <Private>False</Private>
- </Reference>
+ <Reference Include="System" />
<Reference Include="nunit.framework">
- <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
+ <HintPath>..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll</HintPath>
</Reference>
- <Reference Include="nunit.util">
- <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll</HintPath>
- <Private>False</Private>
+ <Reference Include="System.Interactive.Async">
+ <HintPath>..\packages\Ix-Async.1.2.5\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
- <Reference Include="NUnit.VisualStudio.TestAdapter">
- <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll</HintPath>
- <Private>False</Private>
+ <Reference Include="nunitlite">
+ <HintPath>..\packages\NUnitLite.3.2.0\lib\net45\nunitlite.dll</HintPath>
</Reference>
- <Reference Include="System" />
- <Reference Include="System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Ix-Async.1.2.5\lib\net45\System.Interactive.Async.dll</HintPath>
+ <Reference Include="Newtonsoft.Json">
+ <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -93,6 +82,10 @@
<Compile Include="MetadataTest.cs" />
<Compile Include="PerformanceTest.cs" />
<Compile Include="SanityTest.cs" />
+ <Compile Include="HalfcloseTest.cs" />
+ <Compile Include="NUnitMain.cs" />
+ <Compile Include="Internal\FakeNativeCall.cs" />
+ <Compile Include="Internal\AsyncCallServerTest.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
index fac93fcc5c..6fe382751a 100644
--- a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
+++ b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
#endregion
using System;
-using System.Threading;
+using System.Linq;
using Grpc.Core;
using NUnit.Framework;
@@ -44,7 +44,11 @@ namespace Grpc.Core.Tests
public void InitializeAndShutdownGrpcEnvironment()
{
var env = GrpcEnvironment.AddRef();
- Assert.IsNotNull(env.CompletionQueue);
+ Assert.IsTrue(env.CompletionQueues.Count > 0);
+ for (int i = 0; i < env.CompletionQueues.Count; i++)
+ {
+ Assert.IsNotNull(env.CompletionQueues.ElementAt(i));
+ }
GrpcEnvironment.Release();
}
diff --git a/src/csharp/Grpc.Core.Tests/HalfcloseTest.cs b/src/csharp/Grpc.Core.Tests/HalfcloseTest.cs
new file mode 100644
index 0000000000..b4cb451d94
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/HalfcloseTest.cs
@@ -0,0 +1,97 @@
+#region Copyright notice and license
+
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class HalfcloseTest
+ {
+ MockServiceHelper helper;
+ Server server;
+ Channel channel;
+
+ [SetUp]
+ public void Init()
+ {
+ helper = new MockServiceHelper();
+
+ server = helper.GetServer();
+ server.Start();
+ channel = helper.GetChannel();
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ channel.ShutdownAsync().Wait();
+ server.ShutdownAsync().Wait();
+ }
+
+ /// <summary>
+ /// For client streaming and duplex streaming calls, if server does a full close
+ /// before we halfclose the request stream, an attempt to halfclose
+ /// (complete the request stream) shouldn't be treated as an error.
+ /// </summary>
+ [Test]
+ public async Task HalfcloseAfterFullclose_ClientStreamingCall()
+ {
+ helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
+ {
+ return "PASS";
+ });
+
+ var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
+ // make sure server has fullclosed on us
+ Assert.AreEqual("PASS", await call.ResponseAsync);
+
+ // sending close from client should be still fine because server can finish
+ // the call anytime and we cannot do anything about it on the client side.
+ await call.RequestStream.CompleteAsync();
+
+ // Second attempt to close from client is not allowed.
+ Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await call.RequestStream.CompleteAsync());
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
new file mode 100644
index 0000000000..c35aaf680f
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
@@ -0,0 +1,201 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+using Grpc.Core.Internal;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+ /// <summary>
+ /// Uses fake native call to test interaction of <c>AsyncCallServer</c> wrapping code with C core in different situations.
+ /// </summary>
+ public class AsyncCallServerTest
+ {
+ Server server;
+ FakeNativeCall fakeCall;
+ AsyncCallServer<string, string> asyncCallServer;
+
+ [SetUp]
+ public void Init()
+ {
+ // Create a fake server just so we have an instance to refer to.
+ // The server won't actually be used at all.
+ server = new Server()
+ {
+ Ports = { { "localhost", 0, ServerCredentials.Insecure } }
+ };
+ server.Start();
+
+ fakeCall = new FakeNativeCall();
+ asyncCallServer = new AsyncCallServer<string, string>(
+ Marshallers.StringMarshaller.Serializer, Marshallers.StringMarshaller.Deserializer,
+ server);
+ asyncCallServer.InitializeForTesting(fakeCall);
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ server.ShutdownAsync().Wait();
+ }
+
+ [Test]
+ public void CancelNotificationAfterStartDisposes()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void CancelNotificationAfterStartDisposesAfterPendingReadFinishes()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
+
+ var moveNextTask = requestStream.MoveNext();
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+ fakeCall.ReceivedMessageHandler(true, null);
+ Assert.IsFalse(moveNextTask.Result);
+
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void ReadAfterCancelNotificationCanSucceed()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+
+ // Check that starting a read after cancel notification has been processed is legal.
+ var moveNextTask = requestStream.MoveNext();
+ Assert.IsFalse(moveNextTask.Result);
+
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void ReadCompletionFailureClosesRequestStream()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
+
+ // if a read completion's success==false, the request stream will silently finish
+ // and we rely on C core cancelling the call.
+ var moveNextTask = requestStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(false, null);
+ Assert.IsFalse(moveNextTask.Result);
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void WriteAfterCancelNotificationFails()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+
+ // TODO(jtattermusch): should we throw a different exception type instead?
+ Assert.Throws(typeof(InvalidOperationException), () => responseStream.WriteAsync("request1"));
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void WriteCompletionFailureThrows()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
+
+ var writeTask = responseStream.WriteAsync("request1");
+ fakeCall.SendCompletionHandler(false);
+ // TODO(jtattermusch): should we throw a different exception type instead?
+ Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await writeTask);
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void WriteAndWriteStatusCanRunConcurrently()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
+
+ var writeTask = responseStream.WriteAsync("request1");
+ var writeStatusTask = asyncCallServer.SendStatusFromServerAsync(Status.DefaultSuccess, new Metadata(), null);
+
+ fakeCall.SendCompletionHandler(true);
+ fakeCall.SendStatusFromServerHandler(true);
+
+ Assert.DoesNotThrowAsync(async () => await writeTask);
+ Assert.DoesNotThrowAsync(async () => await writeStatusTask);
+
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ [Test]
+ public void WriteAfterWriteStatusThrowsInvalidOperationException()
+ {
+ var finishedTask = asyncCallServer.ServerSideCallAsync();
+ var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
+
+ asyncCallServer.SendStatusFromServerAsync(Status.DefaultSuccess, new Metadata(), null);
+ Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await responseStream.WriteAsync("request1"));
+
+ fakeCall.SendStatusFromServerHandler(true);
+ fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+
+ AssertFinished(asyncCallServer, fakeCall, finishedTask);
+ }
+
+ static void AssertFinished(AsyncCallServer<string, string> asyncCallServer, FakeNativeCall fakeCall, Task finishedTask)
+ {
+ Assert.IsTrue(fakeCall.IsDisposed);
+ Assert.IsTrue(finishedTask.IsCompleted);
+ Assert.DoesNotThrow(() => finishedTask.Wait());
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
index d5a1eeb0fb..81897f8c77 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
#endregion
using System;
-using System.Runtime.InteropServices;
+using System.Collections.Generic;
using System.Threading.Tasks;
using Grpc.Core.Internal;
@@ -40,6 +40,9 @@ using NUnit.Framework;
namespace Grpc.Core.Internal.Tests
{
+ /// <summary>
+ /// Uses fake native call to test interaction of <c>AsyncCall</c> wrapping code with C core in different situations.
+ /// </summary>
public class AsyncCallTest
{
Channel channel;
@@ -64,159 +67,468 @@ namespace Grpc.Core.Internal.Tests
}
[Test]
- public void AsyncUnary_CompletionSuccess()
+ public void AsyncUnary_CanBeStartedOnlyOnce()
+ {
+ asyncCall.UnaryCallAsync("request1");
+ Assert.Throws(typeof(InvalidOperationException),
+ () => asyncCall.UnaryCallAsync("abc"));
+ }
+
+ [Test]
+ public void AsyncUnary_StreamingOperationsNotAllowed()
+ {
+ asyncCall.UnaryCallAsync("request1");
+ Assert.ThrowsAsync(typeof(InvalidOperationException),
+ async () => await asyncCall.ReadMessageAsync());
+ Assert.Throws(typeof(InvalidOperationException),
+ () => asyncCall.SendMessageAsync("abc", new WriteFlags()));
+ }
+
+ [Test]
+ public void AsyncUnary_Success()
+ {
+ var resultTask = asyncCall.UnaryCallAsync("request1");
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+ }
+
+ [Test]
+ public void AsyncUnary_NonSuccessStatusCode()
+ {
+ var resultTask = asyncCall.UnaryCallAsync("request1");
+ fakeCall.UnaryResponseClientHandler(true,
+ CreateClientSideStatus(StatusCode.InvalidArgument),
+ null,
+ new Metadata());
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.InvalidArgument);
+ }
+
+ [Test]
+ public void AsyncUnary_NullResponsePayload()
+ {
+ var resultTask = asyncCall.UnaryCallAsync("request1");
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ null,
+ new Metadata());
+
+ // failure to deserialize will result in InvalidArgument status.
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Internal);
+ }
+
+ [Test]
+ public void ClientStreaming_StreamingReadNotAllowed()
+ {
+ asyncCall.ClientStreamingCallAsync();
+ Assert.ThrowsAsync(typeof(InvalidOperationException),
+ async () => await asyncCall.ReadMessageAsync());
+ }
+
+ [Test]
+ public void ClientStreaming_NoRequest_Success()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+ }
+
+ [Test]
+ public void ClientStreaming_NoRequest_NonSuccessStatusCode()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ fakeCall.UnaryResponseClientHandler(true,
+ CreateClientSideStatus(StatusCode.InvalidArgument),
+ null,
+ new Metadata());
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.InvalidArgument);
+ }
+
+ [Test]
+ public void ClientStreaming_MoreRequests_Success()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ fakeCall.SendCompletionHandler(true);
+ writeTask.Wait();
+
+ var writeTask2 = requestStream.WriteAsync("request2");
+ fakeCall.SendCompletionHandler(true);
+ writeTask2.Wait();
+
+ var completeTask = requestStream.CompleteAsync();
+ fakeCall.SendCompletionHandler(true);
+ completeTask.Wait();
+
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+ }
+
+ [Test]
+ public void ClientStreaming_WriteCompletionFailure()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ fakeCall.SendCompletionHandler(false);
+ // TODO: maybe IOException or waiting for RPCException is more appropriate here.
+ Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await writeTask);
+
+ fakeCall.UnaryResponseClientHandler(true,
+ CreateClientSideStatus(StatusCode.Internal),
+ null,
+ new Metadata());
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Internal);
+ }
+
+ [Test]
+ public void ClientStreaming_WriteAfterReceivingStatusThrowsRpcException()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
+ Assert.AreEqual(Status.DefaultSuccess, ex.Status);
+ }
+
+ [Test]
+ public void ClientStreaming_WriteAfterReceivingStatusThrowsRpcException2()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(new Status(StatusCode.OutOfRange, ""), new Metadata()),
+ null,
+ new Metadata());
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.OutOfRange);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
+ Assert.AreEqual(StatusCode.OutOfRange, ex.Status.StatusCode);
+ }
+
+ [Test]
+ public void ClientStreaming_WriteAfterCompleteThrowsInvalidOperationException()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ requestStream.CompleteAsync();
+
+ Assert.Throws(typeof(InvalidOperationException), () => requestStream.WriteAsync("request1"));
+
+ fakeCall.SendCompletionHandler(true);
+
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+ }
+
+ [Test]
+ public void ClientStreaming_CompleteAfterReceivingStatusSucceeds()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ fakeCall.UnaryResponseClientHandler(true,
+ new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
+ CreateResponsePayload(),
+ new Metadata());
+
+ AssertUnaryResponseSuccess(asyncCall, fakeCall, resultTask);
+ Assert.DoesNotThrowAsync(async () => await requestStream.CompleteAsync());
+ }
+
+ [Test]
+ public void ClientStreaming_WriteAfterCancellationRequestThrowsTaskCanceledException()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ asyncCall.Cancel();
+ Assert.IsTrue(fakeCall.IsCancelled);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await writeTask);
+
+ fakeCall.UnaryResponseClientHandler(true,
+ CreateClientSideStatus(StatusCode.Cancelled),
+ null,
+ new Metadata());
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Cancelled);
+ }
+
+ [Test]
+ public void ServerStreaming_StreamingSendNotAllowed()
+ {
+ asyncCall.StartServerStreamingCall("request1");
+ Assert.Throws(typeof(InvalidOperationException),
+ () => asyncCall.SendMessageAsync("abc", new WriteFlags()));
+ }
+
+ [Test]
+ public void ServerStreaming_NoResponse_Success1()
+ {
+ asyncCall.StartServerStreamingCall("request1");
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+ var readTask = responseStream.MoveNext();
+
+ fakeCall.ReceivedResponseHeadersHandler(true, new Metadata());
+ Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count);
+
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
+ }
+
+ [Test]
+ public void ServerStreaming_NoResponse_Success2()
+ {
+ asyncCall.StartServerStreamingCall("request1");
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+ var readTask = responseStream.MoveNext();
+
+ // try alternative order of completions
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+ fakeCall.ReceivedMessageHandler(true, null);
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
+ }
+
+ [Test]
+ public void ServerStreaming_NoResponse_ReadFailure()
+ {
+ asyncCall.StartServerStreamingCall("request1");
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+ var readTask = responseStream.MoveNext();
+
+ fakeCall.ReceivedMessageHandler(false, null); // after a failed read, we rely on C core to deliver appropriate status code.
+ fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Internal));
+
+ AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Internal);
+ }
+
+ [Test]
+ public void ServerStreaming_MoreResponses_Success()
+ {
+ asyncCall.StartServerStreamingCall("request1");
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var readTask1 = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+ Assert.IsTrue(readTask1.Result);
+ Assert.AreEqual("response1", responseStream.Current);
+
+ var readTask2 = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+ Assert.IsTrue(readTask2.Result);
+ Assert.AreEqual("response1", responseStream.Current);
+
+ var readTask3 = responseStream.MoveNext();
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+ fakeCall.ReceivedMessageHandler(true, null);
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask3);
+ }
+
+ [Test]
+ public void DuplexStreaming_NoRequestNoResponse_Success()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var writeTask1 = requestStream.CompleteAsync();
+ fakeCall.SendCompletionHandler(true);
+ Assert.DoesNotThrowAsync(async () => await writeTask1);
+
+ var readTask = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
+ }
+
+ [Test]
+ public void DuplexStreaming_WriteAfterReceivingStatusThrowsRpcException()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var readTask = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
+ Assert.AreEqual(Status.DefaultSuccess, ex.Status);
+ }
+
+ [Test]
+ public void DuplexStreaming_CompleteAfterReceivingStatusSuceeds()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var readTask = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+
+ AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
+
+ Assert.DoesNotThrowAsync(async () => await requestStream.CompleteAsync());
+ }
+
+ [Test]
+ public void DuplexStreaming_WriteAfterCancellationRequestThrowsTaskCanceledException()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ asyncCall.Cancel();
+ Assert.IsTrue(fakeCall.IsCancelled);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await writeTask);
+
+ var readTask = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
+
+ AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Cancelled);
+ }
+
+ [Test]
+ public void DuplexStreaming_ReadAfterCancellationRequestCanSucceed()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ asyncCall.Cancel();
+ Assert.IsTrue(fakeCall.IsCancelled);
+
+ var readTask1 = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+ Assert.IsTrue(readTask1.Result);
+ Assert.AreEqual("response1", responseStream.Current);
+
+ var readTask2 = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
+
+ AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
+ }
+
+ [Test]
+ public void DuplexStreaming_ReadStartedBeforeCancellationRequestCanSucceed()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var readTask1 = responseStream.MoveNext(); // initiate the read before cancel request
+ asyncCall.Cancel();
+ Assert.IsTrue(fakeCall.IsCancelled);
+
+ fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+ Assert.IsTrue(readTask1.Result);
+ Assert.AreEqual("response1", responseStream.Current);
+
+ var readTask2 = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
+
+ AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
+ }
+
+ ClientSideStatus CreateClientSideStatus(StatusCode statusCode)
+ {
+ return new ClientSideStatus(new Status(statusCode, ""), new Metadata());
+ }
+
+ byte[] CreateResponsePayload()
+ {
+ return Marshallers.StringMarshaller.Serializer("response1");
+ }
+
+ static void AssertUnaryResponseSuccess(AsyncCall<string, string> asyncCall, FakeNativeCall fakeCall, Task<string> resultTask)
{
- var resultTask = asyncCall.UnaryCallAsync("abc");
- fakeCall.UnaryResponseClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()), new byte[] { 1, 2, 3 }, new Metadata());
Assert.IsTrue(resultTask.IsCompleted);
Assert.IsTrue(fakeCall.IsDisposed);
+
Assert.AreEqual(Status.DefaultSuccess, asyncCall.GetStatus());
+ Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count);
+ Assert.AreEqual(0, asyncCall.GetTrailers().Count);
+ Assert.AreEqual("response1", resultTask.Result);
}
- [Test]
- public void AsyncUnary_CompletionFailure()
+ static void AssertStreamingResponseSuccess(AsyncCall<string, string> asyncCall, FakeNativeCall fakeCall, Task<bool> moveNextTask)
{
- var resultTask = asyncCall.UnaryCallAsync("abc");
- fakeCall.UnaryResponseClientHandler(false, new ClientSideStatus(new Status(StatusCode.Internal, ""), null), new byte[] { 1, 2, 3 }, new Metadata());
+ Assert.IsTrue(moveNextTask.IsCompleted);
+ Assert.IsTrue(fakeCall.IsDisposed);
+
+ Assert.IsFalse(moveNextTask.Result);
+ Assert.AreEqual(Status.DefaultSuccess, asyncCall.GetStatus());
+ Assert.AreEqual(0, asyncCall.GetTrailers().Count);
+ }
+ static void AssertUnaryResponseError(AsyncCall<string, string> asyncCall, FakeNativeCall fakeCall, Task<string> resultTask, StatusCode expectedStatusCode)
+ {
Assert.IsTrue(resultTask.IsCompleted);
Assert.IsTrue(fakeCall.IsDisposed);
- Assert.AreEqual(StatusCode.Internal, asyncCall.GetStatus().StatusCode);
- Assert.IsNull(asyncCall.GetTrailers());
- var ex = Assert.Throws<RpcException>(() => resultTask.GetAwaiter().GetResult());
- Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
- }
-
- internal class FakeNativeCall : INativeCall
- {
- public UnaryResponseClientHandler UnaryResponseClientHandler
- {
- get;
- set;
- }
-
- public ReceivedStatusOnClientHandler ReceivedStatusOnClientHandler
- {
- get;
- set;
- }
-
- public ReceivedMessageHandler ReceivedMessageHandler
- {
- get;
- set;
- }
-
- public ReceivedResponseHeadersHandler ReceivedResponseHeadersHandler
- {
- get;
- set;
- }
-
- public SendCompletionHandler SendCompletionHandler
- {
- get;
- set;
- }
-
- public ReceivedCloseOnServerHandler ReceivedCloseOnServerHandler
- {
- get;
- set;
- }
-
- public bool IsCancelled
- {
- get;
- set;
- }
-
- public bool IsDisposed
- {
- get;
- set;
- }
-
- public void Cancel()
- {
- IsCancelled = true;
- }
-
- public void CancelWithStatus(Status status)
- {
- IsCancelled = true;
- }
-
- public string GetPeer()
- {
- return "PEER";
- }
-
- public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
- {
- UnaryResponseClientHandler = callback;
- }
-
- public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
- {
- throw new NotImplementedException();
- }
-
- public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray)
- {
- UnaryResponseClientHandler = callback;
- }
-
- public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
- {
- ReceivedStatusOnClientHandler = callback;
- }
-
- public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray)
- {
- ReceivedStatusOnClientHandler = callback;
- }
-
- public void StartReceiveMessage(ReceivedMessageHandler callback)
- {
- ReceivedMessageHandler = callback;
- }
-
- public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback)
- {
- ReceivedResponseHeadersHandler = callback;
- }
-
- public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray)
- {
- SendCompletionHandler = callback;
- }
-
- public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
- {
- SendCompletionHandler = callback;
- }
-
- public void StartSendCloseFromClient(SendCompletionHandler callback)
- {
- SendCompletionHandler = callback;
- }
-
- public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata)
- {
- SendCompletionHandler = callback;
- }
-
- public void StartServerSide(ReceivedCloseOnServerHandler callback)
- {
- ReceivedCloseOnServerHandler = callback;
- }
-
- public void Dispose()
- {
- IsDisposed = true;
- }
+ Assert.AreEqual(expectedStatusCode, asyncCall.GetStatus().StatusCode);
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await resultTask);
+ Assert.AreEqual(expectedStatusCode, ex.Status.StatusCode);
+ Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count);
+ Assert.AreEqual(0, asyncCall.GetTrailers().Count);
+ }
+
+ static void AssertStreamingResponseError(AsyncCall<string, string> asyncCall, FakeNativeCall fakeCall, Task<bool> moveNextTask, StatusCode expectedStatusCode)
+ {
+ Assert.IsTrue(moveNextTask.IsCompleted);
+ Assert.IsTrue(fakeCall.IsDisposed);
+
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await moveNextTask);
+ Assert.AreEqual(expectedStatusCode, ex.Status.StatusCode);
+ Assert.AreEqual(expectedStatusCode, asyncCall.GetStatus().StatusCode);
+ Assert.AreEqual(0, asyncCall.GetTrailers().Count);
}
}
}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
index c6843f10af..195119f920 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
@@ -60,7 +60,7 @@ namespace Grpc.Core.Internal.Tests
var ev = cq.Next();
cq.Dispose();
GrpcEnvironment.Release();
- Assert.AreEqual(GRPCCompletionType.Shutdown, ev.type);
+ Assert.AreEqual(CompletionQueueEvent.CompletionType.Shutdown, ev.type);
Assert.AreNotEqual(IntPtr.Zero, ev.success);
Assert.AreEqual(IntPtr.Zero, ev.tag);
}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
new file mode 100644
index 0000000000..909112a47c
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
@@ -0,0 +1,184 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+using Grpc.Core.Internal;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+ /// <summary>
+ /// For testing purposes.
+ /// </summary>
+ internal class FakeNativeCall : INativeCall
+ {
+ public UnaryResponseClientHandler UnaryResponseClientHandler
+ {
+ get;
+ set;
+ }
+
+ public ReceivedStatusOnClientHandler ReceivedStatusOnClientHandler
+ {
+ get;
+ set;
+ }
+
+ public ReceivedMessageHandler ReceivedMessageHandler
+ {
+ get;
+ set;
+ }
+
+ public ReceivedResponseHeadersHandler ReceivedResponseHeadersHandler
+ {
+ get;
+ set;
+ }
+
+ public SendCompletionHandler SendCompletionHandler
+ {
+ get;
+ set;
+ }
+
+ public SendCompletionHandler SendStatusFromServerHandler
+ {
+ get;
+ set;
+ }
+
+ public ReceivedCloseOnServerHandler ReceivedCloseOnServerHandler
+ {
+ get;
+ set;
+ }
+
+ public bool IsCancelled
+ {
+ get;
+ set;
+ }
+
+ public bool IsDisposed
+ {
+ get;
+ set;
+ }
+
+ public void Cancel()
+ {
+ IsCancelled = true;
+ }
+
+ public void CancelWithStatus(Status status)
+ {
+ IsCancelled = true;
+ }
+
+ public string GetPeer()
+ {
+ return "PEER";
+ }
+
+ public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ {
+ UnaryResponseClientHandler = callback;
+ }
+
+ public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray)
+ {
+ UnaryResponseClientHandler = callback;
+ }
+
+ public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ {
+ ReceivedStatusOnClientHandler = callback;
+ }
+
+ public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray)
+ {
+ ReceivedStatusOnClientHandler = callback;
+ }
+
+ public void StartReceiveMessage(ReceivedMessageHandler callback)
+ {
+ ReceivedMessageHandler = callback;
+ }
+
+ public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback)
+ {
+ ReceivedResponseHeadersHandler = callback;
+ }
+
+ public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray)
+ {
+ SendCompletionHandler = callback;
+ }
+
+ public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
+ {
+ SendCompletionHandler = callback;
+ }
+
+ public void StartSendCloseFromClient(SendCompletionHandler callback)
+ {
+ SendCompletionHandler = callback;
+ }
+
+ public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
+ byte[] optionalPayload, WriteFlags writeFlags)
+ {
+ SendStatusFromServerHandler = callback;
+ }
+
+ public void StartServerSide(ReceivedCloseOnServerHandler callback)
+ {
+ ReceivedCloseOnServerHandler = callback;
+ }
+
+ public void Dispose()
+ {
+ IsDisposed = true;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
index 74f7f2497a..c124ea29af 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
@@ -61,15 +61,15 @@ namespace Grpc.Core.Internal.Tests
}
[Test]
- public void InfFuture()
+ public void InfFutureMatchesNativeValue()
{
- var timespec = Timespec.InfFuture;
+ Assert.AreEqual(Timespec.NativeInfFuture, Timespec.InfFuture);
}
[Test]
- public void InfPast()
+ public void InfPastMatchesNativeValue()
{
- var timespec = Timespec.InfPast;
+ Assert.AreEqual(Timespec.NativeInfPast, Timespec.InfPast);
}
[Test]
@@ -108,7 +108,7 @@ namespace Grpc.Core.Internal.Tests
Assert.Throws(typeof(InvalidOperationException),
() => new Timespec(0, 1000 * 1000 * 1000).ToDateTime());
Assert.Throws(typeof(InvalidOperationException),
- () => new Timespec(0, 0, GPRClockType.Monotonic).ToDateTime());
+ () => new Timespec(0, 0, ClockType.Monotonic).ToDateTime());
}
[Test]
diff --git a/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
index 37fb36946a..d770f82390 100644
--- a/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
@@ -112,7 +112,7 @@ namespace Grpc.Core.Tests
});
var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "REQUEST");
- var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.MoveNext());
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
}
@@ -134,7 +134,15 @@ namespace Grpc.Core.Tests
{
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
{
- Assert.Throws<IOException>(async () => await requestStream.MoveNext());
+ try
+ {
+ // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
+ await requestStream.MoveNext();
+ Assert.Fail();
+ }
+ catch (IOException)
+ {
+ }
return "RESPONSE";
});
@@ -153,7 +161,7 @@ namespace Grpc.Core.Tests
[Test]
public void RequestSerializationError_AsyncUnary()
{
- Assert.Throws<IOException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE"));
+ Assert.ThrowsAsync<IOException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE"));
}
[Test]
@@ -166,7 +174,7 @@ namespace Grpc.Core.Tests
});
var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
await call.RequestStream.WriteAsync("A");
- Assert.Throws<IOException>(async () => await call.RequestStream.WriteAsync("UNSERIALIZABLE_VALUE"));
+ Assert.ThrowsAsync<IOException>(async () => await call.RequestStream.WriteAsync("UNSERIALIZABLE_VALUE"));
await call.RequestStream.WriteAsync("B");
await call.RequestStream.CompleteAsync();
diff --git a/src/csharp/Grpc.Core.Tests/NUnitMain.cs b/src/csharp/Grpc.Core.Tests/NUnitMain.cs
new file mode 100644
index 0000000000..9c1d7bf3c8
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/NUnitMain.cs
@@ -0,0 +1,59 @@
+#region Copyright notice and license
+
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Reflection;
+using Grpc.Core;
+using Grpc.Core.Logging;
+using NUnit.Common;
+using NUnitLite;
+
+namespace Grpc.Core.Tests
+{
+ /// <summary>
+ /// Provides entry point for NUnitLite
+ /// </summary>
+ public class NUnitMain
+ {
+ public static int Main(string[] args)
+ {
+ // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
+ GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
+#if DOTNET5_4
+ return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
+#else
+ return new AutoRun().Execute(args);
+#endif
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
index da0ea2e6dc..d2b2fc6a66 100644
--- a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
+++ b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -74,6 +74,8 @@ namespace Grpc.Core.Tests
/// (~110ns .NET Windows)
/// </summary>
[Test]
+ [Category("Performance")]
+ [Ignore("Prevent running on Jenkins")]
public void NativeCallbackBenchmark()
{
OpCompletionDelegate handler = Handler;
@@ -95,6 +97,8 @@ namespace Grpc.Core.Tests
/// (~1.1us on .NET Windows)
/// </summary>
[Test]
+ [Category("Performance")]
+ [Ignore("Prevent running on Jenkins")]
public void NewNativeCallbackBenchmark()
{
counter = 0;
@@ -112,6 +116,8 @@ namespace Grpc.Core.Tests
/// (~46ns .NET Windows)
/// </summary>
[Test]
+ [Category("Performance")]
+ [Ignore("Prevent running on Jenkins")]
public void NopPInvokeBenchmark()
{
BenchmarkUtil.RunBenchmark(
diff --git a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs
index a1648f3671..772beadd4a 100644
--- a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs
@@ -155,7 +155,7 @@ namespace Grpc.Core.Tests
{
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{
- Assert.Throws(typeof(ArgumentNullException), async () => await context.WriteResponseHeadersAsync(null));
+ Assert.ThrowsAsync(typeof(ArgumentNullException), async () => await context.WriteResponseHeadersAsync(null));
return "PASS";
});
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index 343ab1e85a..3830f0cbac 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -38,6 +38,7 @@ using System.Reflection;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
+using Newtonsoft.Json;
using NUnit.Framework;
namespace Grpc.Core.Tests
@@ -55,27 +56,23 @@ namespace Grpc.Core.Tests
[Test]
public void TestsJsonUpToDate()
{
- var testClasses = DiscoverAllTestClasses();
- string testsJson = GetTestsJson();
+ var discoveredTests = DiscoverAllTestClasses();
+ string discoveredTestsJson = JsonConvert.SerializeObject(discoveredTests, Formatting.Indented);
- // we don't have a JSON parser at hand, but check that the test class
- // name is contained in the file instead.
- foreach (var className in testClasses) {
- Assert.IsTrue(testsJson.Contains(className),
- string.Format("Test class \"{0}\" is missing in C# tests.json file", className));
- }
+ Assert.AreEqual(discoveredTestsJson, ReadTestsJson());
}
/// <summary>
/// Gets list of all test classes obtained by inspecting all the test assemblies.
/// </summary>
- private List<string> DiscoverAllTestClasses()
+ private Dictionary<string, List<string>> DiscoverAllTestClasses()
{
var assemblies = GetTestAssemblies();
- var testClasses = new List<string>();
+ var testsByAssembly = new Dictionary<string, List<string>>();
foreach (var assembly in assemblies)
{
+ var testClasses = new List<string>();
foreach (var t in assembly.GetTypes())
{
foreach (var m in t.GetMethods())
@@ -89,16 +86,19 @@ namespace Grpc.Core.Tests
}
}
+ testClasses.Sort();
+ testsByAssembly.Add(assembly.GetName().Name, testClasses);
}
- testClasses.Sort();
- return testClasses;
+ return testsByAssembly;
}
- private string GetTestsJson()
+ /// <summary>
+ /// Reads contents of tests.json file.
+ /// </summary>
+ private string ReadTestsJson()
{
var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var testsJsonFile = Path.Combine(assemblyDir, "..", "..", "..", "tests.json");
-
return File.ReadAllText(testsJsonFile);
}
diff --git a/src/csharp/Grpc.Core.Tests/packages.config b/src/csharp/Grpc.Core.Tests/packages.config
index 610831dfe1..aa7d951fdc 100644
--- a/src/csharp/Grpc.Core.Tests/packages.config
+++ b/src/csharp/Grpc.Core.Tests/packages.config
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Ix-Async" version="1.2.5" targetFramework="net45" />
- <package id="NUnit" version="2.6.4" targetFramework="net45" />
- <package id="NUnitTestAdapter" version="2.0.0" targetFramework="net45" />
+ <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
+ <package id="NUnit" version="3.2.0" targetFramework="net45" />
+ <package id="NUnitLite" version="3.2.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs b/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs
index 5ba06d6509..1ad2290928 100644
--- a/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs
+++ b/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs
index 7cd41d0480..7476b0ca16 100644
--- a/src/csharp/Grpc.Core/CallCredentials.cs
+++ b/src/csharp/Grpc.Core/CallCredentials.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/CallInvocationDetails.cs b/src/csharp/Grpc.Core/CallInvocationDetails.cs
index 52bfbe6edb..98db854614 100644
--- a/src/csharp/Grpc.Core/CallInvocationDetails.cs
+++ b/src/csharp/Grpc.Core/CallInvocationDetails.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/CallInvoker.cs b/src/csharp/Grpc.Core/CallInvoker.cs
new file mode 100644
index 0000000000..39199b1fd5
--- /dev/null
+++ b/src/csharp/Grpc.Core/CallInvoker.cs
@@ -0,0 +1,84 @@
+#region Copyright notice and license
+
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System.Threading.Tasks;
+using Grpc.Core.Internal;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Abstraction of client-side RPC invocation.
+ /// </summary>
+ /// <seealso cref="Calls"/>
+ public abstract class CallInvoker
+ {
+ /// <summary>
+ /// Invokes a simple remote call in a blocking fashion.
+ /// </summary>
+ public abstract TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ where TRequest : class
+ where TResponse : class;
+
+ /// <summary>
+ /// Invokes a simple remote call asynchronously.
+ /// </summary>
+ public abstract AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ where TRequest : class
+ where TResponse : class;
+
+ /// <summary>
+ /// Invokes a server streaming call asynchronously.
+ /// In server streaming scenario, client sends on request and server responds with a stream of responses.
+ /// </summary>
+ public abstract AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ where TRequest : class
+ where TResponse : class;
+
+ /// <summary>
+ /// Invokes a client streaming call asynchronously.
+ /// In client streaming scenario, client sends a stream of requests and server responds with a single response.
+ /// </summary>
+ public abstract AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+ where TRequest : class
+ where TResponse : class;
+
+ /// <summary>
+ /// Invokes a duplex streaming call asynchronously.
+ /// In duplex streaming scenario, client sends a stream of requests and server responds with a stream of responses.
+ /// The response stream is completely independent and both side can be sending messages at the same time.
+ /// </summary>
+ public abstract AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+ where TRequest : class
+ where TResponse : class;
+ }
+}
diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs
index 7bd95d4ba8..9ca88849ee 100644
--- a/src/csharp/Grpc.Core/CallOptions.cs
+++ b/src/csharp/Grpc.Core/CallOptions.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -100,10 +100,7 @@ namespace Grpc.Core
/// </summary>
public WriteOptions WriteOptions
{
- get
- {
- return this.writeOptions;
- }
+ get { return this.writeOptions; }
}
/// <summary>
@@ -111,10 +108,7 @@ namespace Grpc.Core
/// </summary>
public ContextPropagationToken PropagationToken
{
- get
- {
- return this.propagationToken;
- }
+ get { return this.propagationToken; }
}
/// <summary>
@@ -122,10 +116,7 @@ namespace Grpc.Core
/// </summary>
public CallCredentials Credentials
{
- get
- {
- return this.credentials;
- }
+ get { return this.credentials; }
}
/// <summary>
@@ -165,6 +156,42 @@ namespace Grpc.Core
}
/// <summary>
+ /// Returns new instance of <see cref="CallOptions"/> with
+ /// <c>WriteOptions</c> set to the value provided. Values of all other fields are preserved.
+ /// </summary>
+ /// <param name="writeOptions">The write options.</param>
+ public CallOptions WithWriteOptions(WriteOptions writeOptions)
+ {
+ var newOptions = this;
+ newOptions.writeOptions = writeOptions;
+ return newOptions;
+ }
+
+ /// <summary>
+ /// Returns new instance of <see cref="CallOptions"/> with
+ /// <c>PropagationToken</c> set to the value provided. Values of all other fields are preserved.
+ /// </summary>
+ /// <param name="propagationToken">The context propagation token.</param>
+ public CallOptions WithPropagationToken(ContextPropagationToken propagationToken)
+ {
+ var newOptions = this;
+ newOptions.propagationToken = propagationToken;
+ return newOptions;
+ }
+
+ /// <summary>
+ /// Returns new instance of <see cref="CallOptions"/> with
+ /// <c>Credentials</c> set to the value provided. Values of all other fields are preserved.
+ /// </summary>
+ /// <param name="credentials">The call credentials.</param>
+ public CallOptions WithCredentials(CallCredentials credentials)
+ {
+ var newOptions = this;
+ newOptions.credentials = credentials;
+ return newOptions;
+ }
+
+ /// <summary>
/// Returns a new instance of <see cref="CallOptions"/> with
/// all previously unset values set to their defaults and deadline and cancellation
/// token propagated when appropriate.
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index d7a482d86f..886adfec33 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
using System;
using System.Collections.Generic;
-using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
@@ -51,9 +51,11 @@ namespace Grpc.Core
readonly object myLock = new object();
readonly AtomicCounter activeCallCounter = new AtomicCounter();
+ readonly CancellationTokenSource shutdownTokenSource = new CancellationTokenSource();
readonly string target;
readonly GrpcEnvironment environment;
+ readonly CompletionQueueSafeHandle completionQueue;
readonly ChannelSafeHandle handle;
readonly Dictionary<string, ChannelOption> options;
@@ -73,6 +75,7 @@ namespace Grpc.Core
EnsureUserAgentChannelOption(this.options);
this.environment = GrpcEnvironment.AddRef();
+ this.completionQueue = this.environment.PickCompletionQueue();
using (var nativeCredentials = credentials.ToNativeCredentials())
using (var nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options.Values))
{
@@ -101,12 +104,13 @@ namespace Grpc.Core
/// <summary>
/// Gets current connectivity state of this channel.
+ /// After channel is has been shutdown, <c>ChannelState.FatalFailure</c> will be returned.
/// </summary>
public ChannelState State
{
get
{
- return handle.CheckConnectivityState(false);
+ return GetConnectivityState(false);
}
}
@@ -132,7 +136,7 @@ namespace Grpc.Core
tcs.SetCanceled();
}
});
- handle.WatchConnectivityState(lastObservedState, deadlineTimespec, environment.CompletionQueue, environment.CompletionRegistry, handler);
+ handle.WatchConnectivityState(lastObservedState, deadlineTimespec, completionQueue, handler);
return tcs.Task;
}
@@ -155,6 +159,17 @@ namespace Grpc.Core
}
/// <summary>
+ /// Returns a token that gets cancelled once <c>ShutdownAsync</c> is invoked.
+ /// </summary>
+ public CancellationToken ShutdownToken
+ {
+ get
+ {
+ return this.shutdownTokenSource.Token;
+ }
+ }
+
+ /// <summary>
/// Allows explicitly requesting channel to connect without starting an RPC.
/// Returned task completes once state Ready was seen. If the deadline is reached,
/// or channel enters the FatalFailure state, the task is cancelled.
@@ -164,7 +179,7 @@ namespace Grpc.Core
/// <param name="deadline">The deadline. <c>null</c> indicates no deadline.</param>
public async Task ConnectAsync(DateTime? deadline = null)
{
- var currentState = handle.CheckConnectivityState(true);
+ var currentState = GetConnectivityState(true);
while (currentState != ChannelState.Ready)
{
if (currentState == ChannelState.FatalFailure)
@@ -172,7 +187,7 @@ namespace Grpc.Core
throw new OperationCanceledException("Channel has reached FatalFailure state.");
}
await WaitForStateChangedAsync(currentState, deadline).ConfigureAwait(false);
- currentState = handle.CheckConnectivityState(false);
+ currentState = GetConnectivityState(false);
}
}
@@ -188,6 +203,8 @@ namespace Grpc.Core
shutdownRequested = true;
}
+ shutdownTokenSource.Cancel();
+
var activeCallCount = activeCallCounter.Count;
if (activeCallCount > 0)
{
@@ -215,6 +232,14 @@ namespace Grpc.Core
}
}
+ internal CompletionQueueSafeHandle CompletionQueue
+ {
+ get
+ {
+ return this.completionQueue;
+ }
+ }
+
internal void AddCallReference(object call)
{
activeCallCounter.Increment();
@@ -231,6 +256,18 @@ namespace Grpc.Core
activeCallCounter.Decrement();
}
+ private ChannelState GetConnectivityState(bool tryToConnect)
+ {
+ try
+ {
+ return handle.CheckConnectivityState(tryToConnect);
+ }
+ catch (ObjectDisposedException)
+ {
+ return ChannelState.FatalFailure;
+ }
+ }
+
private static void EnsureUserAgentChannelOption(Dictionary<string, ChannelOption> options)
{
var key = ChannelOptions.PrimaryUserAgentString;
diff --git a/src/csharp/Grpc.Core/ChannelCredentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs
index 03cda28400..db0cefef8b 100644
--- a/src/csharp/Grpc.Core/ChannelCredentials.cs
+++ b/src/csharp/Grpc.Core/ChannelCredentials.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
index 65e15e21e9..b6eeceabc4 100644
--- a/src/csharp/Grpc.Core/ChannelOptions.cs
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index e5b398062b..5517233e3c 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -31,93 +31,156 @@
#endregion
-using System;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
- /// Interceptor for call headers.
+ /// Generic base class for client-side stubs.
/// </summary>
- /// <remarks>Header interceptor is no longer to recommented way to perform authentication.
- /// For header (initial metadata) based auth such as OAuth2 or JWT access token, use <see cref="MetadataCredentials"/>.
- /// </remarks>
- public delegate void HeaderInterceptor(IMethod method, Metadata metadata);
+ public abstract class ClientBase<T> : ClientBase
+ where T : ClientBase<T>
+ {
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class that
+ /// throws <c>NotImplementedException</c> upon invocation of any RPC.
+ /// This constructor is only provided to allow creation of test doubles
+ /// for client classes (e.g. mocking requires a parameterless constructor).
+ /// </summary>
+ protected ClientBase() : base()
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class.
+ /// </summary>
+ /// <param name="configuration">The configuration.</param>
+ protected ClientBase(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class.
+ /// </summary>
+ /// <param name="channel">The channel to use for remote call invocation.</param>
+ public ClientBase(Channel channel) : base(channel)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class.
+ /// </summary>
+ /// <param name="callInvoker">The <c>CallInvoker</c> for remote call invocation.</param>
+ public ClientBase(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+
+ /// <summary>
+ /// Creates a new client that sets host field for calls explicitly.
+ /// gRPC supports multiple "hosts" being served by a single server.
+ /// By default (if a client was not created by calling this method),
+ /// host <c>null</c> with the meaning "use default host" is used.
+ /// </summary>
+ public T WithHost(string host)
+ {
+ var newConfiguration = this.Configuration.WithHost(host);
+ return NewInstance(newConfiguration);
+ }
+
+ /// <summary>
+ /// Creates a new instance of client from given <c>ClientBaseConfiguration</c>.
+ /// </summary>
+ protected abstract T NewInstance(ClientBaseConfiguration configuration);
+ }
/// <summary>
/// Base class for client-side stubs.
/// </summary>
public abstract class ClientBase
{
- readonly Channel channel;
+ readonly ClientBaseConfiguration configuration;
+ readonly CallInvoker callInvoker;
+
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class that
+ /// throws <c>NotImplementedException</c> upon invocation of any RPC.
+ /// This constructor is only provided to allow creation of test doubles
+ /// for client classes (e.g. mocking requires a parameterless constructor).
+ /// </summary>
+ protected ClientBase() : this(new UnimplementedCallInvoker())
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class.
+ /// </summary>
+ /// <param name="configuration">The configuration.</param>
+ protected ClientBase(ClientBaseConfiguration configuration)
+ {
+ this.configuration = GrpcPreconditions.CheckNotNull(configuration, "configuration");
+ this.callInvoker = configuration.CreateDecoratedCallInvoker();
+ }
/// <summary>
/// Initializes a new instance of <c>ClientBase</c> class.
/// </summary>
/// <param name="channel">The channel to use for remote call invocation.</param>
- public ClientBase(Channel channel)
+ public ClientBase(Channel channel) : this(new DefaultCallInvoker(channel))
{
- this.channel = channel;
}
/// <summary>
- /// Can be used to register a custom header interceptor.
- /// The interceptor is invoked each time a new call on this client is started.
- /// It is not recommented to use header interceptor to add auth headers to RPC calls.
+ /// Initializes a new instance of <c>ClientBase</c> class.
/// </summary>
- /// <seealso cref="HeaderInterceptor"/>
- public HeaderInterceptor HeaderInterceptor
+ /// <param name="callInvoker">The <c>CallInvoker</c> for remote call invocation.</param>
+ public ClientBase(CallInvoker callInvoker) : this(new ClientBaseConfiguration(callInvoker, null))
{
- get;
- set;
}
/// <summary>
- /// gRPC supports multiple "hosts" being served by a single server.
- /// This property can be used to set the target host explicitly.
- /// By default, this will be set to <c>null</c> with the meaning
- /// "use default host".
+ /// Gets the call invoker.
/// </summary>
- public string Host
+ protected CallInvoker CallInvoker
{
- get;
- set;
+ get { return this.callInvoker; }
}
/// <summary>
- /// Channel associated with this client.
+ /// Gets the configuration.
/// </summary>
- public Channel Channel
+ internal ClientBaseConfiguration Configuration
{
- get
- {
- return this.channel;
- }
+ get { return this.configuration; }
}
/// <summary>
- /// Creates a new call to given method.
+ /// Represents configuration of ClientBase. The class itself is visible to
+ /// subclasses, but contents are marked as internal to make the instances opaque.
+ /// The verbose name of this class was chosen to make name clash in generated code
+ /// less likely.
/// </summary>
- /// <param name="method">The method to invoke.</param>
- /// <param name="options">The call options.</param>
- /// <typeparam name="TRequest">Request message type.</typeparam>
- /// <typeparam name="TResponse">Response message type.</typeparam>
- /// <returns>The call invocation details.</returns>
- protected CallInvocationDetails<TRequest, TResponse> CreateCall<TRequest, TResponse>(Method<TRequest, TResponse> method, CallOptions options)
- where TRequest : class
- where TResponse : class
+ protected internal class ClientBaseConfiguration
{
- var interceptor = HeaderInterceptor;
- if (interceptor != null)
+ readonly CallInvoker undecoratedCallInvoker;
+ readonly string host;
+
+ internal ClientBaseConfiguration(CallInvoker undecoratedCallInvoker, string host)
+ {
+ this.undecoratedCallInvoker = GrpcPreconditions.CheckNotNull(undecoratedCallInvoker);
+ this.host = host;
+ }
+
+ internal CallInvoker CreateDecoratedCallInvoker()
+ {
+ return new InterceptingCallInvoker(undecoratedCallInvoker, hostInterceptor: (h) => host);
+ }
+
+ internal ClientBaseConfiguration WithHost(string host)
{
- if (options.Headers == null)
- {
- options = options.WithHeaders(new Metadata());
- }
- interceptor(method, options.Headers);
+ GrpcPreconditions.CheckNotNull(host, "host");
+ return new ClientBaseConfiguration(this.undecoratedCallInvoker, host);
}
- return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
}
}
}
diff --git a/src/csharp/Grpc.Core/ContextPropagationToken.cs b/src/csharp/Grpc.Core/ContextPropagationToken.cs
index c0f638f837..935498246a 100644
--- a/src/csharp/Grpc.Core/ContextPropagationToken.cs
+++ b/src/csharp/Grpc.Core/ContextPropagationToken.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/DefaultCallInvoker.cs b/src/csharp/Grpc.Core/DefaultCallInvoker.cs
new file mode 100644
index 0000000000..1a99e41153
--- /dev/null
+++ b/src/csharp/Grpc.Core/DefaultCallInvoker.cs
@@ -0,0 +1,112 @@
+#region Copyright notice and license
+
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System.Threading.Tasks;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Invokes client RPCs using <see cref="Calls"/>.
+ /// </summary>
+ public class DefaultCallInvoker : CallInvoker
+ {
+ readonly Channel channel;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Grpc.Core.DefaultCallInvoker"/> class.
+ /// </summary>
+ /// <param name="channel">Channel to use.</param>
+ public DefaultCallInvoker(Channel channel)
+ {
+ this.channel = GrpcPreconditions.CheckNotNull(channel);
+ }
+
+ /// <summary>
+ /// Invokes a simple remote call in a blocking fashion.
+ /// </summary>
+ public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ {
+ var call = CreateCall(method, host, options);
+ return Calls.BlockingUnaryCall(call, request);
+ }
+
+ /// <summary>
+ /// Invokes a simple remote call asynchronously.
+ /// </summary>
+ public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ {
+ var call = CreateCall(method, host, options);
+ return Calls.AsyncUnaryCall(call, request);
+ }
+
+ /// <summary>
+ /// Invokes a server streaming call asynchronously.
+ /// In server streaming scenario, client sends on request and server responds with a stream of responses.
+ /// </summary>
+ public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ {
+ var call = CreateCall(method, host, options);
+ return Calls.AsyncServerStreamingCall(call, request);
+ }
+
+ /// <summary>
+ /// Invokes a client streaming call asynchronously.
+ /// In client streaming scenario, client sends a stream of requests and server responds with a single response.
+ /// </summary>
+ public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+ {
+ var call = CreateCall(method, host, options);
+ return Calls.AsyncClientStreamingCall(call);
+ }
+
+ /// <summary>
+ /// Invokes a duplex streaming call asynchronously.
+ /// In duplex streaming scenario, client sends a stream of requests and server responds with a stream of responses.
+ /// The response stream is completely independent and both side can be sending messages at the same time.
+ /// </summary>
+ public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+ {
+ var call = CreateCall(method, host, options);
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+
+ protected virtual CallInvocationDetails<TRequest, TResponse> CreateCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+ where TRequest : class
+ where TResponse : class
+ {
+ return new CallInvocationDetails<TRequest, TResponse>(channel, method, host, options);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 3189835ccd..a8b7b5f00d 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -58,6 +58,7 @@
<Compile Include="IServerStreamWriter.cs" />
<Compile Include="IAsyncStreamWriter.cs" />
<Compile Include="IAsyncStreamReader.cs" />
+ <Compile Include="Logging\TextWriterLogger.cs" />
<Compile Include="Logging\NullLogger.cs" />
<Compile Include="ServerPort.cs" />
<Compile Include="Version.cs" />
@@ -73,7 +74,6 @@
<Compile Include="Internal\CallSafeHandle.cs" />
<Compile Include="Internal\ChannelSafeHandle.cs" />
<Compile Include="Internal\CompletionQueueSafeHandle.cs" />
- <Compile Include="Internal\Enums.cs" />
<Compile Include="Internal\SafeHandleZeroIsInvalid.cs" />
<Compile Include="Internal\Timespec.cs" />
<Compile Include="Internal\GrpcThreadPool.cs" />
@@ -86,7 +86,6 @@
<Compile Include="Utils\BenchmarkUtil.cs" />
<Compile Include="ChannelCredentials.cs" />
<Compile Include="Internal\ChannelArgsSafeHandle.cs" />
- <Compile Include="Internal\AsyncCompletion.cs" />
<Compile Include="Internal\AsyncCallBase.cs" />
<Compile Include="Internal\AsyncCallServer.cs" />
<Compile Include="Internal\AsyncCall.cs" />
@@ -129,6 +128,14 @@
<Compile Include="Profiling\Profilers.cs" />
<Compile Include="Internal\DefaultSslRootsOverride.cs" />
<Compile Include="Utils\GrpcPreconditions.cs" />
+ <Compile Include="CallInvoker.cs" />
+ <Compile Include="DefaultCallInvoker.cs" />
+ <Compile Include="Internal\UnimplementedCallInvoker.cs" />
+ <Compile Include="Internal\InterceptingCallInvoker.cs" />
+ <Compile Include="Internal\ServerRpcNew.cs" />
+ <Compile Include="Internal\ClientSideStatus.cs" />
+ <Compile Include="Internal\ClockType.cs" />
+ <Compile Include="Internal\CallError.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Grpc.Core.nuspec" />
@@ -136,9 +143,7 @@
</ItemGroup>
<Import Project="NativeDeps.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <ItemGroup>
- <Folder Include="Resources\" />
- </ItemGroup>
+ <ItemGroup />
<ItemGroup>
<EmbeddedResource Include="..\..\..\etc\roots.pem">
<Link>Resources\roots.pem</Link>
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index 49bccb050e..0ada0049c2 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -16,7 +16,6 @@
<tags>gRPC RPC Protocol HTTP/2</tags>
<dependencies>
<dependency id="Ix-Async" version="1.2.5" />
- <dependency id="grpc.native.csharp" version="$version$" />
</dependencies>
</metadata>
<files>
@@ -24,5 +23,12 @@
<file src="bin/ReleaseSigned/Grpc.Core.pdb" target="lib/net45" />
<file src="bin/ReleaseSigned/Grpc.Core.xml" target="lib/net45" />
<file src="**\*.cs" target="src" />
+ <file src="Grpc.Core.targets" target="\build\net45\Grpc.Core.targets" />
+ <file src="windows_x86/grpc_csharp_ext.dll" target="/build/native/bin/windows_x86/grpc_csharp_ext.dll" />
+ <file src="windows_x64/grpc_csharp_ext.dll" target="/build/native/bin/windows_x64/grpc_csharp_ext.dll" />
+ <file src="linux_x86/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x86/libgrpc_csharp_ext.so" />
+ <file src="linux_x64/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x64/libgrpc_csharp_ext.so" />
+ <file src="macosx_x86/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x86/libgrpc_csharp_ext.dylib" />
+ <file src="macosx_x64/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x64/libgrpc_csharp_ext.dylib" />
</files>
</package>
diff --git a/src/csharp/grpc.native.csharp/grpc.native.csharp.targets b/src/csharp/Grpc.Core/Grpc.Core.targets
index 501fc50548..501fc50548 100644
--- a/src/csharp/grpc.native.csharp/grpc.native.csharp.targets
+++ b/src/csharp/Grpc.Core/Grpc.Core.targets
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 86b37b8660..18af1099f1 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -32,8 +32,9 @@
#endregion
using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Runtime.InteropServices;
-using System.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Logging;
using Grpc.Core.Utils;
@@ -45,17 +46,19 @@ namespace Grpc.Core
/// </summary>
public class GrpcEnvironment
{
- const int THREAD_POOL_SIZE = 4;
+ const int MinDefaultThreadPoolSize = 4;
static object staticLock = new object();
static GrpcEnvironment instance;
static int refCount;
+ static int? customThreadPoolSize;
+ static int? customCompletionQueueCount;
static ILogger logger = new ConsoleLogger();
readonly GrpcThreadPool threadPool;
- readonly CompletionRegistry completionRegistry;
readonly DebugStats debugStats = new DebugStats();
+ readonly AtomicCounter cqPickerCounter = new AtomicCounter();
bool isClosed;
/// <summary>
@@ -123,36 +126,68 @@ namespace Grpc.Core
}
/// <summary>
+ /// Sets the number of threads in the gRPC thread pool that polls for internal RPC events.
+ /// Can be only invoke before the <c>GrpcEnviroment</c> is started and cannot be changed afterwards.
+ /// Setting thread pool size is an advanced setting and you should only use it if you know what you are doing.
+ /// Most users should rely on the default value provided by gRPC library.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.
+ /// </summary>
+ public static void SetThreadPoolSize(int threadCount)
+ {
+ lock (staticLock)
+ {
+ GrpcPreconditions.CheckState(instance == null, "Can only be set before GrpcEnvironment is initialized");
+ GrpcPreconditions.CheckArgument(threadCount > 0, "threadCount needs to be a positive number");
+ customThreadPoolSize = threadCount;
+ }
+ }
+
+ /// <summary>
+ /// Sets the number of completion queues in the gRPC thread pool that polls for internal RPC events.
+ /// Can be only invoke before the <c>GrpcEnviroment</c> is started and cannot be changed afterwards.
+ /// Setting the number of completions queues is an advanced setting and you should only use it if you know what you are doing.
+ /// Most users should rely on the default value provided by gRPC library.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.
+ /// </summary>
+ public static void SetCompletionQueueCount(int completionQueueCount)
+ {
+ lock (staticLock)
+ {
+ GrpcPreconditions.CheckState(instance == null, "Can only be set before GrpcEnvironment is initialized");
+ GrpcPreconditions.CheckArgument(completionQueueCount > 0, "threadCount needs to be a positive number");
+ customCompletionQueueCount = completionQueueCount;
+ }
+ }
+
+ /// <summary>
/// Creates gRPC environment.
/// </summary>
private GrpcEnvironment()
{
GrpcNativeInit();
- completionRegistry = new CompletionRegistry(this);
- threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE);
+ threadPool = new GrpcThreadPool(this, GetThreadPoolSizeOrDefault(), GetCompletionQueueCountOrDefault());
threadPool.Start();
}
/// <summary>
- /// Gets the completion registry used by this gRPC environment.
+ /// Gets the completion queues used by this gRPC environment.
/// </summary>
- internal CompletionRegistry CompletionRegistry
+ internal IReadOnlyCollection<CompletionQueueSafeHandle> CompletionQueues
{
get
{
- return this.completionRegistry;
+ return this.threadPool.CompletionQueues;
}
}
/// <summary>
- /// Gets the completion queue used by this gRPC environment.
+ /// Picks a completion queue in a round-robin fashion.
+ /// Shouldn't be invoked on a per-call basis (used at per-channel basis).
/// </summary>
- internal CompletionQueueSafeHandle CompletionQueue
+ internal CompletionQueueSafeHandle PickCompletionQueue()
{
- get
- {
- return this.threadPool.CompletionQueue;
- }
+ var cqIndex = (int) ((cqPickerCounter.Increment() - 1) % this.threadPool.CompletionQueues.Count);
+ return this.threadPool.CompletionQueues.ElementAt(cqIndex);
}
/// <summary>
@@ -200,5 +235,27 @@ namespace Grpc.Core
debugStats.CheckOK();
}
+
+ private int GetThreadPoolSizeOrDefault()
+ {
+ if (customThreadPoolSize.HasValue)
+ {
+ return customThreadPoolSize.Value;
+ }
+ // In systems with many cores, use half of the cores for GrpcThreadPool
+ // and the other half for .NET thread pool. This heuristic definitely needs
+ // more work, but seems to work reasonably well for a start.
+ return Math.Max(MinDefaultThreadPoolSize, Environment.ProcessorCount / 2);
+ }
+
+ private int GetCompletionQueueCountOrDefault()
+ {
+ if (customCompletionQueueCount.HasValue)
+ {
+ return customCompletionQueueCount.Value;
+ }
+ // by default, create a completion queue for each thread
+ return GetThreadPoolSizeOrDefault();
+ }
}
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 2caba260b3..895be690a5 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,7 @@
#endregion
using System;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
using System.Threading.Tasks;
-using Grpc.Core.Internal;
using Grpc.Core.Logging;
using Grpc.Core.Profiling;
using Grpc.Core.Utils;
@@ -57,9 +52,11 @@ namespace Grpc.Core.Internal
// Completion of a pending unary response if not null.
TaskCompletionSource<TResponse> unaryResponseTcs;
- // Indicates that steaming call has finished.
+ // TODO(jtattermusch): this field doesn't need to be initialized for unary response calls.
+ // Indicates that response streaming call has finished.
TaskCompletionSource<object> streamingCallFinishedTcs = new TaskCompletionSource<object>();
+ // TODO(jtattermusch): this field could be lazy-initialized (only if someone requests the response headers).
// Response headers set here once received.
TaskCompletionSource<Metadata> responseHeadersTcs = new TaskCompletionSource<Metadata>();
@@ -67,7 +64,7 @@ namespace Grpc.Core.Internal
ClientSideStatus? finishedStatus;
public AsyncCall(CallInvocationDetails<TRequest, TResponse> callDetails)
- : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer, callDetails.Channel.Environment)
+ : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer)
{
this.details = callDetails.WithOptions(callDetails.Options.Normalize());
this.initialMetadataSent = true; // we always send metadata at the very beginning of the call.
@@ -144,7 +141,7 @@ namespace Grpc.Core.Internal
GrpcPreconditions.CheckState(!started);
started = true;
- Initialize(environment.CompletionQueue);
+ Initialize(details.Channel.CompletionQueue);
halfcloseRequested = true;
readingDone = true;
@@ -171,7 +168,7 @@ namespace Grpc.Core.Internal
GrpcPreconditions.CheckState(!started);
started = true;
- Initialize(environment.CompletionQueue);
+ Initialize(details.Channel.CompletionQueue);
readingDone = true;
@@ -195,7 +192,7 @@ namespace Grpc.Core.Internal
GrpcPreconditions.CheckState(!started);
started = true;
- Initialize(environment.CompletionQueue);
+ Initialize(details.Channel.CompletionQueue);
halfcloseRequested = true;
@@ -220,7 +217,7 @@ namespace Grpc.Core.Internal
GrpcPreconditions.CheckState(!started);
started = true;
- Initialize(environment.CompletionQueue);
+ Initialize(details.Channel.CompletionQueue);
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
@@ -232,38 +229,49 @@ namespace Grpc.Core.Internal
/// <summary>
/// Sends a streaming request. Only one pending send action is allowed at any given time.
- /// completionDelegate is called when the operation finishes.
/// </summary>
- public void StartSendMessage(TRequest msg, WriteFlags writeFlags, AsyncCompletionDelegate<object> completionDelegate)
+ public Task SendMessageAsync(TRequest msg, WriteFlags writeFlags)
{
- StartSendMessageInternal(msg, writeFlags, completionDelegate);
+ return SendMessageInternalAsync(msg, writeFlags);
}
/// <summary>
/// Receives a streaming response. Only one pending read action is allowed at any given time.
- /// completionDelegate is called when the operation finishes.
/// </summary>
- public void StartReadMessage(AsyncCompletionDelegate<TResponse> completionDelegate)
+ public Task<TResponse> ReadMessageAsync()
{
- StartReadMessageInternal(completionDelegate);
+ return ReadMessageInternalAsync();
}
/// <summary>
/// Sends halfclose, indicating client is done with streaming requests.
/// Only one pending send action is allowed at any given time.
- /// completionDelegate is called when the operation finishes.
/// </summary>
- public void StartSendCloseFromClient(AsyncCompletionDelegate<object> completionDelegate)
+ public Task SendCloseFromClientAsync()
{
lock (myLock)
{
- GrpcPreconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null");
- CheckSendingAllowed();
+ GrpcPreconditions.CheckState(started);
- call.StartSendCloseFromClient(HandleHalfclosed);
+ var earlyResult = CheckSendPreconditionsClientSide();
+ if (earlyResult != null)
+ {
+ return earlyResult;
+ }
+
+ if (disposed || finished)
+ {
+ // In case the call has already been finished by the serverside,
+ // the halfclose has already been done implicitly, so just return
+ // completed task here.
+ halfcloseRequested = true;
+ return Task.FromResult<object>(null);
+ }
+ call.StartSendCloseFromClient(HandleSendCloseFromClientFinished);
halfcloseRequested = true;
- sendCompletionDelegate = completionDelegate;
+ streamingWriteTcs = new TaskCompletionSource<object>();
+ return streamingWriteTcs.Task;
}
}
@@ -333,6 +341,45 @@ namespace Grpc.Core.Internal
get { return true; }
}
+ protected override Task CheckSendAllowedOrEarlyResult()
+ {
+ var earlyResult = CheckSendPreconditionsClientSide();
+ if (earlyResult != null)
+ {
+ return earlyResult;
+ }
+
+ if (finishedStatus.HasValue)
+ {
+ // throwing RpcException if we already received status on client
+ // side makes the most sense.
+ // Note that this throws even for StatusCode.OK.
+ // Writing after the call has finished is not a programming error because server can close
+ // the call anytime, so don't throw directly, but let the write task finish with an error.
+ var tcs = new TaskCompletionSource<object>();
+ tcs.SetException(new RpcException(finishedStatus.Value.Status));
+ return tcs.Task;
+ }
+
+ return null;
+ }
+
+ private Task CheckSendPreconditionsClientSide()
+ {
+ GrpcPreconditions.CheckState(!halfcloseRequested, "Request stream has already been completed.");
+ GrpcPreconditions.CheckState(streamingWriteTcs == null, "Only one write can be pending at a time.");
+
+ if (cancelRequested)
+ {
+ // Return a cancelled task.
+ var tcs = new TaskCompletionSource<object>();
+ tcs.SetCanceled();
+ return tcs.Task;
+ }
+
+ return null;
+ }
+
private void Initialize(CompletionQueueSafeHandle cq)
{
using (Profilers.ForCurrentThread().NewScope("AsyncCall.Initialize"))
@@ -359,7 +406,7 @@ namespace Grpc.Core.Internal
var credentials = details.Options.Credentials;
using (var nativeCredentials = credentials != null ? credentials.ToNativeCredentials() : null)
{
- var result = details.Channel.Handle.CreateCall(environment.CompletionRegistry,
+ var result = details.Channel.Handle.CreateCall(
parentCall, ContextPropagationToken.DefaultMask, cq,
details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value), nativeCredentials);
return result;
@@ -391,6 +438,7 @@ namespace Grpc.Core.Internal
/// </summary>
private void HandleReceivedResponseHeaders(bool success, Metadata responseHeaders)
{
+ // TODO(jtattermusch): handle success==false
responseHeadersTcs.SetResult(responseHeaders);
}
@@ -399,10 +447,13 @@ namespace Grpc.Core.Internal
/// </summary>
private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders)
{
+ // NOTE: because this event is a result of batch containing GRPC_OP_RECV_STATUS_ON_CLIENT,
+ // success will be always set to true.
+
using (Profilers.ForCurrentThread().NewScope("AsyncCall.HandleUnaryResponse"))
{
TResponse msg = default(TResponse);
- var deserializeException = success ? TryDeserialize(receivedMessage, out msg) : null;
+ var deserializeException = TryDeserialize(receivedMessage, out msg);
lock (myLock)
{
@@ -415,14 +466,13 @@ namespace Grpc.Core.Internal
finishedStatus = receivedStatus;
ReleaseResourcesIfPossible();
-
}
responseHeadersTcs.SetResult(responseHeaders);
var status = receivedStatus.Status;
- if (!success || status.StatusCode != StatusCode.OK)
+ if (status.StatusCode != StatusCode.OK)
{
unaryResponseTcs.SetException(new RpcException(status));
return;
@@ -437,6 +487,9 @@ namespace Grpc.Core.Internal
/// </summary>
private void HandleFinished(bool success, ClientSideStatus receivedStatus)
{
+ // NOTE: because this event is a result of batch containing GRPC_OP_RECV_STATUS_ON_CLIENT,
+ // success will be always set to true.
+
lock (myLock)
{
finished = true;
@@ -447,7 +500,7 @@ namespace Grpc.Core.Internal
var status = receivedStatus.Status;
- if (!success || status.StatusCode != StatusCode.OK)
+ if (status.StatusCode != StatusCode.OK)
{
streamingCallFinishedTcs.SetException(new RpcException(status));
return;
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 45d4c3e078..cb8366c216 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -58,7 +58,6 @@ namespace Grpc.Core.Internal
readonly Func<TWrite, byte[]> serializer;
readonly Func<byte[], TRead> deserializer;
- protected readonly GrpcEnvironment environment;
protected readonly object myLock = new object();
protected INativeCall call;
@@ -67,8 +66,9 @@ namespace Grpc.Core.Internal
protected bool started;
protected bool cancelRequested;
- protected AsyncCompletionDelegate<object> sendCompletionDelegate; // Completion of a pending send or sendclose if not null.
- protected AsyncCompletionDelegate<TRead> readCompletionDelegate; // Completion of a pending send or sendclose if not null.
+ protected TaskCompletionSource<TRead> streamingReadTcs; // Completion of a pending streaming read if not null.
+ protected TaskCompletionSource<object> streamingWriteTcs; // Completion of a pending streaming write or send close from client if not null.
+ protected TaskCompletionSource<object> sendStatusFromServerTcs;
protected bool readingDone; // True if last read (i.e. read with null payload) was already received.
protected bool halfcloseRequested; // True if send close have been initiated.
@@ -77,11 +77,10 @@ namespace Grpc.Core.Internal
protected bool initialMetadataSent;
protected long streamingWritesCounter; // Number of streaming send operations started so far.
- public AsyncCallBase(Func<TWrite, byte[]> serializer, Func<byte[], TRead> deserializer, GrpcEnvironment environment)
+ public AsyncCallBase(Func<TWrite, byte[]> serializer, Func<byte[], TRead> deserializer)
{
this.serializer = GrpcPreconditions.CheckNotNull(serializer);
this.deserializer = GrpcPreconditions.CheckNotNull(deserializer);
- this.environment = GrpcPreconditions.CheckNotNull(environment);
}
/// <summary>
@@ -127,38 +126,51 @@ namespace Grpc.Core.Internal
/// <summary>
/// Initiates sending a message. Only one send operation can be active at a time.
- /// completionDelegate is invoked upon completion.
/// </summary>
- protected void StartSendMessageInternal(TWrite msg, WriteFlags writeFlags, AsyncCompletionDelegate<object> completionDelegate)
+ protected Task SendMessageInternalAsync(TWrite msg, WriteFlags writeFlags)
{
byte[] payload = UnsafeSerialize(msg);
lock (myLock)
{
- GrpcPreconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null");
- CheckSendingAllowed();
+ GrpcPreconditions.CheckState(started);
+ var earlyResult = CheckSendAllowedOrEarlyResult();
+ if (earlyResult != null)
+ {
+ return earlyResult;
+ }
call.StartSendMessage(HandleSendFinished, payload, writeFlags, !initialMetadataSent);
- sendCompletionDelegate = completionDelegate;
initialMetadataSent = true;
streamingWritesCounter++;
+ streamingWriteTcs = new TaskCompletionSource<object>();
+ return streamingWriteTcs.Task;
}
}
/// <summary>
/// Initiates reading a message. Only one read operation can be active at a time.
- /// completionDelegate is invoked upon completion.
/// </summary>
- protected void StartReadMessageInternal(AsyncCompletionDelegate<TRead> completionDelegate)
+ protected Task<TRead> ReadMessageInternalAsync()
{
lock (myLock)
{
- GrpcPreconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null");
- CheckReadingAllowed();
+ GrpcPreconditions.CheckState(started);
+ if (readingDone)
+ {
+ // the last read that returns null or throws an exception is idempotent
+ // and maintains its state.
+ GrpcPreconditions.CheckState(streamingReadTcs != null, "Call does not support streaming reads.");
+ return streamingReadTcs.Task;
+ }
+
+ GrpcPreconditions.CheckState(streamingReadTcs == null, "Only one read can be pending at a time");
+ GrpcPreconditions.CheckState(!disposed);
call.StartReceiveMessage(HandleReadFinished);
- readCompletionDelegate = completionDelegate;
+ streamingReadTcs = new TaskCompletionSource<TRead>();
+ return streamingReadTcs.Task;
}
}
@@ -172,7 +184,7 @@ namespace Grpc.Core.Internal
{
if (!disposed && call != null)
{
- bool noMoreSendCompletions = sendCompletionDelegate == null && (halfcloseRequested || cancelRequested || finished);
+ bool noMoreSendCompletions = streamingWriteTcs == null && (halfcloseRequested || cancelRequested || finished);
if (noMoreSendCompletions && readingDone && finished)
{
ReleaseResources();
@@ -202,33 +214,11 @@ namespace Grpc.Core.Internal
{
}
- protected void CheckSendingAllowed()
- {
- GrpcPreconditions.CheckState(started);
- CheckNotCancelled();
- GrpcPreconditions.CheckState(!disposed);
-
- GrpcPreconditions.CheckState(!halfcloseRequested, "Already halfclosed.");
- GrpcPreconditions.CheckState(!finished, "Already finished.");
- GrpcPreconditions.CheckState(sendCompletionDelegate == null, "Only one write can be pending at a time");
- }
-
- protected virtual void CheckReadingAllowed()
- {
- GrpcPreconditions.CheckState(started);
- GrpcPreconditions.CheckState(!disposed);
-
- GrpcPreconditions.CheckState(!readingDone, "Stream has already been closed.");
- GrpcPreconditions.CheckState(readCompletionDelegate == null, "Only one read can be pending at a time");
- }
-
- protected void CheckNotCancelled()
- {
- if (cancelRequested)
- {
- throw new OperationCanceledException("Remote call has been cancelled.");
- }
- }
+ /// <summary>
+ /// Checks if sending is allowed and possibly returns a Task that allows short-circuiting the send
+ /// logic by directly returning the write operation result task. Normally, null is returned.
+ /// </summary>
+ protected abstract Task CheckSendAllowedOrEarlyResult();
protected byte[] UnsafeSerialize(TWrite msg)
{
@@ -257,63 +247,72 @@ namespace Grpc.Core.Internal
}
}
- protected void FireCompletion<T>(AsyncCompletionDelegate<T> completionDelegate, T value, Exception error)
+ /// <summary>
+ /// Handles send completion.
+ /// </summary>
+ protected void HandleSendFinished(bool success)
{
- try
+ TaskCompletionSource<object> origTcs = null;
+ lock (myLock)
{
- completionDelegate(value, error);
+ origTcs = streamingWriteTcs;
+ streamingWriteTcs = null;
+
+ ReleaseResourcesIfPossible();
}
- catch (Exception e)
+
+ if (!success)
+ {
+ origTcs.SetException(new InvalidOperationException("Send failed"));
+ }
+ else
{
- Logger.Error(e, "Exception occured while invoking completion delegate.");
+ origTcs.SetResult(null);
}
}
/// <summary>
- /// Handles send completion.
+ /// Handles halfclose (send close from client) completion.
/// </summary>
- protected void HandleSendFinished(bool success)
+ protected void HandleSendCloseFromClientFinished(bool success)
{
- AsyncCompletionDelegate<object> origCompletionDelegate = null;
+ TaskCompletionSource<object> origTcs = null;
lock (myLock)
{
- origCompletionDelegate = sendCompletionDelegate;
- sendCompletionDelegate = null;
+ origTcs = streamingWriteTcs;
+ streamingWriteTcs = null;
ReleaseResourcesIfPossible();
}
if (!success)
{
- FireCompletion(origCompletionDelegate, null, new InvalidOperationException("Send failed"));
+ // TODO(jtattermusch): this method is same as HandleSendFinished (only the error message differs).
+ origTcs.SetException(new InvalidOperationException("Sending close from client has failed."));
}
else
{
- FireCompletion(origCompletionDelegate, null, null);
+ origTcs.SetResult(null);
}
}
/// <summary>
- /// Handles halfclose completion.
+ /// Handles send status from server completion.
/// </summary>
- protected void HandleHalfclosed(bool success)
+ protected void HandleSendStatusFromServerFinished(bool success)
{
- AsyncCompletionDelegate<object> origCompletionDelegate = null;
lock (myLock)
{
- origCompletionDelegate = sendCompletionDelegate;
- sendCompletionDelegate = null;
-
ReleaseResourcesIfPossible();
}
if (!success)
{
- FireCompletion(origCompletionDelegate, null, new InvalidOperationException("Halfclose failed"));
+ sendStatusFromServerTcs.SetException(new InvalidOperationException("Error sending status from server."));
}
else
{
- FireCompletion(origCompletionDelegate, null, null);
+ sendStatusFromServerTcs.SetResult(null);
}
}
@@ -322,15 +321,17 @@ namespace Grpc.Core.Internal
/// </summary>
protected void HandleReadFinished(bool success, byte[] receivedMessage)
{
+ // if success == false, received message will be null. It that case we will
+ // treat this completion as the last read an rely on C core to handle the failed
+ // read (e.g. deliver approriate statusCode on the clientside).
+
TRead msg = default(TRead);
var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null;
- AsyncCompletionDelegate<TRead> origCompletionDelegate = null;
+ TaskCompletionSource<TRead> origTcs = null;
lock (myLock)
{
- origCompletionDelegate = readCompletionDelegate;
- readCompletionDelegate = null;
-
+ origTcs = streamingReadTcs;
if (receivedMessage == null)
{
// This was the last read.
@@ -340,20 +341,25 @@ namespace Grpc.Core.Internal
if (deserializeException != null && IsClient)
{
readingDone = true;
+
+ // TODO(jtattermusch): it might be too late to set the status
CancelWithStatus(DeserializeResponseFailureStatus);
}
+ if (!readingDone)
+ {
+ streamingReadTcs = null;
+ }
+
ReleaseResourcesIfPossible();
}
- // TODO: handle the case when success==false
-
if (deserializeException != null && !IsClient)
{
- FireCompletion(origCompletionDelegate, default(TRead), new IOException("Failed to deserialize request message.", deserializeException));
+ origTcs.SetException(new IOException("Failed to deserialize request message.", deserializeException));
return;
}
- FireCompletion(origCompletionDelegate, msg, null);
+ origTcs.SetResult(msg);
}
}
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index 9380c0d0ea..56c23ba3ef 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -51,20 +51,29 @@ namespace Grpc.Core.Internal
readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
readonly Server server;
- public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment, Server server) : base(serializer, deserializer, environment)
+ public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, Server server) : base(serializer, deserializer)
{
this.server = GrpcPreconditions.CheckNotNull(server);
}
- public void Initialize(CallSafeHandle call)
+ public void Initialize(CallSafeHandle call, CompletionQueueSafeHandle completionQueue)
{
- call.Initialize(environment.CompletionRegistry, environment.CompletionQueue);
+ call.Initialize(completionQueue);
server.AddCallReference(this);
InitializeInternal(call);
}
/// <summary>
+ /// Only for testing purposes.
+ /// </summary>
+ public void InitializeForTesting(INativeCall call)
+ {
+ server.AddCallReference(this);
+ InitializeInternal(call);
+ }
+
+ /// <summary>
/// Starts a server side call.
/// </summary>
public Task ServerSideCallAsync()
@@ -82,40 +91,40 @@ namespace Grpc.Core.Internal
/// <summary>
/// Sends a streaming response. Only one pending send action is allowed at any given time.
- /// completionDelegate is called when the operation finishes.
/// </summary>
- public void StartSendMessage(TResponse msg, WriteFlags writeFlags, AsyncCompletionDelegate<object> completionDelegate)
+ public Task SendMessageAsync(TResponse msg, WriteFlags writeFlags)
{
- StartSendMessageInternal(msg, writeFlags, completionDelegate);
+ return SendMessageInternalAsync(msg, writeFlags);
}
/// <summary>
/// Receives a streaming request. Only one pending read action is allowed at any given time.
- /// completionDelegate is called when the operation finishes.
/// </summary>
- public void StartReadMessage(AsyncCompletionDelegate<TRequest> completionDelegate)
+ public Task<TRequest> ReadMessageAsync()
{
- StartReadMessageInternal(completionDelegate);
+ return ReadMessageInternalAsync();
}
/// <summary>
/// Initiates sending a initial metadata.
/// Even though C-core allows sending metadata in parallel to sending messages, we will treat sending metadata as a send message operation
/// to make things simpler.
- /// completionDelegate is invoked upon completion.
/// </summary>
- public void StartSendInitialMetadata(Metadata headers, AsyncCompletionDelegate<object> completionDelegate)
+ public Task SendInitialMetadataAsync(Metadata headers)
{
lock (myLock)
{
GrpcPreconditions.CheckNotNull(headers, "metadata");
- GrpcPreconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null");
+ GrpcPreconditions.CheckState(started);
GrpcPreconditions.CheckState(!initialMetadataSent, "Response headers can only be sent once per call.");
GrpcPreconditions.CheckState(streamingWritesCounter == 0, "Response headers can only be sent before the first write starts.");
- CheckSendingAllowed();
- GrpcPreconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null");
+ var earlyResult = CheckSendAllowedOrEarlyResult();
+ if (earlyResult != null)
+ {
+ return earlyResult;
+ }
using (var metadataArray = MetadataArraySafeHandle.Create(headers))
{
@@ -123,29 +132,39 @@ namespace Grpc.Core.Internal
}
this.initialMetadataSent = true;
- sendCompletionDelegate = completionDelegate;
+ streamingWriteTcs = new TaskCompletionSource<object>();
+ return streamingWriteTcs.Task;
}
}
/// <summary>
- /// Sends call result status, also indicating server is done with streaming responses.
- /// Only one pending send action is allowed at any given time.
- /// completionDelegate is called when the operation finishes.
+ /// Sends call result status, indicating we are done with writes.
+ /// Sending a status different from StatusCode.OK will also implicitly cancel the call.
/// </summary>
- public void StartSendStatusFromServer(Status status, Metadata trailers, AsyncCompletionDelegate<object> completionDelegate)
+ public Task SendStatusFromServerAsync(Status status, Metadata trailers, Tuple<TResponse, WriteFlags> optionalWrite)
{
+ byte[] payload = optionalWrite != null ? UnsafeSerialize(optionalWrite.Item1) : null;
+ var writeFlags = optionalWrite != null ? optionalWrite.Item2 : default(WriteFlags);
+
lock (myLock)
{
- GrpcPreconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null");
- CheckSendingAllowed();
+ GrpcPreconditions.CheckState(started);
+ GrpcPreconditions.CheckState(!disposed);
+ GrpcPreconditions.CheckState(!halfcloseRequested, "Can only send status from server once.");
using (var metadataArray = MetadataArraySafeHandle.Create(trailers))
{
- call.StartSendStatusFromServer(HandleHalfclosed, status, metadataArray, !initialMetadataSent);
+ call.StartSendStatusFromServer(HandleSendStatusFromServerFinished, status, metadataArray, !initialMetadataSent,
+ payload, writeFlags);
}
halfcloseRequested = true;
- readingDone = true;
- sendCompletionDelegate = completionDelegate;
+ initialMetadataSent = true;
+ sendStatusFromServerTcs = new TaskCompletionSource<object>();
+ if (optionalWrite != null)
+ {
+ streamingWritesCounter++;
+ }
+ return sendStatusFromServerTcs.Task;
}
}
@@ -174,15 +193,19 @@ namespace Grpc.Core.Internal
get { return false; }
}
- protected override void CheckReadingAllowed()
+ protected override void OnAfterReleaseResources()
{
- base.CheckReadingAllowed();
- GrpcPreconditions.CheckArgument(!cancelRequested);
+ server.RemoveCallReference(this);
}
- protected override void OnAfterReleaseResources()
+ protected override Task CheckSendAllowedOrEarlyResult()
{
- server.RemoveCallReference(this);
+ GrpcPreconditions.CheckState(!halfcloseRequested, "Response stream has already been completed.");
+ GrpcPreconditions.CheckState(!finished, "Already finished.");
+ GrpcPreconditions.CheckState(streamingWriteTcs == null, "Only one write can be pending at a time");
+ GrpcPreconditions.CheckState(!disposed);
+
+ return null;
}
/// <summary>
@@ -190,12 +213,21 @@ namespace Grpc.Core.Internal
/// </summary>
private void HandleFinishedServerside(bool success, bool cancelled)
{
+ // NOTE: because this event is a result of batch containing GRPC_OP_RECV_CLOSE_ON_SERVER,
+ // success will be always set to true.
lock (myLock)
{
finished = true;
+ if (streamingReadTcs == null)
+ {
+ // if there's no pending read, readingDone=true will dispose now.
+ // if there is a pending read, we will dispose once that read finishes.
+ readingDone = true;
+ streamingReadTcs = new TaskCompletionSource<TRequest>();
+ streamingReadTcs.SetResult(default(TRequest));
+ }
ReleaseResourcesIfPossible();
}
- // TODO(jtattermusch): handle error
if (cancelled)
{
diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
index 0e2108f0f2..c28a6f64d3 100644
--- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -120,107 +120,4 @@ namespace Grpc.Core.Internal
return true;
}
}
-
- /// <summary>
- /// Status + metadata received on client side when call finishes.
- /// (when receive_status_on_client operation finishes).
- /// </summary>
- internal struct ClientSideStatus
- {
- readonly Status status;
- readonly Metadata trailers;
-
- public ClientSideStatus(Status status, Metadata trailers)
- {
- this.status = status;
- this.trailers = trailers;
- }
-
- public Status Status
- {
- get
- {
- return this.status;
- }
- }
-
- public Metadata Trailers
- {
- get
- {
- return this.trailers;
- }
- }
- }
-
- /// <summary>
- /// Details of a newly received RPC.
- /// </summary>
- internal struct ServerRpcNew
- {
- readonly Server server;
- readonly CallSafeHandle call;
- readonly string method;
- readonly string host;
- readonly Timespec deadline;
- readonly Metadata requestMetadata;
-
- public ServerRpcNew(Server server, CallSafeHandle call, string method, string host, Timespec deadline, Metadata requestMetadata)
- {
- this.server = server;
- this.call = call;
- this.method = method;
- this.host = host;
- this.deadline = deadline;
- this.requestMetadata = requestMetadata;
- }
-
- public Server Server
- {
- get
- {
- return this.server;
- }
- }
-
- public CallSafeHandle Call
- {
- get
- {
- return this.call;
- }
- }
-
- public string Method
- {
- get
- {
- return this.method;
- }
- }
-
- public string Host
- {
- get
- {
- return this.host;
- }
- }
-
- public Timespec Deadline
- {
- get
- {
- return this.deadline;
- }
- }
-
- public Metadata RequestMetadata
- {
- get
- {
- return this.requestMetadata;
- }
- }
- }
}
diff --git a/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs
index 4ae57aa773..0221798d2a 100644
--- a/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs
index 0f36337f11..3095a34008 100644
--- a/src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Internal/Enums.cs b/src/csharp/Grpc.Core/Internal/CallError.cs
index 098e7c0e99..541575f5e6 100644
--- a/src/csharp/Grpc.Core/Internal/Enums.cs
+++ b/src/csharp/Grpc.Core/Internal/CallError.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// grpc_call_error from grpc/grpc.h
/// </summary>
- internal enum GRPCCallError
+ internal enum CallError
{
/* everything went ok */
OK = 0,
@@ -70,42 +70,9 @@ namespace Grpc.Core.Internal
/// <summary>
/// Checks the call API invocation's result is OK.
/// </summary>
- public static void CheckOk(this GRPCCallError callError)
+ public static void CheckOk(this CallError callError)
{
- GrpcPreconditions.CheckState(callError == GRPCCallError.OK, "Call error: " + callError);
+ GrpcPreconditions.CheckState(callError == CallError.OK, "Call error: " + callError);
}
}
-
- /// <summary>
- /// grpc_completion_type from grpc/grpc.h
- /// </summary>
- internal enum GRPCCompletionType
- {
- /* Shutting down */
- Shutdown,
-
- /* No event before timeout */
- Timeout,
-
- /* operation completion */
- OpComplete
- }
-
- /// <summary>
- /// gpr_clock_type from grpc/support/time.h
- /// </summary>
- internal enum GPRClockType
- {
- /* Monotonic clock */
- Monotonic,
-
- /* Realtime clock */
- Realtime,
-
- /* Precise clock good for performance profiling. */
- Precise,
-
- /* Timespan - the distance between two time points */
- Timespan
- }
}
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index bc045b67b1..82361f5797 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -47,16 +47,14 @@ namespace Grpc.Core.Internal
static readonly NativeMethods Native = NativeMethods.Get();
const uint GRPC_WRITE_BUFFER_HINT = 1;
- CompletionRegistry completionRegistry;
CompletionQueueSafeHandle completionQueue;
private CallSafeHandle()
{
}
- public void Initialize(CompletionRegistry completionRegistry, CompletionQueueSafeHandle completionQueue)
+ public void Initialize(CompletionQueueSafeHandle completionQueue)
{
- this.completionRegistry = completionRegistry;
this.completionQueue = completionQueue;
}
@@ -70,7 +68,7 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags)
.CheckOk();
}
@@ -90,7 +88,7 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
Native.grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk();
}
}
@@ -100,7 +98,7 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
Native.grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags).CheckOk();
}
}
@@ -110,7 +108,7 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
Native.grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk();
}
}
@@ -120,7 +118,7 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
Native.grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, sendEmptyInitialMetadata).CheckOk();
}
}
@@ -130,18 +128,21 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
Native.grpcsharp_call_send_close_from_client(this, ctx).CheckOk();
}
}
- public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata)
+ public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
+ byte[] optionalPayload, WriteFlags writeFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
- Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray, sendEmptyInitialMetadata).CheckOk();
+ var optionalPayloadLength = optionalPayload != null ? new UIntPtr((ulong)optionalPayload.Length) : UIntPtr.Zero;
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
+ Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail, metadataArray, sendEmptyInitialMetadata,
+ optionalPayload, optionalPayloadLength, writeFlags).CheckOk();
}
}
@@ -150,7 +151,7 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedMessage()));
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedMessage()));
Native.grpcsharp_call_recv_message(this, ctx).CheckOk();
}
}
@@ -160,7 +161,7 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedInitialMetadata()));
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedInitialMetadata()));
Native.grpcsharp_call_recv_initial_metadata(this, ctx).CheckOk();
}
}
@@ -170,7 +171,7 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedCloseOnServerCancelled()));
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedCloseOnServerCancelled()));
Native.grpcsharp_call_start_serverside(this, ctx).CheckOk();
}
}
@@ -180,7 +181,7 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
Native.grpcsharp_call_send_initial_metadata(this, ctx, metadataArray).CheckOk();
}
}
diff --git a/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs
index f6aa710b21..0038024245 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs
index 65cc2e019f..c85f55241a 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
index 2199905cc6..62864dff0c 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -63,7 +63,7 @@ namespace Grpc.Core.Internal
return Native.grpcsharp_secure_channel_create(credentials, target, channelArgs);
}
- public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CallCredentialsSafeHandle credentials)
+ public CallSafeHandle CreateCall(CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CallCredentialsSafeHandle credentials)
{
using (Profilers.ForCurrentThread().NewScope("ChannelSafeHandle.CreateCall"))
{
@@ -72,7 +72,7 @@ namespace Grpc.Core.Internal
{
result.SetCredentials(credentials);
}
- result.Initialize(registry, cq);
+ result.Initialize(cq);
return result;
}
}
@@ -82,11 +82,10 @@ namespace Grpc.Core.Internal
return Native.grpcsharp_channel_check_connectivity_state(this, tryToConnect ? 1 : 0);
}
- public void WatchConnectivityState(ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq,
- CompletionRegistry completionRegistry, BatchCompletionDelegate callback)
+ public void WatchConnectivityState(ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
{
var ctx = BatchContextSafeHandle.Create();
- completionRegistry.RegisterBatchCompletion(ctx, callback);
+ cq.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
Native.grpcsharp_channel_watch_connectivity_state(this, lastObservedState, deadline, cq, ctx);
}
diff --git a/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs b/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs
index 013f00ff6f..924de028f5 100644
--- a/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs
@@ -50,16 +50,12 @@ namespace Grpc.Core.Internal
public Task WriteAsync(TRequest message)
{
- var taskSource = new AsyncCompletionTaskSource<object>();
- call.StartSendMessage(message, GetWriteFlags(), taskSource.CompletionDelegate);
- return taskSource.Task;
+ return call.SendMessageAsync(message, GetWriteFlags());
}
public Task CompleteAsync()
{
- var taskSource = new AsyncCompletionTaskSource<object>();
- call.StartSendCloseFromClient(taskSource.CompletionDelegate);
- return taskSource.Task;
+ return call.SendCloseFromClientAsync();
}
public WriteOptions WriteOptions
diff --git a/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs b/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
index d6e34a0f04..ad9423ff58 100644
--- a/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
@@ -68,9 +68,7 @@ namespace Grpc.Core.Internal
{
throw new InvalidOperationException("Cancellation of individual reads is not supported.");
}
- var taskSource = new AsyncCompletionTaskSource<TResponse>();
- call.StartReadMessage(taskSource.CompletionDelegate);
- var result = await taskSource.Task.ConfigureAwait(false);
+ var result = await call.ReadMessageAsync().ConfigureAwait(false);
this.current = result;
if (result == null)
diff --git a/src/csharp/Grpc.Core/Internal/ClientSideStatus.cs b/src/csharp/Grpc.Core/Internal/ClientSideStatus.cs
new file mode 100644
index 0000000000..5727e3f11f
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/ClientSideStatus.cs
@@ -0,0 +1,70 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using Grpc.Core;
+
+namespace Grpc.Core.Internal
+{
+ /// <summary>
+ /// Status + metadata received on client side when call finishes.
+ /// (when receive_status_on_client operation finishes).
+ /// </summary>
+ internal struct ClientSideStatus
+ {
+ readonly Status status;
+ readonly Metadata trailers;
+
+ public ClientSideStatus(Status status, Metadata trailers)
+ {
+ this.status = status;
+ this.trailers = trailers;
+ }
+
+ public Status Status
+ {
+ get
+ {
+ return this.status;
+ }
+ }
+
+ public Metadata Trailers
+ {
+ get
+ {
+ return this.trailers;
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/ClockType.cs b/src/csharp/Grpc.Core/Internal/ClockType.cs
new file mode 100644
index 0000000000..57533c9d2f
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/ClockType.cs
@@ -0,0 +1,53 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+namespace Grpc.Core.Internal
+{
+ /// <summary>
+ /// gpr_clock_type from grpc/support/time.h
+ /// </summary>
+ internal enum ClockType
+ {
+ /* Monotonic clock */
+ Monotonic,
+
+ /* Realtime clock */
+ Realtime,
+
+ /* Precise clock good for performance profiling. */
+ Precise,
+
+ /* Timespan - the distance between two time points */
+ Timespan
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/CompletionQueueEvent.cs b/src/csharp/Grpc.Core/Internal/CompletionQueueEvent.cs
index 36a92ecd8e..a78e9b70f3 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionQueueEvent.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionQueueEvent.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,7 @@ namespace Grpc.Core.Internal
{
static readonly NativeMethods Native = NativeMethods.Get();
- public GRPCCompletionType type;
+ public CompletionType type;
public int success;
public IntPtr tag;
@@ -55,5 +55,20 @@ namespace Grpc.Core.Internal
return Native.grpcsharp_sizeof_grpc_event();
}
}
+
+ /// <summary>
+ /// grpc_completion_type from grpc/grpc.h
+ /// </summary>
+ internal enum CompletionType
+ {
+ /* Shutting down */
+ Shutdown,
+
+ /* No event before timeout */
+ Timeout,
+
+ /* operation completion */
+ OpComplete
+ }
}
}
diff --git a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
index 5c75b52e23..46f5624223 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@ namespace Grpc.Core.Internal
static readonly NativeMethods Native = NativeMethods.Get();
AtomicCounter shutdownRefcount = new AtomicCounter(1);
+ CompletionRegistry completionRegistry;
private CompletionQueueSafeHandle()
{
@@ -53,7 +54,13 @@ namespace Grpc.Core.Internal
public static CompletionQueueSafeHandle Create()
{
return Native.grpcsharp_completion_queue_create();
+ }
+ public static CompletionQueueSafeHandle Create(CompletionRegistry completionRegistry)
+ {
+ var cq = Native.grpcsharp_completion_queue_create();
+ cq.completionRegistry = completionRegistry;
+ return cq;
}
public CompletionQueueEvent Next()
@@ -83,6 +90,15 @@ namespace Grpc.Core.Internal
DecrementShutdownRefcount();
}
+ /// <summary>
+ /// Completion registry associated with this completion queue.
+ /// Doesn't need to be set if only using Pluck() operations.
+ /// </summary>
+ public CompletionRegistry CompletionRegistry
+ {
+ get { return completionRegistry; }
+ }
+
protected override bool ReleaseHandle()
{
Native.grpcsharp_completion_queue_destroy(handle);
diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
index 3a293e1626..628844f242 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs b/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
index dfaee5d9d7..aa4dafd7f2 100644
--- a/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
+++ b/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index 4b7124ee74..4de543bef7 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -33,15 +33,15 @@
using System;
using System.Collections.Generic;
-using System.Runtime.InteropServices;
+using System.Linq;
using System.Threading;
-using System.Threading.Tasks;
using Grpc.Core.Logging;
+using Grpc.Core.Utils;
namespace Grpc.Core.Internal
{
/// <summary>
- /// Pool of threads polling on the same completion queue.
+ /// Pool of threads polling on a set of completions queues.
/// </summary>
internal class GrpcThreadPool
{
@@ -51,25 +51,31 @@ namespace Grpc.Core.Internal
readonly object myLock = new object();
readonly List<Thread> threads = new List<Thread>();
readonly int poolSize;
+ readonly int completionQueueCount;
- CompletionQueueSafeHandle cq;
+ IReadOnlyCollection<CompletionQueueSafeHandle> completionQueues;
- public GrpcThreadPool(GrpcEnvironment environment, int poolSize)
+ /// <summary>
+ /// Creates a thread pool threads polling on a set of completions queues.
+ /// </summary>
+ /// <param name="environment">Environment.</param>
+ /// <param name="poolSize">Pool size.</param>
+ /// <param name="completionQueueCount">Completion queue count.</param>
+ public GrpcThreadPool(GrpcEnvironment environment, int poolSize, int completionQueueCount)
{
this.environment = environment;
this.poolSize = poolSize;
+ this.completionQueueCount = completionQueueCount;
+ GrpcPreconditions.CheckArgument(poolSize >= completionQueueCount,
+ "Thread pool size cannot be smaller than the number of completion queues used.");
}
public void Start()
{
lock (myLock)
{
- if (cq != null)
- {
- throw new InvalidOperationException("Already started.");
- }
-
- cq = CompletionQueueSafeHandle.Create();
+ GrpcPreconditions.CheckState(completionQueues == null, "Already started.");
+ completionQueues = CreateCompletionQueueList(environment, completionQueueCount);
for (int i = 0; i < poolSize; i++)
{
@@ -82,49 +88,60 @@ namespace Grpc.Core.Internal
{
lock (myLock)
{
- cq.Shutdown();
+ foreach (var cq in completionQueues)
+ {
+ cq.Shutdown();
+ }
+
foreach (var thread in threads)
{
thread.Join();
}
- cq.Dispose();
+ foreach (var cq in completionQueues)
+ {
+ cq.Dispose();
+ }
}
}
- internal CompletionQueueSafeHandle CompletionQueue
+ internal IReadOnlyCollection<CompletionQueueSafeHandle> CompletionQueues
{
get
{
- return cq;
+ return completionQueues;
}
}
- private Thread CreateAndStartThread(int i)
+ private Thread CreateAndStartThread(int threadIndex)
{
- var thread = new Thread(new ThreadStart(RunHandlerLoop));
+ var cqIndex = threadIndex % completionQueues.Count;
+ var cq = completionQueues.ElementAt(cqIndex);
+
+ var thread = new Thread(new ThreadStart(() => RunHandlerLoop(cq)));
thread.IsBackground = false;
+ thread.Name = string.Format("grpc {0} (cq {1})", threadIndex, cqIndex);
thread.Start();
- thread.Name = "grpc " + i;
+
return thread;
}
/// <summary>
/// Body of the polling thread.
/// </summary>
- private void RunHandlerLoop()
+ private void RunHandlerLoop(CompletionQueueSafeHandle cq)
{
CompletionQueueEvent ev;
do
{
ev = cq.Next();
- if (ev.type == GRPCCompletionType.OpComplete)
+ if (ev.type == CompletionQueueEvent.CompletionType.OpComplete)
{
bool success = (ev.success != 0);
IntPtr tag = ev.tag;
try
{
- var callback = environment.CompletionRegistry.Extract(tag);
+ var callback = cq.CompletionRegistry.Extract(tag);
callback(success);
}
catch (Exception e)
@@ -133,7 +150,18 @@ namespace Grpc.Core.Internal
}
}
}
- while (ev.type != GRPCCompletionType.Shutdown);
+ while (ev.type != CompletionQueueEvent.CompletionType.Shutdown);
+ }
+
+ private static IReadOnlyCollection<CompletionQueueSafeHandle> CreateCompletionQueueList(GrpcEnvironment environment, int completionQueueCount)
+ {
+ var list = new List<CompletionQueueSafeHandle>();
+ for (int i = 0; i < completionQueueCount; i++)
+ {
+ var completionRegistry = new CompletionRegistry(environment);
+ list.Add(CompletionQueueSafeHandle.Create(completionRegistry));
+ }
+ return list.AsReadOnly();
}
}
}
diff --git a/src/csharp/Grpc.Core/Internal/INativeCall.cs b/src/csharp/Grpc.Core/Internal/INativeCall.cs
index cbef599139..cd3719cb50 100644
--- a/src/csharp/Grpc.Core/Internal/INativeCall.cs
+++ b/src/csharp/Grpc.Core/Internal/INativeCall.cs
@@ -78,7 +78,7 @@ namespace Grpc.Core.Internal
void StartSendCloseFromClient(SendCompletionHandler callback);
- void StartSendStatusFromServer(SendCompletionHandler callback, Grpc.Core.Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata);
+ void StartSendStatusFromServer(SendCompletionHandler callback, Grpc.Core.Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, Grpc.Core.WriteFlags writeFlags);
void StartServerSide(ReceivedCloseOnServerHandler callback);
}
diff --git a/src/csharp/Grpc.Core/Internal/InterceptingCallInvoker.cs b/src/csharp/Grpc.Core/Internal/InterceptingCallInvoker.cs
new file mode 100644
index 0000000000..ef48dc7121
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/InterceptingCallInvoker.cs
@@ -0,0 +1,134 @@
+#region Copyright notice and license
+
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+ /// <summary>
+ /// Decorates an underlying <c>CallInvoker</c> to intercept call invocations.
+ /// </summary>
+ internal class InterceptingCallInvoker : CallInvoker
+ {
+ readonly CallInvoker callInvoker;
+ readonly Func<string, string> hostInterceptor;
+ readonly Func<CallOptions, CallOptions> callOptionsInterceptor;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Grpc.Core.InterceptingCallInvoker"/> class.
+ /// </summary>
+ public InterceptingCallInvoker(CallInvoker callInvoker,
+ Func<string, string> hostInterceptor = null,
+ Func<CallOptions, CallOptions> callOptionsInterceptor = null)
+ {
+ this.callInvoker = GrpcPreconditions.CheckNotNull(callInvoker);
+ this.hostInterceptor = hostInterceptor;
+ this.callOptionsInterceptor = callOptionsInterceptor;
+ }
+
+ /// <summary>
+ /// Intercepts a unary call.
+ /// </summary>
+ public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ {
+ host = InterceptHost(host);
+ options = InterceptCallOptions(options);
+ return callInvoker.BlockingUnaryCall(method, host, options, request);
+ }
+
+ /// <summary>
+ /// Invokes a simple remote call asynchronously.
+ /// </summary>
+ public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ {
+ host = InterceptHost(host);
+ options = InterceptCallOptions(options);
+ return callInvoker.AsyncUnaryCall(method, host, options, request);
+ }
+
+ /// <summary>
+ /// Invokes a server streaming call asynchronously.
+ /// In server streaming scenario, client sends on request and server responds with a stream of responses.
+ /// </summary>
+ public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ {
+ host = InterceptHost(host);
+ options = InterceptCallOptions(options);
+ return callInvoker.AsyncServerStreamingCall(method, host, options, request);
+ }
+
+ /// <summary>
+ /// Invokes a client streaming call asynchronously.
+ /// In client streaming scenario, client sends a stream of requests and server responds with a single response.
+ /// </summary>
+ public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+ {
+ host = InterceptHost(host);
+ options = InterceptCallOptions(options);
+ return callInvoker.AsyncClientStreamingCall(method, host, options);
+ }
+
+ /// <summary>
+ /// Invokes a duplex streaming call asynchronously.
+ /// In duplex streaming scenario, client sends a stream of requests and server responds with a stream of responses.
+ /// The response stream is completely independent and both side can be sending messages at the same time.
+ /// </summary>
+ public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+ {
+ host = InterceptHost(host);
+ options = InterceptCallOptions(options);
+ return callInvoker.AsyncDuplexStreamingCall(method, host, options);
+ }
+
+ private string InterceptHost(string host)
+ {
+ if (hostInterceptor == null)
+ {
+ return host;
+ }
+ return hostInterceptor(host);
+ }
+
+ private CallOptions InterceptCallOptions(CallOptions options)
+ {
+ if (callOptionsInterceptor == null)
+ {
+ return options;
+ }
+ return callOptionsInterceptor(options);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
index 81760d7a10..dc9f62fdab 100644
--- a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,11 @@ namespace Grpc.Core.Internal
{
using (Profilers.ForCurrentThread().NewScope("MetadataArraySafeHandle.Create"))
{
+ if (metadata.Count == 0)
+ {
+ return new MetadataArraySafeHandle();
+ }
+
// TODO(jtattermusch): we might wanna check that the metadata is readonly
var metadataArray = Native.grpcsharp_metadata_array_create(new UIntPtr((ulong)metadata.Count));
for (int i = 0; i < metadata.Count; i++)
diff --git a/src/csharp/Grpc.Core/Internal/NativeExtension.cs b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
index 4c742ab6c3..b45ba19c24 100644
--- a/src/csharp/Grpc.Core/Internal/NativeExtension.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@ namespace Grpc.Core.Internal
internal sealed class NativeExtension
{
const string NativeLibrariesDir = "nativelibs";
+ const string DnxStyleNativeLibrariesDir = "../../build/native/bin/";
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeExtension>();
static readonly object staticLock = new object();
@@ -99,15 +100,48 @@ namespace Grpc.Core.Internal
// TODO: allow customizing path to native extension (possibly through exposing a GrpcEnvironment property).
var libraryFlavor = string.Format("{0}_{1}", GetPlatformString(), GetArchitectureString());
- var fullPath = Path.Combine(GetExecutingAssemblyDirectory(),
- NativeLibrariesDir, libraryFlavor, GetNativeLibraryFilename());
- return new UnmanagedLibrary(fullPath);
+
+ var assemblyDirectory = Path.GetDirectoryName(GetAssemblyPath());
+
+ // With old-style VS projects, the native libraries get copied using a .targets rule to the build output folder
+ // alongside the compiled assembly.
+ var classicPath = Path.Combine(assemblyDirectory, NativeLibrariesDir, libraryFlavor, GetNativeLibraryFilename());
+
+ // DNX-style project.json projects will use Grpc.Core assembly directly in the location where it got restored
+ // by nuget. We locate the native libraries based on known structure of Grpc.Core nuget package.
+ var dnxStylePath = Path.Combine(assemblyDirectory, DnxStyleNativeLibrariesDir, libraryFlavor, GetNativeLibraryFilename());
+
+ return new UnmanagedLibrary(new string[] {classicPath, dnxStylePath});
+ }
+
+ private static string GetAssemblyPath()
+ {
+ var assembly = typeof(NativeExtension).GetTypeInfo().Assembly;
+#if DOTNET5_4
+ // Assembly.EscapedCodeBase does not exit under CoreCLR, but assemblies imported from a nuget package
+ // don't seem to be shadowed by DNX-based projects at all.
+ return assembly.Location;
+#else
+ // If assembly is shadowed (e.g. in a webapp), EscapedCodeBase is pointing
+ // to the original location of the assembly, and Location is pointing
+ // to the shadow copy. We care about the original location because
+ // the native dlls don't get shadowed.
+
+ var escapedCodeBase = assembly.EscapedCodeBase;
+ if (IsFileUri(escapedCodeBase))
+ {
+ return new Uri(escapedCodeBase).LocalPath;
+ }
+ return assembly.Location;
+#endif
}
- private static string GetExecutingAssemblyDirectory()
+#if !DOTNET5_4
+ private static bool IsFileUri(string uri)
{
- return Path.GetDirectoryName(typeof(NativeExtension).GetTypeInfo().Assembly.Location);
+ return uri.ToLowerInvariant().StartsWith(Uri.UriSchemeFile);
}
+#endif
private static string GetPlatformString()
{
diff --git a/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
index 4bbbb4808c..3fcf8673ee 100644
--- a/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
index e810ffcdd0..26af6311d5 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -87,7 +87,7 @@ namespace Grpc.Core.Internal
}
}
- private async void StartGetMetadata(AuthInterceptorContext context, IntPtr callbackPtr, IntPtr userDataPtr)
+ private async Task StartGetMetadata(AuthInterceptorContext context, IntPtr callbackPtr, IntPtr userDataPtr)
{
try
{
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
index 19a573581e..65607ed120 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -137,6 +137,7 @@ namespace Grpc.Core.Internal
public readonly Delegates.grpcsharp_server_credentials_release_delegate grpcsharp_server_credentials_release;
public readonly Delegates.grpcsharp_server_create_delegate grpcsharp_server_create;
+ public readonly Delegates.grpcsharp_server_register_completion_queue_delegate grpcsharp_server_register_completion_queue;
public readonly Delegates.grpcsharp_server_add_insecure_http2_port_delegate grpcsharp_server_add_insecure_http2_port;
public readonly Delegates.grpcsharp_server_add_secure_http2_port_delegate grpcsharp_server_add_secure_http2_port;
public readonly Delegates.grpcsharp_server_start_delegate grpcsharp_server_start;
@@ -244,6 +245,7 @@ namespace Grpc.Core.Internal
this.grpcsharp_server_credentials_release = GetMethodDelegate<Delegates.grpcsharp_server_credentials_release_delegate>(library);
this.grpcsharp_server_create = GetMethodDelegate<Delegates.grpcsharp_server_create_delegate>(library);
+ this.grpcsharp_server_register_completion_queue = GetMethodDelegate<Delegates.grpcsharp_server_register_completion_queue_delegate>(library);
this.grpcsharp_server_add_insecure_http2_port = GetMethodDelegate<Delegates.grpcsharp_server_add_insecure_http2_port_delegate>(library);
this.grpcsharp_server_add_secure_http2_port = GetMethodDelegate<Delegates.grpcsharp_server_add_secure_http2_port_delegate>(library);
this.grpcsharp_server_start = GetMethodDelegate<Delegates.grpcsharp_server_start_delegate>(library);
@@ -348,6 +350,7 @@ namespace Grpc.Core.Internal
this.grpcsharp_server_credentials_release = PInvokeMethods.grpcsharp_server_credentials_release;
this.grpcsharp_server_create = PInvokeMethods.grpcsharp_server_create;
+ this.grpcsharp_server_register_completion_queue = PInvokeMethods.grpcsharp_server_register_completion_queue;
this.grpcsharp_server_add_insecure_http2_port = PInvokeMethods.grpcsharp_server_add_insecure_http2_port;
this.grpcsharp_server_add_secure_http2_port = PInvokeMethods.grpcsharp_server_add_secure_http2_port;
this.grpcsharp_server_start = PInvokeMethods.grpcsharp_server_start;
@@ -418,32 +421,33 @@ namespace Grpc.Core.Internal
public delegate CallCredentialsSafeHandle grpcsharp_composite_call_credentials_create_delegate(CallCredentialsSafeHandle creds1, CallCredentialsSafeHandle creds2);
public delegate void grpcsharp_call_credentials_release_delegate(IntPtr credentials);
- public delegate GRPCCallError grpcsharp_call_cancel_delegate(CallSafeHandle call);
- public delegate GRPCCallError grpcsharp_call_cancel_with_status_delegate(CallSafeHandle call, StatusCode status, string description);
- public delegate GRPCCallError grpcsharp_call_start_unary_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
- public delegate GRPCCallError grpcsharp_call_start_client_streaming_delegate(CallSafeHandle call,
+ public delegate CallError grpcsharp_call_cancel_delegate(CallSafeHandle call);
+ public delegate CallError grpcsharp_call_cancel_with_status_delegate(CallSafeHandle call, StatusCode status, string description);
+ public delegate CallError grpcsharp_call_start_unary_delegate(CallSafeHandle call,
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
+ public delegate CallError grpcsharp_call_start_client_streaming_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
- public delegate GRPCCallError grpcsharp_call_start_server_streaming_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len,
+ public delegate CallError grpcsharp_call_start_server_streaming_delegate(CallSafeHandle call,
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen,
MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
- public delegate GRPCCallError grpcsharp_call_start_duplex_streaming_delegate(CallSafeHandle call,
+ public delegate CallError grpcsharp_call_start_duplex_streaming_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
- public delegate GRPCCallError grpcsharp_call_send_message_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
- public delegate GRPCCallError grpcsharp_call_send_close_from_client_delegate(CallSafeHandle call,
+ public delegate CallError grpcsharp_call_send_message_delegate(CallSafeHandle call,
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
+ public delegate CallError grpcsharp_call_send_close_from_client_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx);
- public delegate GRPCCallError grpcsharp_call_send_status_from_server_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata);
- public delegate GRPCCallError grpcsharp_call_recv_message_delegate(CallSafeHandle call,
+ public delegate CallError grpcsharp_call_send_status_from_server_delegate(CallSafeHandle call,
+ BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
+ byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
+ public delegate CallError grpcsharp_call_recv_message_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx);
- public delegate GRPCCallError grpcsharp_call_recv_initial_metadata_delegate(CallSafeHandle call,
+ public delegate CallError grpcsharp_call_recv_initial_metadata_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx);
- public delegate GRPCCallError grpcsharp_call_start_serverside_delegate(CallSafeHandle call,
+ public delegate CallError grpcsharp_call_start_serverside_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx);
- public delegate GRPCCallError grpcsharp_call_send_initial_metadata_delegate(CallSafeHandle call,
+ public delegate CallError grpcsharp_call_send_initial_metadata_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
- public delegate GRPCCallError grpcsharp_call_set_credentials_delegate(CallSafeHandle call, CallCredentialsSafeHandle credentials);
+ public delegate CallError grpcsharp_call_set_credentials_delegate(CallSafeHandle call, CallCredentialsSafeHandle credentials);
public delegate CStringSafeHandle grpcsharp_call_get_peer_delegate(CallSafeHandle call);
public delegate void grpcsharp_call_destroy_delegate(IntPtr call);
@@ -492,23 +496,24 @@ namespace Grpc.Core.Internal
public delegate ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create_delegate(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, bool forceClientAuth);
public delegate void grpcsharp_server_credentials_release_delegate(IntPtr credentials);
- public delegate ServerSafeHandle grpcsharp_server_create_delegate(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args);
+ public delegate ServerSafeHandle grpcsharp_server_create_delegate(ChannelArgsSafeHandle args);
+ public delegate void grpcsharp_server_register_completion_queue_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq);
public delegate int grpcsharp_server_add_insecure_http2_port_delegate(ServerSafeHandle server, string addr);
public delegate int grpcsharp_server_add_secure_http2_port_delegate(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds);
public delegate void grpcsharp_server_start_delegate(ServerSafeHandle server);
- public delegate GRPCCallError grpcsharp_server_request_call_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
+ public delegate CallError grpcsharp_server_request_call_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
public delegate void grpcsharp_server_cancel_all_calls_delegate(ServerSafeHandle server);
public delegate void grpcsharp_server_shutdown_and_notify_callback_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
public delegate void grpcsharp_server_destroy_delegate(IntPtr server);
- public delegate Timespec gprsharp_now_delegate(GPRClockType clockType);
- public delegate Timespec gprsharp_inf_future_delegate(GPRClockType clockType);
- public delegate Timespec gprsharp_inf_past_delegate(GPRClockType clockType);
+ public delegate Timespec gprsharp_now_delegate(ClockType clockType);
+ public delegate Timespec gprsharp_inf_future_delegate(ClockType clockType);
+ public delegate Timespec gprsharp_inf_past_delegate(ClockType clockType);
- public delegate Timespec gprsharp_convert_clock_type_delegate(Timespec t, GPRClockType targetClock);
+ public delegate Timespec gprsharp_convert_clock_type_delegate(Timespec t, ClockType targetClock);
public delegate int gprsharp_sizeof_timespec_delegate();
- public delegate GRPCCallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] OpCompletionDelegate callback);
+ public delegate CallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] OpCompletionDelegate callback);
public delegate IntPtr grpcsharp_test_nop_delegate(IntPtr ptr);
}
@@ -586,58 +591,59 @@ namespace Grpc.Core.Internal
// CallSafeHandle
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_cancel(CallSafeHandle call);
+ public static extern CallError grpcsharp_call_cancel(CallSafeHandle call);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description);
+ public static extern CallError grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_start_unary(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
+ public static extern CallError grpcsharp_call_start_unary(CallSafeHandle call,
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_start_client_streaming(CallSafeHandle call,
+ public static extern CallError grpcsharp_call_start_client_streaming(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_start_server_streaming(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len,
+ public static extern CallError grpcsharp_call_start_server_streaming(CallSafeHandle call,
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen,
MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call,
+ public static extern CallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] send_buffer, UIntPtr send_buffer_len, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
+ public static extern CallError grpcsharp_call_send_message(CallSafeHandle call,
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_send_close_from_client(CallSafeHandle call,
+ public static extern CallError grpcsharp_call_send_close_from_client(CallSafeHandle call,
BatchContextSafeHandle ctx);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_send_status_from_server(CallSafeHandle call,
- BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata);
+ public static extern CallError grpcsharp_call_send_status_from_server(CallSafeHandle call,
+ BatchContextSafeHandle ctx, StatusCode statusCode, string statusMessage, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
+ byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_recv_message(CallSafeHandle call,
+ public static extern CallError grpcsharp_call_recv_message(CallSafeHandle call,
BatchContextSafeHandle ctx);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_recv_initial_metadata(CallSafeHandle call,
+ public static extern CallError grpcsharp_call_recv_initial_metadata(CallSafeHandle call,
BatchContextSafeHandle ctx);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_start_serverside(CallSafeHandle call,
+ public static extern CallError grpcsharp_call_start_serverside(CallSafeHandle call,
BatchContextSafeHandle ctx);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_send_initial_metadata(CallSafeHandle call,
+ public static extern CallError grpcsharp_call_send_initial_metadata(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_call_set_credentials(CallSafeHandle call, CallCredentialsSafeHandle credentials);
+ public static extern CallError grpcsharp_call_set_credentials(CallSafeHandle call, CallCredentialsSafeHandle credentials);
[DllImport("grpc_csharp_ext.dll")]
public static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call);
@@ -771,7 +777,10 @@ namespace Grpc.Core.Internal
// ServerSafeHandle
[DllImport("grpc_csharp_ext.dll")]
- public static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args);
+ public static extern ServerSafeHandle grpcsharp_server_create(ChannelArgsSafeHandle args);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ public static extern void grpcsharp_server_register_completion_queue(ServerSafeHandle server, CompletionQueueSafeHandle cq);
[DllImport("grpc_csharp_ext.dll")]
public static extern int grpcsharp_server_add_insecure_http2_port(ServerSafeHandle server, string addr);
@@ -783,7 +792,7 @@ namespace Grpc.Core.Internal
public static extern void grpcsharp_server_start(ServerSafeHandle server);
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_server_request_call(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
+ public static extern CallError grpcsharp_server_request_call(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
[DllImport("grpc_csharp_ext.dll")]
public static extern void grpcsharp_server_cancel_all_calls(ServerSafeHandle server);
@@ -797,16 +806,16 @@ namespace Grpc.Core.Internal
// Timespec
[DllImport("grpc_csharp_ext.dll")]
- public static extern Timespec gprsharp_now(GPRClockType clockType);
+ public static extern Timespec gprsharp_now(ClockType clockType);
[DllImport("grpc_csharp_ext.dll")]
- public static extern Timespec gprsharp_inf_future(GPRClockType clockType);
+ public static extern Timespec gprsharp_inf_future(ClockType clockType);
[DllImport("grpc_csharp_ext.dll")]
- public static extern Timespec gprsharp_inf_past(GPRClockType clockType);
+ public static extern Timespec gprsharp_inf_past(ClockType clockType);
[DllImport("grpc_csharp_ext.dll")]
- public static extern Timespec gprsharp_convert_clock_type(Timespec t, GPRClockType targetClock);
+ public static extern Timespec gprsharp_convert_clock_type(Timespec t, ClockType targetClock);
[DllImport("grpc_csharp_ext.dll")]
public static extern int gprsharp_sizeof_timespec();
@@ -814,7 +823,7 @@ namespace Grpc.Core.Internal
// Testing
[DllImport("grpc_csharp_ext.dll")]
- public static extern GRPCCallError grpcsharp_test_callback([MarshalAs(UnmanagedType.FunctionPtr)] OpCompletionDelegate callback);
+ public static extern CallError grpcsharp_test_callback([MarshalAs(UnmanagedType.FunctionPtr)] OpCompletionDelegate callback);
[DllImport("grpc_csharp_ext.dll")]
public static extern IntPtr grpcsharp_test_nop(IntPtr ptr);
diff --git a/src/csharp/Grpc.Core/Internal/PlatformApis.cs b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
index fb1acfb607..5d8c44b589 100644
--- a/src/csharp/Grpc.Core/Internal/PlatformApis.cs
+++ b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index ccf144de2d..6a2f520163 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,7 @@ namespace Grpc.Core.Internal
{
internal interface IServerCallHandler
{
- Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment);
+ Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq);
}
internal class UnaryServerCallHandler<TRequest, TResponse> : IServerCallHandler
@@ -62,42 +62,45 @@ namespace Grpc.Core.Internal
this.handler = handler;
}
- public async Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment)
+ public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer,
- environment, newRpc.Server);
+ newRpc.Server);
- asyncCall.Initialize(newRpc.Call);
+ asyncCall.Initialize(newRpc.Call, cq);
var finishedTask = asyncCall.ServerSideCallAsync();
var requestStream = new ServerRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
+ Tuple<TResponse,WriteFlags> responseTuple = null;
var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken);
try
{
GrpcPreconditions.CheckArgument(await requestStream.MoveNext().ConfigureAwait(false));
var request = requestStream.Current;
- // TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated.
- GrpcPreconditions.CheckArgument(!await requestStream.MoveNext().ConfigureAwait(false));
- var result = await handler(request, context).ConfigureAwait(false);
+ var response = await handler(request, context).ConfigureAwait(false);
status = context.Status;
- await responseStream.WriteAsync(result).ConfigureAwait(false);
+ responseTuple = Tuple.Create(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured in handler.");
+ if (!(e is RpcException))
+ {
+ Logger.Warning(e, "Exception occured in handler.");
+ }
status = HandlerUtils.StatusFromException(e);
}
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
+ await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseTuple).ConfigureAwait(false);
}
- catch (OperationCanceledException)
+ catch (Exception)
{
- // Call has been already cancelled.
+ asyncCall.Cancel();
+ throw;
}
await finishedTask.ConfigureAwait(false);
}
@@ -118,14 +121,14 @@ namespace Grpc.Core.Internal
this.handler = handler;
}
- public async Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment)
+ public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer,
- environment, newRpc.Server);
+ newRpc.Server);
- asyncCall.Initialize(newRpc.Call);
+ asyncCall.Initialize(newRpc.Call, cq);
var finishedTask = asyncCall.ServerSideCallAsync();
var requestStream = new ServerRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
@@ -136,24 +139,26 @@ namespace Grpc.Core.Internal
{
GrpcPreconditions.CheckArgument(await requestStream.MoveNext().ConfigureAwait(false));
var request = requestStream.Current;
- // TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated.
- GrpcPreconditions.CheckArgument(!await requestStream.MoveNext().ConfigureAwait(false));
await handler(request, responseStream, context).ConfigureAwait(false);
status = context.Status;
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured in handler.");
+ if (!(e is RpcException))
+ {
+ Logger.Warning(e, "Exception occured in handler.");
+ }
status = HandlerUtils.StatusFromException(e);
}
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
+ await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, null).ConfigureAwait(false);
}
- catch (OperationCanceledException)
+ catch (Exception)
{
- // Call has been already cancelled.
+ asyncCall.Cancel();
+ throw;
}
await finishedTask.ConfigureAwait(false);
}
@@ -174,46 +179,44 @@ namespace Grpc.Core.Internal
this.handler = handler;
}
- public async Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment)
+ public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer,
- environment, newRpc.Server);
+ newRpc.Server);
- asyncCall.Initialize(newRpc.Call);
+ asyncCall.Initialize(newRpc.Call, cq);
var finishedTask = asyncCall.ServerSideCallAsync();
var requestStream = new ServerRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
+ Tuple<TResponse,WriteFlags> responseTuple = null;
var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken);
try
{
- var result = await handler(requestStream, context).ConfigureAwait(false);
+ var response = await handler(requestStream, context).ConfigureAwait(false);
status = context.Status;
- try
- {
- await responseStream.WriteAsync(result).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- status = Status.DefaultCancelled;
- }
+ responseTuple = Tuple.Create(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured in handler.");
+ if (!(e is RpcException))
+ {
+ Logger.Warning(e, "Exception occured in handler.");
+ }
status = HandlerUtils.StatusFromException(e);
}
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
+ await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseTuple).ConfigureAwait(false);
}
- catch (OperationCanceledException)
+ catch (Exception)
{
- // Call has been already cancelled.
+ asyncCall.Cancel();
+ throw;
}
await finishedTask.ConfigureAwait(false);
}
@@ -234,14 +237,14 @@ namespace Grpc.Core.Internal
this.handler = handler;
}
- public async Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment)
+ public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
var asyncCall = new AsyncCallServer<TRequest, TResponse>(
method.ResponseMarshaller.Serializer,
method.RequestMarshaller.Deserializer,
- environment, newRpc.Server);
+ newRpc.Server);
- asyncCall.Initialize(newRpc.Call);
+ asyncCall.Initialize(newRpc.Call, cq);
var finishedTask = asyncCall.ServerSideCallAsync();
var requestStream = new ServerRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
@@ -255,16 +258,20 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured in handler.");
+ if (!(e is RpcException))
+ {
+ Logger.Warning(e, "Exception occured in handler.");
+ }
status = HandlerUtils.StatusFromException(e);
}
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
+ await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, null).ConfigureAwait(false);
}
- catch (OperationCanceledException)
+ catch (Exception)
{
- // Call has been already cancelled.
+ asyncCall.Cancel();
+ throw;
}
await finishedTask.ConfigureAwait(false);
}
@@ -274,17 +281,15 @@ namespace Grpc.Core.Internal
{
public static readonly NoSuchMethodCallHandler Instance = new NoSuchMethodCallHandler();
- public async Task HandleCall(ServerRpcNew newRpc, GrpcEnvironment environment)
+ public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
// We don't care about the payload type here.
var asyncCall = new AsyncCallServer<byte[], byte[]>(
- (payload) => payload, (payload) => payload, environment, newRpc.Server);
+ (payload) => payload, (payload) => payload, newRpc.Server);
- asyncCall.Initialize(newRpc.Call);
+ asyncCall.Initialize(newRpc.Call, cq);
var finishedTask = asyncCall.ServerSideCallAsync();
- var responseStream = new ServerResponseStream<byte[], byte[]>(asyncCall);
-
- await responseStream.WriteStatusAsync(new Status(StatusCode.Unimplemented, ""), Metadata.Empty).ConfigureAwait(false);
+ await asyncCall.SendStatusFromServerAsync(new Status(StatusCode.Unimplemented, ""), Metadata.Empty, null).ConfigureAwait(false);
await finishedTask.ConfigureAwait(false);
}
}
@@ -300,15 +305,19 @@ namespace Grpc.Core.Internal
return rpcException.Status;
}
- // TODO(jtattermusch): what is the right status code here?
return new Status(StatusCode.Unknown, "Exception was thrown by handler.");
}
+ public static WriteFlags GetWriteFlags(WriteOptions writeOptions)
+ {
+ return writeOptions != null ? writeOptions.Flags : default(WriteFlags);
+ }
+
public static ServerCallContext NewContext<TRequest, TResponse>(ServerRpcNew newRpc, string peer, ServerResponseStream<TRequest, TResponse> serverResponseStream, CancellationToken cancellationToken)
where TRequest : class
where TResponse : class
{
- DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime();
+ DateTime realtimeDeadline = newRpc.Deadline.ToClockType(ClockType.Realtime).ToDateTime();
return new ServerCallContext(newRpc.Call, newRpc.Method, newRpc.Host, peer, realtimeDeadline,
newRpc.RequestMetadata, cancellationToken, serverResponseStream.WriteResponseHeadersAsync, serverResponseStream);
diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
index a50f357990..24f686fddc 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs b/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
index e7be82c318..d76030d1ad 100644
--- a/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
@@ -68,9 +68,7 @@ namespace Grpc.Core.Internal
{
throw new InvalidOperationException("Cancellation of individual reads is not supported.");
}
- var taskSource = new AsyncCompletionTaskSource<TRequest>();
- call.StartReadMessage(taskSource.CompletionDelegate);
- var result = await taskSource.Task.ConfigureAwait(false);
+ var result = await call.ReadMessageAsync().ConfigureAwait(false);
this.current = result;
return result != null;
}
diff --git a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs
index 03e39efc02..25b79b4398 100644
--- a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs
@@ -52,23 +52,12 @@ namespace Grpc.Core.Internal
public Task WriteAsync(TResponse message)
{
- var taskSource = new AsyncCompletionTaskSource<object>();
- call.StartSendMessage(message, GetWriteFlags(), taskSource.CompletionDelegate);
- return taskSource.Task;
- }
-
- public Task WriteStatusAsync(Status status, Metadata trailers)
- {
- var taskSource = new AsyncCompletionTaskSource<object>();
- call.StartSendStatusFromServer(status, trailers, taskSource.CompletionDelegate);
- return taskSource.Task;
+ return call.SendMessageAsync(message, GetWriteFlags());
}
public Task WriteResponseHeadersAsync(Metadata responseHeaders)
{
- var taskSource = new AsyncCompletionTaskSource<object>();
- call.StartSendInitialMetadata(responseHeaders, taskSource.CompletionDelegate);
- return taskSource.Task;
+ return call.SendInitialMetadataAsync(responseHeaders);
}
public WriteOptions WriteOptions
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCompletion.cs b/src/csharp/Grpc.Core/Internal/ServerRpcNew.cs
index d5bbf676ff..e4f1880bdb 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCompletion.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerRpcNew.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -32,63 +32,78 @@
#endregion
using System;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Grpc.Core.Internal;
-using Grpc.Core.Utils;
+using Grpc.Core;
namespace Grpc.Core.Internal
{
/// <summary>
- /// If error != null, there's been an error or operation has been cancelled.
+ /// Details of a newly received RPC.
/// </summary>
- internal delegate void AsyncCompletionDelegate<T>(T result, Exception error);
-
- /// <summary>
- /// Helper for transforming AsyncCompletionDelegate into full-fledged Task.
- /// </summary>
- internal class AsyncCompletionTaskSource<T>
+ internal struct ServerRpcNew
{
- readonly TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
- readonly AsyncCompletionDelegate<T> completionDelegate;
+ readonly Server server;
+ readonly CallSafeHandle call;
+ readonly string method;
+ readonly string host;
+ readonly Timespec deadline;
+ readonly Metadata requestMetadata;
+
+ public ServerRpcNew(Server server, CallSafeHandle call, string method, string host, Timespec deadline, Metadata requestMetadata)
+ {
+ this.server = server;
+ this.call = call;
+ this.method = method;
+ this.host = host;
+ this.deadline = deadline;
+ this.requestMetadata = requestMetadata;
+ }
+
+ public Server Server
+ {
+ get
+ {
+ return this.server;
+ }
+ }
- public AsyncCompletionTaskSource()
+ public CallSafeHandle Call
{
- completionDelegate = new AsyncCompletionDelegate<T>(HandleCompletion);
+ get
+ {
+ return this.call;
+ }
}
- public Task<T> Task
+ public string Method
{
get
{
- return tcs.Task;
+ return this.method;
}
}
- public AsyncCompletionDelegate<T> CompletionDelegate
+ public string Host
{
get
{
- return completionDelegate;
+ return this.host;
}
}
- private void HandleCompletion(T value, Exception error)
+ public Timespec Deadline
{
- if (error == null)
+ get
{
- tcs.SetResult(value);
- return;
+ return this.deadline;
}
- if (error is OperationCanceledException)
+ }
+
+ public Metadata RequestMetadata
+ {
+ get
{
- tcs.SetCanceled();
- return;
+ return this.requestMetadata;
}
- tcs.SetException(error);
}
}
}
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index a57fb3b789..8581302706 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -31,12 +31,6 @@
#endregion
-using System;
-using System.Collections.Concurrent;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using Grpc.Core.Utils;
-
namespace Grpc.Core.Internal
{
/// <summary>
@@ -50,12 +44,17 @@ namespace Grpc.Core.Internal
{
}
- public static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args)
+ public static ServerSafeHandle NewServer(ChannelArgsSafeHandle args)
{
// Increment reference count for the native gRPC environment to make sure we don't do grpc_shutdown() before destroying the server handle.
// Doing so would make object finalizer crash if we end up abandoning the handle.
GrpcEnvironment.GrpcNativeInit();
- return Native.grpcsharp_server_create(cq, args);
+ return Native.grpcsharp_server_create(args);
+ }
+
+ public void RegisterCompletionQueue(CompletionQueueSafeHandle cq)
+ {
+ Native.grpcsharp_server_register_completion_queue(this, cq);
}
public int AddInsecurePort(string addr)
@@ -73,18 +72,18 @@ namespace Grpc.Core.Internal
Native.grpcsharp_server_start(this);
}
- public void ShutdownAndNotify(BatchCompletionDelegate callback, GrpcEnvironment environment)
+ public void ShutdownAndNotify(BatchCompletionDelegate callback, CompletionQueueSafeHandle completionQueue)
{
var ctx = BatchContextSafeHandle.Create();
- environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
- Native.grpcsharp_server_shutdown_and_notify_callback(this, environment.CompletionQueue, ctx);
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+ Native.grpcsharp_server_shutdown_and_notify_callback(this, completionQueue, ctx);
}
- public void RequestCall(BatchCompletionDelegate callback, GrpcEnvironment environment)
+ public void RequestCall(BatchCompletionDelegate callback, CompletionQueueSafeHandle completionQueue)
{
var ctx = BatchContextSafeHandle.Create();
- environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
- Native.grpcsharp_server_request_call(this, environment.CompletionQueue, ctx).CheckOk();
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+ Native.grpcsharp_server_request_call(this, completionQueue, ctx).CheckOk();
}
protected override bool ReleaseHandle()
diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs
index 754be4e035..c9fd710e1e 100644
--- a/src/csharp/Grpc.Core/Internal/Timespec.cs
+++ b/src/csharp/Grpc.Core/Internal/Timespec.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -49,11 +49,11 @@ namespace Grpc.Core.Internal
static readonly NativeMethods Native = NativeMethods.Get();
static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
- public Timespec(long tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, GPRClockType.Realtime)
+ public Timespec(long tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, ClockType.Realtime)
{
}
- public Timespec(long tv_sec, int tv_nsec, GPRClockType clock_type)
+ public Timespec(long tv_sec, int tv_nsec, ClockType clock_type)
{
this.tv_sec = tv_sec;
this.tv_nsec = tv_nsec;
@@ -62,7 +62,7 @@ namespace Grpc.Core.Internal
private long tv_sec;
private int tv_nsec;
- private GPRClockType clock_type;
+ private ClockType clock_type;
/// <summary>
/// Timespec a long time in the future.
@@ -71,7 +71,7 @@ namespace Grpc.Core.Internal
{
get
{
- return Native.gprsharp_inf_future(GPRClockType.Realtime);
+ return new Timespec(long.MaxValue, 0, ClockType.Realtime);
}
}
@@ -82,7 +82,7 @@ namespace Grpc.Core.Internal
{
get
{
- return Native.gprsharp_inf_past(GPRClockType.Realtime);
+ return new Timespec(long.MinValue, 0, ClockType.Realtime);
}
}
@@ -93,7 +93,7 @@ namespace Grpc.Core.Internal
{
get
{
- return Native.gprsharp_now(GPRClockType.Realtime);
+ return Native.gprsharp_now(ClockType.Realtime);
}
}
@@ -122,7 +122,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Converts the timespec to desired clock type.
/// </summary>
- public Timespec ToClockType(GPRClockType targetClock)
+ public Timespec ToClockType(ClockType targetClock)
{
return Native.gprsharp_convert_clock_type(this, targetClock);
}
@@ -142,7 +142,7 @@ namespace Grpc.Core.Internal
public DateTime ToDateTime()
{
GrpcPreconditions.CheckState(tv_nsec >= 0 && tv_nsec < NanosPerSecond);
- GrpcPreconditions.CheckState(clock_type == GPRClockType.Realtime);
+ GrpcPreconditions.CheckState(clock_type == ClockType.Realtime);
// fast path for InfFuture
if (this.Equals(InfFuture))
@@ -227,10 +227,11 @@ namespace Grpc.Core.Internal
{
get
{
- return Native.gprsharp_now(GPRClockType.Precise);
+ return Native.gprsharp_now(ClockType.Precise);
}
}
+ // for tests only
internal static int NativeSize
{
get
@@ -238,5 +239,23 @@ namespace Grpc.Core.Internal
return Native.gprsharp_sizeof_timespec();
}
}
+
+ // for tests only
+ internal static Timespec NativeInfFuture
+ {
+ get
+ {
+ return Native.gprsharp_inf_future(ClockType.Realtime);
+ }
+ }
+
+ // for tests only
+ public static Timespec NativeInfPast
+ {
+ get
+ {
+ return Native.gprsharp_inf_past(ClockType.Realtime);
+ }
+ }
}
}
diff --git a/src/csharp/Grpc.Core/Internal/UnimplementedCallInvoker.cs b/src/csharp/Grpc.Core/Internal/UnimplementedCallInvoker.cs
new file mode 100644
index 0000000000..0c7340873b
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/UnimplementedCallInvoker.cs
@@ -0,0 +1,75 @@
+#region Copyright notice and license
+
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+ /// <summary>
+ /// Call invoker that throws <c>NotImplementedException</c> for all requests.
+ /// </summary>
+ internal class UnimplementedCallInvoker : CallInvoker
+ {
+ public UnimplementedCallInvoker()
+ {
+ }
+
+ public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
index e763c15025..5a80746101 100644
--- a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
+++ b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -32,8 +32,6 @@
#endregion
using System;
-using System.Collections.Concurrent;
-using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
@@ -63,14 +61,9 @@ namespace Grpc.Core.Internal
readonly string libraryPath;
readonly IntPtr handle;
- public UnmanagedLibrary(string libraryPath)
+ public UnmanagedLibrary(string[] libraryPathAlternatives)
{
- this.libraryPath = GrpcPreconditions.CheckNotNull(libraryPath);
-
- if (!File.Exists(this.libraryPath))
- {
- throw new FileNotFoundException("Error loading native library. File does not exist.", this.libraryPath);
- }
+ this.libraryPath = FirstValidLibraryPath(libraryPathAlternatives);
Logger.Debug("Attempting to load native library \"{0}\"", this.libraryPath);
@@ -139,6 +132,19 @@ namespace Grpc.Core.Internal
throw new InvalidOperationException("Unsupported platform.");
}
+ private static string FirstValidLibraryPath(string[] libraryPathAlternatives)
+ {
+ GrpcPreconditions.CheckArgument(libraryPathAlternatives.Length > 0, "libraryPathAlternatives cannot be empty.");
+ foreach (var path in libraryPathAlternatives)
+ {
+ if (File.Exists(path))
+ {
+ return path;
+ }
+ }
+ throw new FileNotFoundException(String.Format("Error loading native library. Not found in any of the possible locations {0}", libraryPathAlternatives));
+ }
+
private static class Windows
{
[DllImport("kernel32.dll")]
diff --git a/src/csharp/Grpc.Core/KeyCertificatePair.cs b/src/csharp/Grpc.Core/KeyCertificatePair.cs
index 0fb6817986..a8f3bb073d 100644
--- a/src/csharp/Grpc.Core/KeyCertificatePair.cs
+++ b/src/csharp/Grpc.Core/KeyCertificatePair.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
index 5c5b802164..5e8dced641 100644
--- a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
+++ b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
@@ -33,118 +33,33 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
namespace Grpc.Core.Logging
{
/// <summary>Logger that logs to System.Console.</summary>
- public class ConsoleLogger : ILogger
+ public class ConsoleLogger : TextWriterLogger
{
- readonly Type forType;
- readonly string forTypeString;
-
/// <summary>Creates a console logger not associated to any specific type.</summary>
public ConsoleLogger() : this(null)
{
}
/// <summary>Creates a console logger that logs messsage specific for given type.</summary>
- private ConsoleLogger(Type forType)
+ private ConsoleLogger(Type forType) : base(() => Console.Error, forType)
{
- this.forType = forType;
- if (forType != null)
- {
- var namespaceStr = forType.Namespace ?? "";
- if (namespaceStr.Length > 0)
- {
- namespaceStr += ".";
- }
- this.forTypeString = namespaceStr + forType.Name + " ";
- }
- else
- {
- this.forTypeString = "";
- }
}
/// <summary>
/// Returns a logger associated with the specified type.
/// </summary>
- public ILogger ForType<T>()
+ public override ILogger ForType<T>()
{
- if (typeof(T) == forType)
+ if (typeof(T) == AssociatedType)
{
return this;
}
return new ConsoleLogger(typeof(T));
}
-
- /// <summary>Logs a message with severity Debug.</summary>
- public void Debug(string message)
- {
- Log("D", message);
- }
-
- /// <summary>Logs a formatted message with severity Debug.</summary>
- public void Debug(string format, params object[] formatArgs)
- {
- Debug(string.Format(format, formatArgs));
- }
-
- /// <summary>Logs a message with severity Info.</summary>
- public void Info(string message)
- {
- Log("I", message);
- }
-
- /// <summary>Logs a formatted message with severity Info.</summary>
- public void Info(string format, params object[] formatArgs)
- {
- Info(string.Format(format, formatArgs));
- }
-
- /// <summary>Logs a message with severity Warning.</summary>
- public void Warning(string message)
- {
- Log("W", message);
- }
-
- /// <summary>Logs a formatted message with severity Warning.</summary>
- public void Warning(string format, params object[] formatArgs)
- {
- Warning(string.Format(format, formatArgs));
- }
-
- /// <summary>Logs a message and an associated exception with severity Warning.</summary>
- public void Warning(Exception exception, string message)
- {
- Warning(message + " " + exception);
- }
-
- /// <summary>Logs a message with severity Error.</summary>
- public void Error(string message)
- {
- Log("E", message);
- }
-
- /// <summary>Logs a formatted message with severity Error.</summary>
- public void Error(string format, params object[] formatArgs)
- {
- Error(string.Format(format, formatArgs));
- }
-
- /// <summary>Logs a message and an associated exception with severity Error.</summary>
- public void Error(Exception exception, string message)
- {
- Error(message + " " + exception);
- }
-
- private void Log(string severityString, string message)
- {
- Console.Error.WriteLine("{0}{1} {2}{3}",
- severityString,
- DateTime.Now,
- forTypeString,
- message);
- }
}
}
diff --git a/src/csharp/Grpc.Core/Logging/TextWriterLogger.cs b/src/csharp/Grpc.Core/Logging/TextWriterLogger.cs
new file mode 100644
index 0000000000..397320ddff
--- /dev/null
+++ b/src/csharp/Grpc.Core/Logging/TextWriterLogger.cs
@@ -0,0 +1,176 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Logging
+{
+ /// <summary>Logger that logs to an arbitrary <c>System.IO.TextWriter</c>.</summary>
+ public class TextWriterLogger : ILogger
+ {
+ // Format similar enough to C core log format except nanosecond precision is not supported.
+ const string DateTimeFormatString = "MMdd HH:mm:ss.ffffff";
+
+ readonly Func<TextWriter> textWriterProvider;
+ readonly Type forType;
+ readonly string forTypeString;
+
+ /// <summary>
+ /// Creates a console logger not associated to any specific type and writes to given <c>System.IO.TextWriter</c>.
+ /// User is responsible for providing an instance of TextWriter that is thread-safe.
+ /// </summary>
+ public TextWriterLogger(TextWriter textWriter) : this(() => textWriter)
+ {
+ GrpcPreconditions.CheckNotNull(textWriter);
+ }
+
+ /// <summary>
+ /// Creates a console logger not associated to any specific type and writes to a <c>System.IO.TextWriter</c> obtained from given provider.
+ /// User is responsible for providing an instance of TextWriter that is thread-safe.
+ /// </summary>
+ public TextWriterLogger(Func<TextWriter> textWriterProvider) : this(textWriterProvider, null)
+ {
+ }
+
+ /// <summary>Creates a console logger that logs messsage specific for given type.</summary>
+ protected TextWriterLogger(Func<TextWriter> textWriterProvider, Type forType)
+ {
+ this.textWriterProvider = GrpcPreconditions.CheckNotNull(textWriterProvider);
+ this.forType = forType;
+ if (forType != null)
+ {
+ var namespaceStr = forType.Namespace ?? "";
+ if (namespaceStr.Length > 0)
+ {
+ namespaceStr += ".";
+ }
+ this.forTypeString = namespaceStr + forType.Name + " ";
+ }
+ else
+ {
+ this.forTypeString = "";
+ }
+ }
+
+ /// <summary>
+ /// Returns a logger associated with the specified type.
+ /// </summary>
+ public virtual ILogger ForType<T>()
+ {
+ if (typeof(T) == forType)
+ {
+ return this;
+ }
+ return new TextWriterLogger(this.textWriterProvider, typeof(T));
+ }
+
+ /// <summary>Logs a message with severity Debug.</summary>
+ public void Debug(string message)
+ {
+ Log("D", message);
+ }
+
+ /// <summary>Logs a formatted message with severity Debug.</summary>
+ public void Debug(string format, params object[] formatArgs)
+ {
+ Debug(string.Format(format, formatArgs));
+ }
+
+ /// <summary>Logs a message with severity Info.</summary>
+ public void Info(string message)
+ {
+ Log("I", message);
+ }
+
+ /// <summary>Logs a formatted message with severity Info.</summary>
+ public void Info(string format, params object[] formatArgs)
+ {
+ Info(string.Format(format, formatArgs));
+ }
+
+ /// <summary>Logs a message with severity Warning.</summary>
+ public void Warning(string message)
+ {
+ Log("W", message);
+ }
+
+ /// <summary>Logs a formatted message with severity Warning.</summary>
+ public void Warning(string format, params object[] formatArgs)
+ {
+ Warning(string.Format(format, formatArgs));
+ }
+
+ /// <summary>Logs a message and an associated exception with severity Warning.</summary>
+ public void Warning(Exception exception, string message)
+ {
+ Warning(message + " " + exception);
+ }
+
+ /// <summary>Logs a message with severity Error.</summary>
+ public void Error(string message)
+ {
+ Log("E", message);
+ }
+
+ /// <summary>Logs a formatted message with severity Error.</summary>
+ public void Error(string format, params object[] formatArgs)
+ {
+ Error(string.Format(format, formatArgs));
+ }
+
+ /// <summary>Logs a message and an associated exception with severity Error.</summary>
+ public void Error(Exception exception, string message)
+ {
+ Error(message + " " + exception);
+ }
+
+ /// <summary>Gets the type associated with this logger.</summary>
+ protected Type AssociatedType
+ {
+ get { return forType; }
+ }
+
+ private void Log(string severityString, string message)
+ {
+ textWriterProvider().WriteLine("{0}{1} {2}{3}",
+ severityString,
+ DateTime.Now.ToString(DateTimeFormatString, CultureInfo.InvariantCulture),
+ forTypeString,
+ message);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs
index 5847248c1a..d86e75b3cb 100644
--- a/src/csharp/Grpc.Core/Marshaller.cs
+++ b/src/csharp/Grpc.Core/Marshaller.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index 52cef96f40..e982fa0c48 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs
index 3870076f7f..0cf041be2b 100644
--- a/src/csharp/Grpc.Core/Method.cs
+++ b/src/csharp/Grpc.Core/Method.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Profiling/Profilers.cs b/src/csharp/Grpc.Core/Profiling/Profilers.cs
index 8a181447d6..aa0d96c0e0 100644
--- a/src/csharp/Grpc.Core/Profiling/Profilers.cs
+++ b/src/csharp/Grpc.Core/Profiling/Profilers.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
index bde74945fb..370fa98687 100644
--- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
@@ -16,6 +16,12 @@ using System.Runtime.CompilerServices;
"0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
"27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" +
"71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")]
+[assembly: InternalsVisibleTo("Grpc.IntegrationTesting,PublicKey=" +
+ "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" +
+ "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
+ "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" +
+ "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")]
#else
[assembly: InternalsVisibleTo("Grpc.Core.Tests")]
+[assembly: InternalsVisibleTo("Grpc.IntegrationTesting")]
#endif
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index 5d0fc6b1f0..069185e13a 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
+using System.Linq;
using System.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Logging;
@@ -48,6 +47,7 @@ namespace Grpc.Core
/// </summary>
public class Server
{
+ const int InitialAllowRpcTokenCountPerCq = 10;
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Server>();
readonly AtomicCounter activeCallCounter = new AtomicCounter();
@@ -65,7 +65,7 @@ namespace Grpc.Core
readonly TaskCompletionSource<object> shutdownTcs = new TaskCompletionSource<object>();
bool startRequested;
- bool shutdownRequested;
+ volatile bool shutdownRequested;
/// <summary>
/// Create a new server.
@@ -79,7 +79,12 @@ namespace Grpc.Core
this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
using (var channelArgs = ChannelOptions.CreateChannelArgs(this.options))
{
- this.handle = ServerSafeHandle.NewServer(environment.CompletionQueue, channelArgs);
+ this.handle = ServerSafeHandle.NewServer(channelArgs);
+ }
+
+ foreach (var cq in environment.CompletionQueues)
+ {
+ this.handle.RegisterCompletionQueue(cq);
}
}
@@ -129,7 +134,16 @@ namespace Grpc.Core
startRequested = true;
handle.Start();
- AllowOneRpc();
+
+ // Starting with more than one AllowOneRpc tokens can significantly increase
+ // unary RPC throughput.
+ for (int i = 0; i < InitialAllowRpcTokenCountPerCq; i++)
+ {
+ foreach (var cq in environment.CompletionQueues)
+ {
+ AllowOneRpc(cq);
+ }
+ }
}
}
@@ -147,7 +161,8 @@ namespace Grpc.Core
shutdownRequested = true;
}
- handle.ShutdownAndNotify(HandleServerShutdown, environment);
+ var cq = environment.CompletionQueues.First(); // any cq will do
+ handle.ShutdownAndNotify(HandleServerShutdown, cq);
await shutdownTcs.Task.ConfigureAwait(false);
DisposeHandle();
@@ -167,7 +182,8 @@ namespace Grpc.Core
shutdownRequested = true;
}
- handle.ShutdownAndNotify(HandleServerShutdown, environment);
+ var cq = environment.CompletionQueues.First(); // any cq will do
+ handle.ShutdownAndNotify(HandleServerShutdown, cq);
handle.CancelAllCalls();
await shutdownTcs.Task.ConfigureAwait(false);
DisposeHandle();
@@ -237,14 +253,11 @@ namespace Grpc.Core
/// <summary>
/// Allows one new RPC call to be received by server.
/// </summary>
- private void AllowOneRpc()
+ private void AllowOneRpc(CompletionQueueSafeHandle cq)
{
- lock (myLock)
+ if (!shutdownRequested)
{
- if (!shutdownRequested)
- {
- handle.RequestCall(HandleNewServerRpc, environment);
- }
+ handle.RequestCall((success, ctx) => HandleNewServerRpc(success, ctx, cq), cq);
}
}
@@ -261,7 +274,7 @@ namespace Grpc.Core
/// <summary>
/// Selects corresponding handler for given call and handles the call.
/// </summary>
- private async Task HandleCallAsync(ServerRpcNew newRpc)
+ private async Task HandleCallAsync(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
try
{
@@ -270,7 +283,7 @@ namespace Grpc.Core
{
callHandler = NoSuchMethodCallHandler.Instance;
}
- await callHandler.HandleCall(newRpc, environment).ConfigureAwait(false);
+ await callHandler.HandleCall(newRpc, cq).ConfigureAwait(false);
}
catch (Exception e)
{
@@ -281,8 +294,10 @@ namespace Grpc.Core
/// <summary>
/// Handles the native callback.
/// </summary>
- private void HandleNewServerRpc(bool success, BatchContextSafeHandle ctx)
+ private void HandleNewServerRpc(bool success, BatchContextSafeHandle ctx, CompletionQueueSafeHandle cq)
{
+ Task.Run(() => AllowOneRpc(cq));
+
if (success)
{
ServerRpcNew newRpc = ctx.GetServerRpcNew(this);
@@ -290,11 +305,9 @@ namespace Grpc.Core
// after server shutdown, the callback returns with null call
if (!newRpc.Call.IsInvalid)
{
- Task.Run(async () => await HandleCallAsync(newRpc)).ConfigureAwait(false);
+ HandleCallAsync(newRpc, cq); // we don't need to await.
}
}
-
- AllowOneRpc();
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs
index 456d331c9c..ace4820027 100644
--- a/src/csharp/Grpc.Core/ServerCredentials.cs
+++ b/src/csharp/Grpc.Core/ServerCredentials.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/ServerPort.cs b/src/csharp/Grpc.Core/ServerPort.cs
index 10ddcb782f..afae0846dd 100644
--- a/src/csharp/Grpc.Core/ServerPort.cs
+++ b/src/csharp/Grpc.Core/ServerPort.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Utils/GrpcPreconditions.cs b/src/csharp/Grpc.Core/Utils/GrpcPreconditions.cs
index 76bf04ce8b..fcfe97a09b 100644
--- a/src/csharp/Grpc.Core/Utils/GrpcPreconditions.cs
+++ b/src/csharp/Grpc.Core/Utils/GrpcPreconditions.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs
index 6d88438a07..f5c44fd098 100644
--- a/src/csharp/Grpc.Core/Version.cs
+++ b/src/csharp/Grpc.Core/Version.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -33,5 +33,6 @@
using System.Reflection;
-// The current version of gRPC C#.
[assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentAssemblyVersion)]
+[assembly: AssemblyFileVersion(Grpc.Core.VersionInfo.CurrentAssemblyFileVersion)]
+[assembly: AssemblyInformationalVersion(Grpc.Core.VersionInfo.CurrentVersion)]
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 4bd4f204dd..e1609341d9 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -35,17 +35,24 @@ namespace Grpc.Core
{
/// <summary>
/// Provides info about current version of gRPC.
+ /// See https://codingforsmarties.wordpress.com/2016/01/21/how-to-version-assemblies-destined-for-nuget/
+ /// for rationale about assembly versioning.
/// </summary>
public static class VersionInfo
{
/// <summary>
- /// Current version of gRPC C# assemblies
+ /// Current <c>AssemblyVersion</c> attribute of gRPC C# assemblies
/// </summary>
- public const string CurrentAssemblyVersion = "0.14.0.0";
+ public const string CurrentAssemblyVersion = "1.0.0.0";
+
+ /// <summary>
+ /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
+ /// </summary>
+ public const string CurrentAssemblyFileVersion = "0.15.0.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "0.14.0-dev";
+ public const string CurrentVersion = "0.15.0-dev";
}
}
diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
index 64e429ed5a..aadef6833d 100644
--- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs
+++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@ namespace Math
public static void Main(string[] args)
{
var channel = new Channel("127.0.0.1", 23456, ChannelCredentials.Insecure);
- Math.IMathClient client = new Math.MathClient(channel);
+ Math.MathClient client = new Math.MathClient(channel);
MathExamples.DivExample(client);
MathExamples.DivAsyncExample(client).Wait();
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index 9aeab059f9..3fd28c6528 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -3,10 +3,8 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>10.0.0</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}</ProjectGuid>
- <OutputType>Library</OutputType>
+ <OutputType>Exe</OutputType>
<RootNamespace>Grpc.Examples.Tests</RootNamespace>
<AssemblyName>Grpc.Examples.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
@@ -37,18 +35,19 @@
<AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Protobuf.3.0.0-beta2\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
+ <Reference Include="System" />
+ <Reference Include="Google.Protobuf">
+ <HintPath>..\packages\Google.Protobuf.3.0.0-beta3\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
- <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
+ <HintPath>..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll</HintPath>
</Reference>
- <Reference Include="System" />
- <Reference Include="System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
+ <Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.5\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
+ <Reference Include="nunitlite">
+ <HintPath>..\packages\NUnitLite.3.2.0\lib\net45\nunitlite.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@@ -56,6 +55,7 @@
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MathClientServerTests.cs" />
+ <Compile Include="NUnitMain.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index 290d42808e..ee11105efe 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -92,7 +92,7 @@ namespace Math.Tests
public void DivByZero()
{
var ex = Assert.Throws<RpcException>(() => client.Div(new DivArgs { Dividend = 0, Divisor = 0 }));
- Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode);
+ Assert.AreEqual(StatusCode.InvalidArgument, ex.Status.StatusCode);
}
[Test]
@@ -149,7 +149,7 @@ namespace Math.Tests
using (var call = client.Fib(new FibArgs { Limit = 0 },
deadline: DateTime.UtcNow.AddMilliseconds(500)))
{
- var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.ToListAsync());
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.ToListAsync());
// We can't guarantee the status code always DeadlineExceeded. See issue #2685.
Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal });
diff --git a/src/csharp/Grpc.Examples.Tests/NUnitMain.cs b/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
new file mode 100644
index 0000000000..ea87802766
--- /dev/null
+++ b/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
@@ -0,0 +1,59 @@
+#region Copyright notice and license
+
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Reflection;
+using Grpc.Core;
+using Grpc.Core.Logging;
+using NUnit.Common;
+using NUnitLite;
+
+namespace Grpc.Examples.Tests
+{
+ /// <summary>
+ /// Provides entry point for NUnitLite
+ /// </summary>
+ public class NUnitMain
+ {
+ public static int Main(string[] args)
+ {
+ // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
+ GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
+#if DOTNET5_4
+ return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
+#else
+ return new AutoRun().Execute(args);
+#endif
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Examples.Tests/packages.config b/src/csharp/Grpc.Examples.Tests/packages.config
index ed30d2d428..668601af8e 100644
--- a/src/csharp/Grpc.Examples.Tests/packages.config
+++ b/src/csharp/Grpc.Examples.Tests/packages.config
@@ -1,6 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
- <package id="Google.Protobuf" version="3.0.0-beta2" targetFramework="net45" />
- <package id="Ix-Async" version="1.2.5" targetFramework="net45" />
- <package id="NUnit" version="2.6.4" targetFramework="net45" />
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Google.Protobuf" version="3.0.0-beta3" targetFramework="net45" />
+ <package id="Ix-Async" version="1.2.5" targetFramework="net45" />
+ <package id="NUnit" version="3.2.0" targetFramework="net45" />
+ <package id="NUnitLite" version="3.2.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index 15b04c8d8b..30170ab03c 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -39,7 +39,10 @@
<ItemGroup>
<Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Protobuf.3.0.0-beta2\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
+ <HintPath>..\packages\Google.Protobuf.3.0.0-beta3\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
+ </Reference>
+ <Reference Include="nunit.framework">
+ <HintPath>..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data.Linq" />
diff --git a/src/csharp/Grpc.Examples/Math.cs b/src/csharp/Grpc.Examples/Math.cs
index 33c4f8d9c0..a17228c8c5 100644
--- a/src/csharp/Grpc.Examples/Math.cs
+++ b/src/csharp/Grpc.Examples/Math.cs
@@ -34,12 +34,12 @@ namespace Math {
"Mw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
- new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
- new pbr::GeneratedCodeInfo(typeof(global::Math.DivArgs), global::Math.DivArgs.Parser, new[]{ "Dividend", "Divisor" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Math.DivReply), global::Math.DivReply.Parser, new[]{ "Quotient", "Remainder" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Math.FibArgs), global::Math.FibArgs.Parser, new[]{ "Limit" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Math.Num), global::Math.Num.Parser, new[]{ "Num_" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Math.FibReply), global::Math.FibReply.Parser, new[]{ "Count" }, null, null, null)
+ new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Math.DivArgs), global::Math.DivArgs.Parser, new[]{ "Dividend", "Divisor" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Math.DivReply), global::Math.DivReply.Parser, new[]{ "Quotient", "Remainder" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Math.FibArgs), global::Math.FibArgs.Parser, new[]{ "Limit" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Math.Num), global::Math.Num.Parser, new[]{ "Num_" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Math.FibReply), global::Math.FibReply.Parser, new[]{ "Count" }, null, null, null)
}));
}
#endregion
diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs
index 8009ccbbfa..d260830b94 100644
--- a/src/csharp/Grpc.Examples/MathExamples.cs
+++ b/src/csharp/Grpc.Examples/MathExamples.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -32,25 +32,26 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using Grpc.Core;
using Grpc.Core.Utils;
namespace Math
{
public static class MathExamples
{
- public static void DivExample(Math.IMathClient client)
+ public static void DivExample(Math.MathClient client)
{
DivReply result = client.Div(new DivArgs { Dividend = 10, Divisor = 3 });
Console.WriteLine("Div Result: " + result);
}
- public static async Task DivAsyncExample(Math.IMathClient client)
+ public static async Task DivAsyncExample(Math.MathClient client)
{
DivReply result = await client.DivAsync(new DivArgs { Dividend = 4, Divisor = 5 });
Console.WriteLine("DivAsync Result: " + result);
}
- public static async Task FibExample(Math.IMathClient client)
+ public static async Task FibExample(Math.MathClient client)
{
using (var call = client.Fib(new FibArgs { Limit = 5 }))
{
@@ -59,7 +60,7 @@ namespace Math
}
}
- public static async Task SumExample(Math.IMathClient client)
+ public static async Task SumExample(Math.MathClient client)
{
var numbers = new List<Num>
{
@@ -75,7 +76,7 @@ namespace Math
}
}
- public static async Task DivManyExample(Math.IMathClient client)
+ public static async Task DivManyExample(Math.MathClient client)
{
var divArgsList = new List<DivArgs>
{
@@ -90,7 +91,7 @@ namespace Math
}
}
- public static async Task DependendRequestsExample(Math.IMathClient client)
+ public static async Task DependendRequestsExample(Math.MathClient client)
{
var numbers = new List<Num>
{
@@ -109,5 +110,42 @@ namespace Math
DivReply result = await client.DivAsync(new DivArgs { Dividend = sum.Num_, Divisor = numbers.Count });
Console.WriteLine("Avg Result: " + result);
}
+
+ /// <summary>
+ /// Shows how to handle a call ending with non-OK status.
+ /// </summary>
+ public static async Task HandleErrorExample(Math.MathClient client)
+ {
+ try
+ {
+ DivReply result = await client.DivAsync(new DivArgs { Dividend = 5, Divisor = 0 });
+ }
+ catch (RpcException ex)
+ {
+ Console.WriteLine(string.Format("RPC ended with status {0}", ex.Status));
+ }
+ }
+
+ /// <summary>
+ /// Shows how to send request headers and how to access response headers
+ /// and response trailers.
+ /// </summary>
+ public static async Task MetadataExample(Math.MathClient client)
+ {
+ var requestHeaders = new Metadata
+ {
+ { "custom-header", "custom-value" }
+ };
+
+ var call = client.DivAsync(new DivArgs { Dividend = 5, Divisor = 0 }, requestHeaders);
+
+ // Get response headers
+ Metadata responseHeaders = await call.ResponseHeadersAsync;
+
+ var result = await call;
+
+ // Get response trailers after the call has finished.
+ Metadata responseTrailers = call.GetTrailers();
+ }
}
}
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index a6e878d0f4..d700a18778 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -1,5 +1,35 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: math.proto
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
#region Designer generated code
using System;
@@ -45,96 +75,269 @@ namespace Math {
__Marshaller_Num,
__Marshaller_Num);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Math.MathReflection.Descriptor.Services[0]; }
}
- // client interface
+ /// <summary>Client for Math</summary>
+ [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IMathClient
{
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options);
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options);
+ /// <summary>
+ /// 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.
+ /// </summary>
AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// 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.
+ /// </summary>
AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options);
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options);
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of Math</summary>
+ [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IMath
{
- Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context);
- Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context);
- Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context);
- Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context);
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
+ global::System.Threading.Tasks.Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context);
+ /// <summary>
+ /// 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.
+ /// </summary>
+ global::System.Threading.Tasks.Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context);
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
+ global::System.Threading.Tasks.Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context);
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
+ global::System.Threading.Tasks.Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context);
}
- // client stub
- public class MathClient : ClientBase, IMathClient
+ /// <summary>Base class for server-side implementations of Math</summary>
+ public abstract class MathBase
+ {
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// <summary>Client for Math</summary>
+ #pragma warning disable 0618
+ public class MathClient : ClientBase<MathClient>, IMathClient
+ #pragma warning restore 0618
{
public MathClient(Channel channel) : base(channel)
{
}
- public global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public MathClient(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ protected MathClient() : base()
+ {
+ }
+ ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ protected MathClient(ClientBaseConfiguration configuration) : base(configuration)
{
- var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken));
- return Calls.BlockingUnaryCall(call, request);
}
- public global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options)
+
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
+ public virtual global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_Div, options);
- return Calls.BlockingUnaryCall(call, request);
+ return Div(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
+ public virtual global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options)
{
- var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncUnaryCall(call, request);
+ return CallInvoker.BlockingUnaryCall(__Method_Div, null, options, request);
}
- public AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options)
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_Div, options);
- return Calls.AsyncUnaryCall(call, request);
+ return DivAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options)
{
- var call = CreateCall(__Method_DivMany, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncDuplexStreamingCall(call);
+ return CallInvoker.AsyncUnaryCall(__Method_Div, null, options, request);
}
- public AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options)
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_DivMany, options);
- return Calls.AsyncDuplexStreamingCall(call);
+ return DivMany(new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options)
{
- var call = CreateCall(__Method_Fib, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncServerStreamingCall(call, request);
+ return CallInvoker.AsyncDuplexStreamingCall(__Method_DivMany, null, options);
}
- public AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options)
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
+ public virtual AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_Fib, options);
- return Calls.AsyncServerStreamingCall(call, request);
+ return Fib(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
+ public virtual AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options)
{
- var call = CreateCall(__Method_Sum, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncClientStreamingCall(call);
+ return CallInvoker.AsyncServerStreamingCall(__Method_Fib, null, options, request);
}
- public AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options)
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
+ public virtual AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_Sum, options);
- return Calls.AsyncClientStreamingCall(call);
+ return Sum(new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
+ public virtual AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options)
+ {
+ return CallInvoker.AsyncClientStreamingCall(__Method_Sum, null, options);
+ }
+ protected override MathClient NewInstance(ClientBaseConfiguration configuration)
+ {
+ return new MathClient(configuration);
+ }
+ }
+
+ /// <summary>Creates a new client for Math</summary>
+ public static MathClient NewClient(Channel channel)
+ {
+ return new MathClient(channel);
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
public static ServerServiceDefinition BindService(IMath serviceImpl)
+ #pragma warning restore 0618
{
return ServerServiceDefinition.CreateBuilder(__ServiceName)
.AddMethod(__Method_Div, serviceImpl.Div)
@@ -143,10 +346,16 @@ namespace Math {
.AddMethod(__Method_Sum, serviceImpl.Sum).Build();
}
- // creates a new client
- public static MathClient NewClient(Channel channel)
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
+ public static ServerServiceDefinition BindService(MathBase serviceImpl)
+ #pragma warning restore 0618
{
- return new MathClient(channel);
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_Div, serviceImpl.Div)
+ .AddMethod(__Method_DivMany, serviceImpl.DivMany)
+ .AddMethod(__Method_Fib, serviceImpl.Fib)
+ .AddMethod(__Method_Sum, serviceImpl.Sum).Build();
}
}
diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs
index 71dc655e46..a28020f62f 100644
--- a/src/csharp/Grpc.Examples/MathServiceImpl.cs
+++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -43,36 +43,28 @@ namespace Math
/// <summary>
/// Implementation of MathService server
/// </summary>
- public class MathServiceImpl : Math.IMath
+ public class MathServiceImpl : Math.MathBase
{
- public Task<DivReply> Div(DivArgs request, ServerCallContext context)
+ public override Task<DivReply> Div(DivArgs request, ServerCallContext context)
{
return Task.FromResult(DivInternal(request));
}
- public async Task Fib(FibArgs request, IServerStreamWriter<Num> responseStream, ServerCallContext context)
+ public override async Task Fib(FibArgs request, IServerStreamWriter<Num> responseStream, ServerCallContext context)
{
- if (request.Limit <= 0)
- {
- // keep streaming the sequence until cancelled.
- IEnumerator<Num> fibEnumerator = FibInternal(long.MaxValue).GetEnumerator();
- while (!context.CancellationToken.IsCancellationRequested && fibEnumerator.MoveNext())
- {
- await responseStream.WriteAsync(fibEnumerator.Current);
- await Task.Delay(100);
- }
- }
+ var limit = request.Limit > 0 ? request.Limit : long.MaxValue;
+ var fibEnumerator = FibInternal(limit).GetEnumerator();
- if (request.Limit > 0)
+ // Keep streaming the sequence until the call is cancelled.
+ // Use CancellationToken from ServerCallContext to detect the cancellation.
+ while (!context.CancellationToken.IsCancellationRequested && fibEnumerator.MoveNext())
{
- foreach (var num in FibInternal(request.Limit))
- {
- await responseStream.WriteAsync(num);
- }
+ await responseStream.WriteAsync(fibEnumerator.Current);
+ await Task.Delay(100);
}
}
- public async Task<Num> Sum(IAsyncStreamReader<Num> requestStream, ServerCallContext context)
+ public override async Task<Num> Sum(IAsyncStreamReader<Num> requestStream, ServerCallContext context)
{
long sum = 0;
await requestStream.ForEachAsync(async num =>
@@ -82,13 +74,20 @@ namespace Math
return new Num { Num_ = sum };
}
- public async Task DivMany(IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream, ServerCallContext context)
+ public override async Task DivMany(IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream, ServerCallContext context)
{
await requestStream.ForEachAsync(async divArgs => await responseStream.WriteAsync(DivInternal(divArgs)));
}
static DivReply DivInternal(DivArgs args)
{
+ if (args.Divisor == 0)
+ {
+ // One can finish the RPC with non-ok status by throwing RpcException instance.
+ // Alternatively, resulting status can be set using ServerCallContext.Status
+ throw new RpcException(new Status(StatusCode.InvalidArgument, "Division by zero"));
+ }
+
long quotient = args.Dividend / args.Divisor;
long remainder = args.Dividend % args.Divisor;
return new DivReply { Quotient = quotient, Remainder = remainder };
diff --git a/src/csharp/Grpc.Examples/packages.config b/src/csharp/Grpc.Examples/packages.config
index dfb8304ad1..a70dcbd4c6 100644
--- a/src/csharp/Grpc.Examples/packages.config
+++ b/src/csharp/Grpc.Examples/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Google.Protobuf" version="3.0.0-beta2" targetFramework="net45" />
+ <package id="Google.Protobuf" version="3.0.0-beta3" targetFramework="net45" />
<package id="Ix-Async" version="1.2.5" targetFramework="net45" />
- <package id="NUnit" version="2.6.4" targetFramework="net45" />
+ <package id="NUnit" version="3.2.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
index bb6488b4f1..a5ee4fdb46 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}</ProjectGuid>
- <OutputType>Library</OutputType>
+ <OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Grpc.HealthCheck.Tests</RootNamespace>
<AssemblyName>Grpc.HealthCheck.Tests</AssemblyName>
@@ -37,13 +37,6 @@
<AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Protobuf.3.0.0-beta2\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
- </Reference>
- <Reference Include="nunit.framework">
- <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
- </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@@ -51,6 +44,15 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
+ <Reference Include="Google.Protobuf">
+ <HintPath>..\packages\Google.Protobuf.3.0.0-beta3\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
+ </Reference>
+ <Reference Include="nunit.framework">
+ <HintPath>..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="nunitlite">
+ <HintPath>..\packages\NUnitLite.3.2.0\lib\net45\nunitlite.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@@ -59,14 +61,15 @@
<Compile Include="HealthServiceImplTest.cs" />
<Compile Include="HealthClientServerTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="NUnitMain.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
- <Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project>
+ <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
<Name>Grpc.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Grpc.HealthCheck\Grpc.HealthCheck.csproj">
- <Project>{aa5e328a-8835-49d7-98ed-c29f2b3049f0}</Project>
+ <Project>{AA5E328A-8835-49D7-98ED-C29F2B3049F0}</Project>
<Name>Grpc.HealthCheck</Name>
</ProjectReference>
</ItemGroup>
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
index c3fac05324..070674bae9 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -49,7 +49,7 @@ namespace Grpc.HealthCheck.Tests
const string Host = "localhost";
Server server;
Channel channel;
- Grpc.Health.V1.Health.IHealthClient client;
+ Grpc.Health.V1.Health.HealthClient client;
Grpc.HealthCheck.HealthServiceImpl serviceImpl;
[TestFixtureSetUp]
@@ -79,16 +79,17 @@ namespace Grpc.HealthCheck.Tests
[Test]
public void ServiceIsRunning()
{
- serviceImpl.SetStatus("", HealthCheckResponse.Types.ServingStatus.SERVING);
+ serviceImpl.SetStatus("", HealthCheckResponse.Types.ServingStatus.Serving);
var response = client.Check(new HealthCheckRequest { Service = "" });
- Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, response.Status);
+ Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.Serving, response.Status);
}
[Test]
public void ServiceDoesntExist()
{
- Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => client.Check(new HealthCheckRequest { Service = "nonexistent.service" }));
+ var ex = Assert.Throws<RpcException>(() => client.Check(new HealthCheckRequest { Service = "nonexistent.service" }));
+ Assert.AreEqual(StatusCode.NotFound, ex.Status.StatusCode);
}
// TODO(jtattermusch): add test with timeout once timeouts are supported
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
index 47e4b7c2a7..15703604ba 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -50,38 +50,39 @@ namespace Grpc.HealthCheck.Tests
public void SetStatus()
{
var impl = new HealthServiceImpl();
- impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.SERVING);
- Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, ""));
+ impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.Serving);
+ Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.Serving, GetStatusHelper(impl, ""));
- impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.NOT_SERVING);
- Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.NOT_SERVING, GetStatusHelper(impl, ""));
+ impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.NotServing);
+ Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.NotServing, GetStatusHelper(impl, ""));
- impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
- Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, ""));
+ impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.Unknown);
+ Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.Unknown, GetStatusHelper(impl, ""));
- impl.SetStatus("grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.SERVING);
- Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "grpc.test.TestService"));
+ impl.SetStatus("grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.Serving);
+ Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.Serving, GetStatusHelper(impl, "grpc.test.TestService"));
}
[Test]
public void ClearStatus()
{
var impl = new HealthServiceImpl();
- impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.SERVING);
- impl.SetStatus("grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+ impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.Serving);
+ impl.SetStatus("grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.Unknown);
impl.ClearStatus("");
- Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => GetStatusHelper(impl, ""));
- Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "grpc.test.TestService"));
+ var ex = Assert.Throws<RpcException>(() => GetStatusHelper(impl, ""));
+ Assert.AreEqual(StatusCode.NotFound, ex.Status.StatusCode);
+ Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.Unknown, GetStatusHelper(impl, "grpc.test.TestService"));
}
[Test]
public void ClearAll()
{
var impl = new HealthServiceImpl();
- impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.SERVING);
- impl.SetStatus("grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+ impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.Serving);
+ impl.SetStatus("grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.Unknown);
impl.ClearAll();
Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, ""));
@@ -92,7 +93,7 @@ namespace Grpc.HealthCheck.Tests
public void NullsRejected()
{
var impl = new HealthServiceImpl();
- Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus(null, HealthCheckResponse.Types.ServingStatus.SERVING));
+ Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus(null, HealthCheckResponse.Types.ServingStatus.Serving));
Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus(null));
}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs b/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
new file mode 100644
index 0000000000..0820523f35
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
@@ -0,0 +1,59 @@
+#region Copyright notice and license
+
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Reflection;
+using Grpc.Core;
+using Grpc.Core.Logging;
+using NUnit.Common;
+using NUnitLite;
+
+namespace Grpc.HealthCheck.Tests
+{
+ /// <summary>
+ /// Provides entry point for NUnitLite
+ /// </summary>
+ public class NUnitMain
+ {
+ public static int Main(string[] args)
+ {
+ // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
+ GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
+#if DOTNET5_4
+ return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
+#else
+ return new AutoRun().Execute(args);
+#endif
+ }
+ }
+}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/packages.config b/src/csharp/Grpc.HealthCheck.Tests/packages.config
index 4728093979..2bcfec8829 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/packages.config
+++ b/src/csharp/Grpc.HealthCheck.Tests/packages.config
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Google.Protobuf" version="3.0.0-beta2" targetFramework="net45" />
- <package id="NUnit" version="2.6.4" targetFramework="net45" />
+ <package id="Google.Protobuf" version="3.0.0-beta3" targetFramework="net45" />
+ <package id="NUnit" version="3.2.0" targetFramework="net45" />
+ <package id="NUnitLite" version="3.2.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
index 498528aa18..2697b74f59 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -40,7 +40,7 @@
<ItemGroup>
<Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Protobuf.3.0.0-beta2\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
+ <HintPath>..\packages\Google.Protobuf.3.0.0-beta3\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
diff --git a/src/csharp/Grpc.HealthCheck/Health.cs b/src/csharp/Grpc.HealthCheck/Health.cs
index d0d0c0b519..100ad187d7 100644
--- a/src/csharp/Grpc.HealthCheck/Health.cs
+++ b/src/csharp/Grpc.HealthCheck/Health.cs
@@ -33,9 +33,9 @@ namespace Grpc.Health.V1 {
"Ag5HcnBjLkhlYWx0aC5WMWIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
- new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1.HealthCheckRequest), global::Grpc.Health.V1.HealthCheckRequest.Parser, new[]{ "Service" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1.HealthCheckResponse), global::Grpc.Health.V1.HealthCheckResponse.Parser, new[]{ "Status" }, null, new[]{ typeof(global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus) }, null)
+ new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Health.V1.HealthCheckRequest), global::Grpc.Health.V1.HealthCheckRequest.Parser, new[]{ "Service" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Health.V1.HealthCheckResponse), global::Grpc.Health.V1.HealthCheckResponse.Parser, new[]{ "Status" }, null, new[]{ typeof(global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus) }, null)
}));
}
#endregion
@@ -75,7 +75,7 @@ namespace Grpc.Health.V1 {
public string Service {
get { return service_; }
set {
- service_ = pb::Preconditions.CheckNotNull(value, "value");
+ service_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
@@ -174,7 +174,7 @@ namespace Grpc.Health.V1 {
/// <summary>Field number for the "status" field.</summary>
public const int StatusFieldNumber = 1;
- private global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus status_ = global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus.UNKNOWN;
+ private global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus status_ = 0;
public global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus Status {
get { return status_; }
set {
@@ -199,7 +199,7 @@ namespace Grpc.Health.V1 {
public override int GetHashCode() {
int hash = 1;
- if (Status != global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus.UNKNOWN) hash ^= Status.GetHashCode();
+ if (Status != 0) hash ^= Status.GetHashCode();
return hash;
}
@@ -208,7 +208,7 @@ namespace Grpc.Health.V1 {
}
public void WriteTo(pb::CodedOutputStream output) {
- if (Status != global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus.UNKNOWN) {
+ if (Status != 0) {
output.WriteRawTag(8);
output.WriteEnum((int) Status);
}
@@ -216,7 +216,7 @@ namespace Grpc.Health.V1 {
public int CalculateSize() {
int size = 0;
- if (Status != global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus.UNKNOWN) {
+ if (Status != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status);
}
return size;
@@ -226,7 +226,7 @@ namespace Grpc.Health.V1 {
if (other == null) {
return;
}
- if (other.Status != global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus.UNKNOWN) {
+ if (other.Status != 0) {
Status = other.Status;
}
}
@@ -251,9 +251,9 @@ namespace Grpc.Health.V1 {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Types {
public enum ServingStatus {
- UNKNOWN = 0,
- SERVING = 1,
- NOT_SERVING = 2,
+ [pbr::OriginalName("UNKNOWN")] Unknown = 0,
+ [pbr::OriginalName("SERVING")] Serving = 1,
+ [pbr::OriginalName("NOT_SERVING")] NotServing = 2,
}
}
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index 68320eb5c2..51c6a39b1d 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -1,5 +1,35 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: health.proto
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
#region Designer generated code
using System;
@@ -22,13 +52,14 @@ namespace Grpc.Health.V1 {
__Marshaller_HealthCheckRequest,
__Marshaller_HealthCheckResponse);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Health.V1.HealthReflection.Descriptor.Services[0]; }
}
- // client interface
+ /// <summary>Client for Health</summary>
+ [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IHealthClient
{
global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
@@ -37,51 +68,87 @@ namespace Grpc.Health.V1 {
AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of Health</summary>
+ [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IHealth
{
- Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context);
+ global::System.Threading.Tasks.Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context);
}
- // client stub
- public class HealthClient : ClientBase, IHealthClient
+ /// <summary>Base class for server-side implementations of Health</summary>
+ public abstract class HealthBase
+ {
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// <summary>Client for Health</summary>
+ #pragma warning disable 0618
+ public class HealthClient : ClientBase<HealthClient>, IHealthClient
+ #pragma warning restore 0618
{
public HealthClient(Channel channel) : base(channel)
{
}
- public global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public HealthClient(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ protected HealthClient() : base()
+ {
+ }
+ ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ protected HealthClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ public virtual global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return Check(request, new CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options)
{
- var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken));
- return Calls.BlockingUnaryCall(call, request);
+ return CallInvoker.BlockingUnaryCall(__Method_Check, null, options, request);
}
- public global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options)
+ public virtual AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_Check, options);
- return Calls.BlockingUnaryCall(call, request);
+ return CheckAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public virtual AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options)
{
- var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncUnaryCall(call, request);
+ return CallInvoker.AsyncUnaryCall(__Method_Check, null, options, request);
}
- public AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options)
+ protected override HealthClient NewInstance(ClientBaseConfiguration configuration)
{
- var call = CreateCall(__Method_Check, options);
- return Calls.AsyncUnaryCall(call, request);
+ return new HealthClient(configuration);
}
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates a new client for Health</summary>
+ public static HealthClient NewClient(Channel channel)
+ {
+ return new HealthClient(channel);
+ }
+
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
public static ServerServiceDefinition BindService(IHealth serviceImpl)
+ #pragma warning restore 0618
{
return ServerServiceDefinition.CreateBuilder(__ServiceName)
.AddMethod(__Method_Check, serviceImpl.Check).Build();
}
- // creates a new client
- public static HealthClient NewClient(Channel channel)
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
+ public static ServerServiceDefinition BindService(HealthBase serviceImpl)
+ #pragma warning restore 0618
{
- return new HealthClient(channel);
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_Check, serviceImpl.Check).Build();
}
}
diff --git a/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
index 21482b302b..d0406ece00 100644
--- a/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
@@ -1,5 +1,5 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -51,7 +51,7 @@ namespace Grpc.HealthCheck
/// server.AddServiceDefinition(Grpc.Health.V1.Health.BindService(serviceImpl));
/// </code>
/// </summary>
- public class HealthServiceImpl : Grpc.Health.V1.Health.IHealth
+ public class HealthServiceImpl : Grpc.Health.V1.Health.HealthBase
{
private readonly object myLock = new object();
private readonly Dictionary<string, HealthCheckResponse.Types.ServingStatus> statusMap =
@@ -99,7 +99,7 @@ namespace Grpc.HealthCheck
/// <param name="request">The check request.</param>
/// <param name="context">The call context.</param>
/// <returns>The asynchronous response.</returns>
- public Task<HealthCheckResponse> Check(HealthCheckRequest request, ServerCallContext context)
+ public override Task<HealthCheckResponse> Check(HealthCheckRequest request, ServerCallContext context)
{
lock (myLock)
{
diff --git a/src/csharp/Grpc.HealthCheck/packages.config b/src/csharp/Grpc.HealthCheck/packages.config
index 358a978ba9..a52d9e508f 100644
--- a/src/csharp/Grpc.HealthCheck/packages.config
+++ b/src/csharp/Grpc.HealthCheck/packages.config
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Google.Protobuf" version="3.0.0-beta2" targetFramework="net45" />
+ <package id="Google.Protobuf" version="3.0.0-beta3" targetFramework="net45" />
<package id="Ix-Async" version="1.2.5" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index f37c1464c3..339a754c02 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -9,7 +9,7 @@
<AssemblyName>Grpc.IntegrationTesting.Client</AssemblyName>
<StartupObject>Grpc.IntegrationTesting.Client.Program</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <NuGetPackageImportStamp>6d22e68f</NuGetPackageImportStamp>
+ <NuGetPackageImportStamp>dfa56e6c</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -43,28 +43,17 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth, Version=1.10.0.25333, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Auth, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.10.0\lib\net40\Google.Apis.Auth.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.10.0.25333, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.10.0\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Core, Version=1.10.0.25331, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Core, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Core.1.10.0\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
- </Reference>
- <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
- </Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions">
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
- </Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Core.1.11.1\lib\net45\Google.Apis.Core.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -73,12 +62,6 @@
<Reference Include="System" />
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
- <Reference Include="System.Net.Http.Extensions">
- <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
- </Reference>
- <Reference Include="System.Net.Http.Primitives">
- <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
- </Reference>
<Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
@@ -100,14 +83,6 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
- <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
- <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
- <PropertyGroup>
- <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
- </PropertyGroup>
- <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
- </Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/app.config b/src/csharp/Grpc.IntegrationTesting.Client/app.config
deleted file mode 100644
index 84d7534d65..0000000000
--- a/src/csharp/Grpc.IntegrationTesting.Client/app.config
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
- <runtime>
- <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Google.Apis.Core" publicKeyToken="4b01fa6e34db77ab" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-1.9.2.38523" newVersion="1.9.2.38523" />
- </dependentAssembly>
- </assemblyBinding>
- </runtime>
-</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/packages.config b/src/csharp/Grpc.IntegrationTesting.Client/packages.config
index 5fe8ca616c..c20d9ceed6 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting.Client/packages.config
@@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
- <package id="Google.Apis.Auth" version="1.10.0" targetFramework="net45" />
- <package id="Google.Apis.Core" version="1.10.0" targetFramework="net45" />
- <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
- <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
- <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
- <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.11.1" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.11.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/app.config b/src/csharp/Grpc.IntegrationTesting.QpsWorker/app.config
index 940d25cae3..e204447bb3 100644
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/app.config
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/app.config
@@ -6,6 +6,10 @@
<assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
</dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Google.Apis.Core" publicKeyToken="4b01fa6e34db77ab" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.11.1.0" newVersion="1.11.1.0" />
+ </dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index f27b96a53f..27a5650308 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -9,7 +9,7 @@
<AssemblyName>Grpc.IntegrationTesting.Server</AssemblyName>
<StartupObject>Grpc.IntegrationTesting.Server.Program</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <NuGetPackageImportStamp>d9ee8e52</NuGetPackageImportStamp>
+ <NuGetPackageImportStamp>7ceb739e</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -43,28 +43,17 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth, Version=1.10.0.25333, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Auth, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.10.0\lib\net40\Google.Apis.Auth.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.10.0.25333, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.10.0\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Core, Version=1.10.0.25331, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Core, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Core.1.10.0\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
- </Reference>
- <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
- </Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions">
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
- </Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Core.1.11.1\lib\net45\Google.Apis.Core.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -73,12 +62,6 @@
<Reference Include="System" />
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
- <Reference Include="System.Net.Http.Extensions">
- <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
- </Reference>
- <Reference Include="System.Net.Http.Primitives">
- <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
- </Reference>
<Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
@@ -100,14 +83,6 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
- <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
- <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
- <PropertyGroup>
- <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
- </PropertyGroup>
- <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
- </Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/app.config b/src/csharp/Grpc.IntegrationTesting.Server/app.config
deleted file mode 100644
index 84d7534d65..0000000000
--- a/src/csharp/Grpc.IntegrationTesting.Server/app.config
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
- <runtime>
- <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Google.Apis.Core" publicKeyToken="4b01fa6e34db77ab" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-1.9.2.38523" newVersion="1.9.2.38523" />
- </dependentAssembly>
- </assemblyBinding>
- </runtime>
-</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/packages.config b/src/csharp/Grpc.IntegrationTesting.Server/packages.config
index 5fe8ca616c..c20d9ceed6 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting.Server/packages.config
@@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
- <package id="Google.Apis.Auth" version="1.10.0" targetFramework="net45" />
- <package id="Google.Apis.Core" version="1.10.0" targetFramework="net45" />
- <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
- <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
- <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
- <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.11.1" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.11.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/.gitignore b/src/csharp/Grpc.IntegrationTesting.StressClient/.gitignore
new file mode 100644
index 0000000000..a382af2294
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/.gitignore
@@ -0,0 +1,3 @@
+bin
+obj
+
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
new file mode 100644
index 0000000000..d6eba74289
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{ADEBA147-80AE-4710-82E9-5B7F93690266}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Grpc.IntegrationTesting.StressClient</RootNamespace>
+ <AssemblyName>Grpc.IntegrationTesting.StressClient</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\Grpc.Core\Version.cs">
+ <Link>Version.cs</Link>
+ </Compile>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+ <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
+ <Name>Grpc.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj">
+ <Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
+ <Name>Grpc.IntegrationTesting</Name>
+ </ProjectReference>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Program.cs b/src/csharp/Grpc.IntegrationTesting.StressClient/Program.cs
new file mode 100644
index 0000000000..dffdf22fa5
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Program.cs
@@ -0,0 +1,45 @@
+#region Copyright notice and license
+
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+
+namespace Grpc.IntegrationTesting.StressClient
+{
+ class MainClass
+ {
+ public static void Main(string[] args)
+ {
+ StressTestClient.Run(args);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.StressClient/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..e845bbfb9e
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.IntegrationTesting.StressClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
diff --git a/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs
index 47a15224f1..07f2703d4a 100644
--- a/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs
+++ b/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -44,26 +44,23 @@ namespace Grpc.Testing
/// <summary>
/// Implementation of BenchmarkService server
/// </summary>
- public class BenchmarkServiceImpl : BenchmarkService.IBenchmarkService
+ public class BenchmarkServiceImpl : BenchmarkService.BenchmarkServiceBase
{
- private readonly int responseSize;
-
- public BenchmarkServiceImpl(int responseSize)
+ public BenchmarkServiceImpl()
{
- this.responseSize = responseSize;
}
- public Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
+ public override Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
{
- var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
+ var response = new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) };
return Task.FromResult(response);
}
- public async Task StreamingCall(IAsyncStreamReader<SimpleRequest> requestStream, IServerStreamWriter<SimpleResponse> responseStream, ServerCallContext context)
+ public override async Task StreamingCall(IAsyncStreamReader<SimpleRequest> requestStream, IServerStreamWriter<SimpleResponse> responseStream, ServerCallContext context)
{
await requestStream.ForEachAsync(async request =>
{
- var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
+ var response = new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) };
await responseStream.WriteAsync(response);
});
}
diff --git a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
index c4016012cb..39b9ae08e6 100644
--- a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
#endregion
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -41,6 +42,9 @@ using System.Threading;
using System.Threading.Tasks;
using Google.Protobuf;
using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Logging;
+using Grpc.Core.Profiling;
using Grpc.Core.Utils;
using NUnit.Framework;
using Grpc.Testing;
@@ -50,58 +54,119 @@ namespace Grpc.IntegrationTesting
/// <summary>
/// Helper methods to start client runners for performance testing.
/// </summary>
- public static class ClientRunners
+ public class ClientRunners
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<ClientRunners>();
+
+ // Profilers to use for clients.
+ static readonly BlockingCollection<BasicProfiler> profilers = new BlockingCollection<BasicProfiler>();
+
+ internal static void AddProfiler(BasicProfiler profiler)
+ {
+ GrpcPreconditions.CheckNotNull(profiler);
+ profilers.Add(profiler);
+ }
+
/// <summary>
/// Creates a started client runner.
/// </summary>
public static IClientRunner CreateStarted(ClientConfig config)
{
- string target = config.ServerTargets.Single();
- GrpcPreconditions.CheckArgument(config.LoadParams.LoadCase == LoadParams.LoadOneofCase.ClosedLoop);
+ Logger.Debug("ClientConfig: {0}", config);
- var credentials = config.SecurityParams != null ? TestCredentials.CreateSslCredentials() : ChannelCredentials.Insecure;
- var channel = new Channel(target, credentials);
+ if (config.AsyncClientThreads != 0)
+ {
+ Logger.Warning("ClientConfig.AsyncClientThreads is not supported for C#. Ignoring the value");
+ }
+ if (config.CoreLimit != 0)
+ {
+ Logger.Warning("ClientConfig.CoreLimit is not supported for C#. Ignoring the value");
+ }
+ if (config.CoreList.Count > 0)
+ {
+ Logger.Warning("ClientConfig.CoreList is not supported for C#. Ignoring the value");
+ }
+
+ var channels = CreateChannels(config.ClientChannels, config.ServerTargets, config.SecurityParams);
- switch (config.RpcType)
+ return new ClientRunnerImpl(channels,
+ config.ClientType,
+ config.RpcType,
+ config.OutstandingRpcsPerChannel,
+ config.LoadParams,
+ config.PayloadConfig,
+ config.HistogramParams,
+ () => GetNextProfiler());
+ }
+
+ private static List<Channel> CreateChannels(int clientChannels, IEnumerable<string> serverTargets, SecurityParams securityParams)
+ {
+ GrpcPreconditions.CheckArgument(clientChannels > 0, "clientChannels needs to be at least 1.");
+ GrpcPreconditions.CheckArgument(serverTargets.Count() > 0, "at least one serverTarget needs to be specified.");
+
+ var credentials = securityParams != null ? TestCredentials.CreateSslCredentials() : ChannelCredentials.Insecure;
+ List<ChannelOption> channelOptions = null;
+ if (securityParams != null && securityParams.ServerHostOverride != "")
{
- case RpcType.UNARY:
- return new SyncUnaryClientRunner(channel,
- config.PayloadConfig.SimpleParams.ReqSize,
- config.HistogramParams);
+ channelOptions = new List<ChannelOption>
+ {
+ new ChannelOption(ChannelOptions.SslTargetNameOverride, securityParams.ServerHostOverride)
+ };
+ }
- case RpcType.STREAMING:
- default:
- throw new ArgumentException("Unsupported RpcType.");
+ var result = new List<Channel>();
+ for (int i = 0; i < clientChannels; i++)
+ {
+ var target = serverTargets.ElementAt(i % serverTargets.Count());
+ var channel = new Channel(target, credentials, channelOptions);
+ result.Add(channel);
}
+ return result;
+ }
+
+ private static BasicProfiler GetNextProfiler()
+ {
+ BasicProfiler result = null;
+ profilers.TryTake(out result);
+ return result;
}
}
- /// <summary>
- /// Client that starts synchronous unary calls in a closed loop.
- /// </summary>
- public class SyncUnaryClientRunner : IClientRunner
+ internal class ClientRunnerImpl : IClientRunner
{
const double SecondsToNanos = 1e9;
- readonly Channel channel;
- readonly int payloadSize;
+ readonly List<Channel> channels;
+ readonly ClientType clientType;
+ readonly RpcType rpcType;
+ readonly PayloadConfig payloadConfig;
readonly Histogram histogram;
- readonly BenchmarkService.IBenchmarkServiceClient client;
- readonly Task runnerTask;
- readonly CancellationTokenSource stoppedCts;
+ readonly List<Task> runnerTasks;
+ readonly CancellationTokenSource stoppedCts = new CancellationTokenSource();
readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
+ readonly AtomicCounter statsResetCount = new AtomicCounter();
- public SyncUnaryClientRunner(Channel channel, int payloadSize, HistogramParams histogramParams)
+ public ClientRunnerImpl(List<Channel> channels, ClientType clientType, RpcType rpcType, int outstandingRpcsPerChannel, LoadParams loadParams, PayloadConfig payloadConfig, HistogramParams histogramParams, Func<BasicProfiler> profilerFactory)
{
- this.channel = GrpcPreconditions.CheckNotNull(channel);
- this.payloadSize = payloadSize;
+ GrpcPreconditions.CheckArgument(outstandingRpcsPerChannel > 0, "outstandingRpcsPerChannel");
+ GrpcPreconditions.CheckNotNull(histogramParams, "histogramParams");
+ this.channels = new List<Channel>(channels);
+ this.clientType = clientType;
+ this.rpcType = rpcType;
+ this.payloadConfig = payloadConfig;
this.histogram = new Histogram(histogramParams.Resolution, histogramParams.MaxPossible);
- this.stoppedCts = new CancellationTokenSource();
- this.client = BenchmarkService.NewClient(channel);
- this.runnerTask = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
+ this.runnerTasks = new List<Task>();
+ foreach (var channel in this.channels)
+ {
+ for (int i = 0; i < outstandingRpcsPerChannel; i++)
+ {
+ var timer = CreateTimer(loadParams, 1.0 / this.channels.Count / outstandingRpcsPerChannel);
+ var optionalProfiler = profilerFactory();
+ this.runnerTasks.Add(RunClientAsync(channel, timer, optionalProfiler));
+ }
+ }
}
public ClientStats GetStats(bool reset)
@@ -109,6 +174,11 @@ namespace Grpc.IntegrationTesting
var histogramData = histogram.GetSnapshot(reset);
var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds;
+ if (reset)
+ {
+ statsResetCount.Increment();
+ }
+
// TODO: populate user time and system time
return new ClientStats
{
@@ -122,32 +192,183 @@ namespace Grpc.IntegrationTesting
public async Task StopAsync()
{
stoppedCts.Cancel();
- await runnerTask;
- await channel.ShutdownAsync();
+ foreach (var runnerTask in runnerTasks)
+ {
+ await runnerTask;
+ }
+ foreach (var channel in channels)
+ {
+ await channel.ShutdownAsync();
+ }
}
- private void Run()
+ private void RunUnary(Channel channel, IInterarrivalTimer timer, BasicProfiler optionalProfiler)
{
- var request = new SimpleRequest
+ if (optionalProfiler != null)
{
- Payload = CreateZerosPayload(payloadSize)
- };
+ Profilers.SetForCurrentThread(optionalProfiler);
+ }
+
+ bool profilerReset = false;
+
+ var client = BenchmarkService.NewClient(channel);
+ var request = CreateSimpleRequest();
var stopwatch = new Stopwatch();
while (!stoppedCts.Token.IsCancellationRequested)
{
+ // after the first stats reset, also reset the profiler.
+ if (optionalProfiler != null && !profilerReset && statsResetCount.Count > 0)
+ {
+ optionalProfiler.Reset();
+ profilerReset = true;
+ }
+
stopwatch.Restart();
client.UnaryCall(request);
stopwatch.Stop();
// spec requires data point in nanoseconds.
histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
+
+ timer.WaitForNext();
+ }
+ }
+
+ private async Task RunUnaryAsync(Channel channel, IInterarrivalTimer timer)
+ {
+ var client = BenchmarkService.NewClient(channel);
+ var request = CreateSimpleRequest();
+ var stopwatch = new Stopwatch();
+
+ while (!stoppedCts.Token.IsCancellationRequested)
+ {
+ stopwatch.Restart();
+ await client.UnaryCallAsync(request);
+ stopwatch.Stop();
+
+ // spec requires data point in nanoseconds.
+ histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
+
+ await timer.WaitForNextAsync();
+ }
+ }
+
+ private async Task RunStreamingPingPongAsync(Channel channel, IInterarrivalTimer timer)
+ {
+ var client = BenchmarkService.NewClient(channel);
+ var request = CreateSimpleRequest();
+ var stopwatch = new Stopwatch();
+
+ using (var call = client.StreamingCall())
+ {
+ while (!stoppedCts.Token.IsCancellationRequested)
+ {
+ stopwatch.Restart();
+ await call.RequestStream.WriteAsync(request);
+ await call.ResponseStream.MoveNext();
+ stopwatch.Stop();
+
+ // spec requires data point in nanoseconds.
+ histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
+
+ await timer.WaitForNextAsync();
+ }
+
+ // finish the streaming call
+ await call.RequestStream.CompleteAsync();
+ Assert.IsFalse(await call.ResponseStream.MoveNext());
+ }
+ }
+
+ private async Task RunGenericStreamingAsync(Channel channel, IInterarrivalTimer timer)
+ {
+ var request = CreateByteBufferRequest();
+ var stopwatch = new Stopwatch();
+
+ var callDetails = new CallInvocationDetails<byte[], byte[]>(channel, GenericService.StreamingCallMethod, new CallOptions());
+
+ using (var call = Calls.AsyncDuplexStreamingCall(callDetails))
+ {
+ while (!stoppedCts.Token.IsCancellationRequested)
+ {
+ stopwatch.Restart();
+ await call.RequestStream.WriteAsync(request);
+ await call.ResponseStream.MoveNext();
+ stopwatch.Stop();
+
+ // spec requires data point in nanoseconds.
+ histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
+
+ await timer.WaitForNextAsync();
+ }
+
+ // finish the streaming call
+ await call.RequestStream.CompleteAsync();
+ Assert.IsFalse(await call.ResponseStream.MoveNext());
}
}
+ private Task RunClientAsync(Channel channel, IInterarrivalTimer timer, BasicProfiler optionalProfiler)
+ {
+ if (payloadConfig.PayloadCase == PayloadConfig.PayloadOneofCase.BytebufParams)
+ {
+ GrpcPreconditions.CheckArgument(clientType == ClientType.AsyncClient, "Generic client only supports async API");
+ GrpcPreconditions.CheckArgument(rpcType == RpcType.Streaming, "Generic client only supports streaming calls");
+ return RunGenericStreamingAsync(channel, timer);
+ }
+
+ GrpcPreconditions.CheckNotNull(payloadConfig.SimpleParams);
+ if (clientType == ClientType.SyncClient)
+ {
+ GrpcPreconditions.CheckArgument(rpcType == RpcType.Unary, "Sync client can only be used for Unary calls in C#");
+ // create a dedicated thread for the synchronous client
+ return Task.Factory.StartNew(() => RunUnary(channel, timer, optionalProfiler), TaskCreationOptions.LongRunning);
+ }
+ else if (clientType == ClientType.AsyncClient)
+ {
+ switch (rpcType)
+ {
+ case RpcType.Unary:
+ return RunUnaryAsync(channel, timer);
+ case RpcType.Streaming:
+ return RunStreamingPingPongAsync(channel, timer);
+ }
+ }
+ throw new ArgumentException("Unsupported configuration.");
+ }
+
+ private SimpleRequest CreateSimpleRequest()
+ {
+ GrpcPreconditions.CheckNotNull(payloadConfig.SimpleParams);
+ return new SimpleRequest
+ {
+ Payload = CreateZerosPayload(payloadConfig.SimpleParams.ReqSize),
+ ResponseSize = payloadConfig.SimpleParams.RespSize
+ };
+ }
+
+ private byte[] CreateByteBufferRequest()
+ {
+ return new byte[payloadConfig.BytebufParams.ReqSize];
+ }
+
private static Payload CreateZerosPayload(int size)
{
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
+
+ private static IInterarrivalTimer CreateTimer(LoadParams loadParams, double loadMultiplier)
+ {
+ switch (loadParams.LoadCase)
+ {
+ case LoadParams.LoadOneofCase.ClosedLoop:
+ return new ClosedLoopInterarrivalTimer();
+ case LoadParams.LoadOneofCase.Poisson:
+ return new PoissonInterarrivalTimer(loadParams.Poisson.OfferedLoad * loadMultiplier);
+ default:
+ throw new ArgumentException("Unknown load type");
+ }
+ }
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Control.cs b/src/csharp/Grpc.IntegrationTesting/Control.cs
index 291bc75397..412f800ff9 100644
--- a/src/csharp/Grpc.IntegrationTesting/Control.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Control.cs
@@ -26,69 +26,84 @@ namespace Grpc.Testing {
"CiRzcmMvcHJvdG8vZ3JwYy90ZXN0aW5nL2NvbnRyb2wucHJvdG8SDGdycGMu",
"dGVzdGluZxolc3JjL3Byb3RvL2dycGMvdGVzdGluZy9wYXlsb2Fkcy5wcm90",
"bxoic3JjL3Byb3RvL2dycGMvdGVzdGluZy9zdGF0cy5wcm90byIlCg1Qb2lz",
- "c29uUGFyYW1zEhQKDG9mZmVyZWRfbG9hZBgBIAEoASJBCg1Vbmlmb3JtUGFy",
- "YW1zEhcKD2ludGVyYXJyaXZhbF9sbxgBIAEoARIXCg9pbnRlcmFycml2YWxf",
- "aGkYAiABKAEiKwoTRGV0ZXJtaW5pc3RpY1BhcmFtcxIUCgxvZmZlcmVkX2xv",
- "YWQYASABKAEiOAoMUGFyZXRvUGFyYW1zEhkKEWludGVyYXJyaXZhbF9iYXNl",
- "GAEgASgBEg0KBWFscGhhGAIgASgBIhIKEENsb3NlZExvb3BQYXJhbXMijgIK",
- "CkxvYWRQYXJhbXMSNQoLY2xvc2VkX2xvb3AYASABKAsyHi5ncnBjLnRlc3Rp",
- "bmcuQ2xvc2VkTG9vcFBhcmFtc0gAEi4KB3BvaXNzb24YAiABKAsyGy5ncnBj",
- "LnRlc3RpbmcuUG9pc3NvblBhcmFtc0gAEi4KB3VuaWZvcm0YAyABKAsyGy5n",
- "cnBjLnRlc3RpbmcuVW5pZm9ybVBhcmFtc0gAEjMKBmRldGVybRgEIAEoCzIh",
- "LmdycGMudGVzdGluZy5EZXRlcm1pbmlzdGljUGFyYW1zSAASLAoGcGFyZXRv",
- "GAUgASgLMhouZ3JwYy50ZXN0aW5nLlBhcmV0b1BhcmFtc0gAQgYKBGxvYWQi",
- "QwoOU2VjdXJpdHlQYXJhbXMSEwoLdXNlX3Rlc3RfY2EYASABKAgSHAoUc2Vy",
- "dmVyX2hvc3Rfb3ZlcnJpZGUYAiABKAki1gMKDENsaWVudENvbmZpZxIWCg5z",
- "ZXJ2ZXJfdGFyZ2V0cxgBIAMoCRItCgtjbGllbnRfdHlwZRgCIAEoDjIYLmdy",
- "cGMudGVzdGluZy5DbGllbnRUeXBlEjUKD3NlY3VyaXR5X3BhcmFtcxgDIAEo",
- "CzIcLmdycGMudGVzdGluZy5TZWN1cml0eVBhcmFtcxIkChxvdXRzdGFuZGlu",
- "Z19ycGNzX3Blcl9jaGFubmVsGAQgASgFEhcKD2NsaWVudF9jaGFubmVscxgF",
- "IAEoBRIcChRhc3luY19jbGllbnRfdGhyZWFkcxgHIAEoBRInCghycGNfdHlw",
- "ZRgIIAEoDjIVLmdycGMudGVzdGluZy5ScGNUeXBlEi0KC2xvYWRfcGFyYW1z",
- "GAogASgLMhguZ3JwYy50ZXN0aW5nLkxvYWRQYXJhbXMSMwoOcGF5bG9hZF9j",
- "b25maWcYCyABKAsyGy5ncnBjLnRlc3RpbmcuUGF5bG9hZENvbmZpZxI3ChBo",
- "aXN0b2dyYW1fcGFyYW1zGAwgASgLMh0uZ3JwYy50ZXN0aW5nLkhpc3RvZ3Jh",
- "bVBhcmFtcxIRCgljb3JlX2xpc3QYDSADKAUSEgoKY29yZV9saW1pdBgOIAEo",
- "BSI4CgxDbGllbnRTdGF0dXMSKAoFc3RhdHMYASABKAsyGS5ncnBjLnRlc3Rp",
- "bmcuQ2xpZW50U3RhdHMiFQoETWFyaxINCgVyZXNldBgBIAEoCCJoCgpDbGll",
- "bnRBcmdzEisKBXNldHVwGAEgASgLMhouZ3JwYy50ZXN0aW5nLkNsaWVudENv",
- "bmZpZ0gAEiIKBG1hcmsYAiABKAsyEi5ncnBjLnRlc3RpbmcuTWFya0gAQgkK",
- "B2FyZ3R5cGUi/AEKDFNlcnZlckNvbmZpZxItCgtzZXJ2ZXJfdHlwZRgBIAEo",
- "DjIYLmdycGMudGVzdGluZy5TZXJ2ZXJUeXBlEjUKD3NlY3VyaXR5X3BhcmFt",
- "cxgCIAEoCzIcLmdycGMudGVzdGluZy5TZWN1cml0eVBhcmFtcxIMCgRwb3J0",
- "GAQgASgFEhwKFGFzeW5jX3NlcnZlcl90aHJlYWRzGAcgASgFEhIKCmNvcmVf",
- "bGltaXQYCCABKAUSMwoOcGF5bG9hZF9jb25maWcYCSABKAsyGy5ncnBjLnRl",
- "c3RpbmcuUGF5bG9hZENvbmZpZxIRCgljb3JlX2xpc3QYCiADKAUiaAoKU2Vy",
- "dmVyQXJncxIrCgVzZXR1cBgBIAEoCzIaLmdycGMudGVzdGluZy5TZXJ2ZXJD",
- "b25maWdIABIiCgRtYXJrGAIgASgLMhIuZ3JwYy50ZXN0aW5nLk1hcmtIAEIJ",
- "Cgdhcmd0eXBlIlUKDFNlcnZlclN0YXR1cxIoCgVzdGF0cxgBIAEoCzIZLmdy",
- "cGMudGVzdGluZy5TZXJ2ZXJTdGF0cxIMCgRwb3J0GAIgASgFEg0KBWNvcmVz",
- "GAMgASgFIg0KC0NvcmVSZXF1ZXN0Ih0KDENvcmVSZXNwb25zZRINCgVjb3Jl",
- "cxgBIAEoBSIGCgRWb2lkKi8KCkNsaWVudFR5cGUSDwoLU1lOQ19DTElFTlQQ",
- "ABIQCgxBU1lOQ19DTElFTlQQASpJCgpTZXJ2ZXJUeXBlEg8KC1NZTkNfU0VS",
- "VkVSEAASEAoMQVNZTkNfU0VSVkVSEAESGAoUQVNZTkNfR0VORVJJQ19TRVJW",
- "RVIQAiojCgdScGNUeXBlEgkKBVVOQVJZEAASDQoJU1RSRUFNSU5HEAFiBnBy",
- "b3RvMw=="));
+ "c29uUGFyYW1zEhQKDG9mZmVyZWRfbG9hZBgBIAEoASISChBDbG9zZWRMb29w",
+ "UGFyYW1zInsKCkxvYWRQYXJhbXMSNQoLY2xvc2VkX2xvb3AYASABKAsyHi5n",
+ "cnBjLnRlc3RpbmcuQ2xvc2VkTG9vcFBhcmFtc0gAEi4KB3BvaXNzb24YAiAB",
+ "KAsyGy5ncnBjLnRlc3RpbmcuUG9pc3NvblBhcmFtc0gAQgYKBGxvYWQiQwoO",
+ "U2VjdXJpdHlQYXJhbXMSEwoLdXNlX3Rlc3RfY2EYASABKAgSHAoUc2VydmVy",
+ "X2hvc3Rfb3ZlcnJpZGUYAiABKAki8AMKDENsaWVudENvbmZpZxIWCg5zZXJ2",
+ "ZXJfdGFyZ2V0cxgBIAMoCRItCgtjbGllbnRfdHlwZRgCIAEoDjIYLmdycGMu",
+ "dGVzdGluZy5DbGllbnRUeXBlEjUKD3NlY3VyaXR5X3BhcmFtcxgDIAEoCzIc",
+ "LmdycGMudGVzdGluZy5TZWN1cml0eVBhcmFtcxIkChxvdXRzdGFuZGluZ19y",
+ "cGNzX3Blcl9jaGFubmVsGAQgASgFEhcKD2NsaWVudF9jaGFubmVscxgFIAEo",
+ "BRIcChRhc3luY19jbGllbnRfdGhyZWFkcxgHIAEoBRInCghycGNfdHlwZRgI",
+ "IAEoDjIVLmdycGMudGVzdGluZy5ScGNUeXBlEi0KC2xvYWRfcGFyYW1zGAog",
+ "ASgLMhguZ3JwYy50ZXN0aW5nLkxvYWRQYXJhbXMSMwoOcGF5bG9hZF9jb25m",
+ "aWcYCyABKAsyGy5ncnBjLnRlc3RpbmcuUGF5bG9hZENvbmZpZxI3ChBoaXN0",
+ "b2dyYW1fcGFyYW1zGAwgASgLMh0uZ3JwYy50ZXN0aW5nLkhpc3RvZ3JhbVBh",
+ "cmFtcxIRCgljb3JlX2xpc3QYDSADKAUSEgoKY29yZV9saW1pdBgOIAEoBRIY",
+ "ChBvdGhlcl9jbGllbnRfYXBpGA8gASgJIjgKDENsaWVudFN0YXR1cxIoCgVz",
+ "dGF0cxgBIAEoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cyIVCgRNYXJr",
+ "Eg0KBXJlc2V0GAEgASgIImgKCkNsaWVudEFyZ3MSKwoFc2V0dXAYASABKAsy",
+ "Gi5ncnBjLnRlc3RpbmcuQ2xpZW50Q29uZmlnSAASIgoEbWFyaxgCIAEoCzIS",
+ "LmdycGMudGVzdGluZy5NYXJrSABCCQoHYXJndHlwZSKWAgoMU2VydmVyQ29u",
+ "ZmlnEi0KC3NlcnZlcl90eXBlGAEgASgOMhguZ3JwYy50ZXN0aW5nLlNlcnZl",
+ "clR5cGUSNQoPc2VjdXJpdHlfcGFyYW1zGAIgASgLMhwuZ3JwYy50ZXN0aW5n",
+ "LlNlY3VyaXR5UGFyYW1zEgwKBHBvcnQYBCABKAUSHAoUYXN5bmNfc2VydmVy",
+ "X3RocmVhZHMYByABKAUSEgoKY29yZV9saW1pdBgIIAEoBRIzCg5wYXlsb2Fk",
+ "X2NvbmZpZxgJIAEoCzIbLmdycGMudGVzdGluZy5QYXlsb2FkQ29uZmlnEhEK",
+ "CWNvcmVfbGlzdBgKIAMoBRIYChBvdGhlcl9zZXJ2ZXJfYXBpGAsgASgJImgK",
+ "ClNlcnZlckFyZ3MSKwoFc2V0dXAYASABKAsyGi5ncnBjLnRlc3RpbmcuU2Vy",
+ "dmVyQ29uZmlnSAASIgoEbWFyaxgCIAEoCzISLmdycGMudGVzdGluZy5NYXJr",
+ "SABCCQoHYXJndHlwZSJVCgxTZXJ2ZXJTdGF0dXMSKAoFc3RhdHMYASABKAsy",
+ "GS5ncnBjLnRlc3RpbmcuU2VydmVyU3RhdHMSDAoEcG9ydBgCIAEoBRINCgVj",
+ "b3JlcxgDIAEoBSINCgtDb3JlUmVxdWVzdCIdCgxDb3JlUmVzcG9uc2USDQoF",
+ "Y29yZXMYASABKAUiBgoEVm9pZCL9AQoIU2NlbmFyaW8SDAoEbmFtZRgBIAEo",
+ "CRIxCg1jbGllbnRfY29uZmlnGAIgASgLMhouZ3JwYy50ZXN0aW5nLkNsaWVu",
+ "dENvbmZpZxITCgtudW1fY2xpZW50cxgDIAEoBRIxCg1zZXJ2ZXJfY29uZmln",
+ "GAQgASgLMhouZ3JwYy50ZXN0aW5nLlNlcnZlckNvbmZpZxITCgtudW1fc2Vy",
+ "dmVycxgFIAEoBRIWCg53YXJtdXBfc2Vjb25kcxgGIAEoBRIZChFiZW5jaG1h",
+ "cmtfc2Vjb25kcxgHIAEoBRIgChhzcGF3bl9sb2NhbF93b3JrZXJfY291bnQY",
+ "CCABKAUiNgoJU2NlbmFyaW9zEikKCXNjZW5hcmlvcxgBIAMoCzIWLmdycGMu",
+ "dGVzdGluZy5TY2VuYXJpbyKSAgoVU2NlbmFyaW9SZXN1bHRTdW1tYXJ5EgsK",
+ "A3FwcxgBIAEoARIbChNxcHNfcGVyX3NlcnZlcl9jb3JlGAIgASgBEhoKEnNl",
+ "cnZlcl9zeXN0ZW1fdGltZRgDIAEoARIYChBzZXJ2ZXJfdXNlcl90aW1lGAQg",
+ "ASgBEhoKEmNsaWVudF9zeXN0ZW1fdGltZRgFIAEoARIYChBjbGllbnRfdXNl",
+ "cl90aW1lGAYgASgBEhIKCmxhdGVuY3lfNTAYByABKAESEgoKbGF0ZW5jeV85",
+ "MBgIIAEoARISCgpsYXRlbmN5Xzk1GAkgASgBEhIKCmxhdGVuY3lfOTkYCiAB",
+ "KAESEwoLbGF0ZW5jeV85OTkYCyABKAEimAIKDlNjZW5hcmlvUmVzdWx0EigK",
+ "CHNjZW5hcmlvGAEgASgLMhYuZ3JwYy50ZXN0aW5nLlNjZW5hcmlvEi4KCWxh",
+ "dGVuY2llcxgCIAEoCzIbLmdycGMudGVzdGluZy5IaXN0b2dyYW1EYXRhEi8K",
+ "DGNsaWVudF9zdGF0cxgDIAMoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0",
+ "cxIvCgxzZXJ2ZXJfc3RhdHMYBCADKAsyGS5ncnBjLnRlc3RpbmcuU2VydmVy",
+ "U3RhdHMSFAoMc2VydmVyX2NvcmVzGAUgAygFEjQKB3N1bW1hcnkYBiABKAsy",
+ "Iy5ncnBjLnRlc3RpbmcuU2NlbmFyaW9SZXN1bHRTdW1tYXJ5KkEKCkNsaWVu",
+ "dFR5cGUSDwoLU1lOQ19DTElFTlQQABIQCgxBU1lOQ19DTElFTlQQARIQCgxP",
+ "VEhFUl9DTElFTlQQAipbCgpTZXJ2ZXJUeXBlEg8KC1NZTkNfU0VSVkVSEAAS",
+ "EAoMQVNZTkNfU0VSVkVSEAESGAoUQVNZTkNfR0VORVJJQ19TRVJWRVIQAhIQ",
+ "CgxPVEhFUl9TRVJWRVIQAyojCgdScGNUeXBlEgkKBVVOQVJZEAASDQoJU1RS",
+ "RUFNSU5HEAFiBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Grpc.Testing.PayloadsReflection.Descriptor, global::Grpc.Testing.StatsReflection.Descriptor, },
- new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.ClientType), typeof(global::Grpc.Testing.ServerType), typeof(global::Grpc.Testing.RpcType), }, new pbr::GeneratedCodeInfo[] {
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.PoissonParams), global::Grpc.Testing.PoissonParams.Parser, new[]{ "OfferedLoad" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.UniformParams), global::Grpc.Testing.UniformParams.Parser, new[]{ "InterarrivalLo", "InterarrivalHi" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.DeterministicParams), global::Grpc.Testing.DeterministicParams.Parser, new[]{ "OfferedLoad" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ParetoParams), global::Grpc.Testing.ParetoParams.Parser, new[]{ "InterarrivalBase", "Alpha" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClosedLoopParams), global::Grpc.Testing.ClosedLoopParams.Parser, null, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.LoadParams), global::Grpc.Testing.LoadParams.Parser, new[]{ "ClosedLoop", "Poisson", "Uniform", "Determ", "Pareto" }, new[]{ "Load" }, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SecurityParams), global::Grpc.Testing.SecurityParams.Parser, new[]{ "UseTestCa", "ServerHostOverride" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientConfig), global::Grpc.Testing.ClientConfig.Parser, new[]{ "ServerTargets", "ClientType", "SecurityParams", "OutstandingRpcsPerChannel", "ClientChannels", "AsyncClientThreads", "RpcType", "LoadParams", "PayloadConfig", "HistogramParams", "CoreList", "CoreLimit" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientStatus), global::Grpc.Testing.ClientStatus.Parser, new[]{ "Stats" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Mark), global::Grpc.Testing.Mark.Parser, new[]{ "Reset" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientArgs), global::Grpc.Testing.ClientArgs.Parser, new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerConfig), global::Grpc.Testing.ServerConfig.Parser, new[]{ "ServerType", "SecurityParams", "Port", "AsyncServerThreads", "CoreLimit", "PayloadConfig", "CoreList" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerArgs), global::Grpc.Testing.ServerArgs.Parser, new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerStatus), global::Grpc.Testing.ServerStatus.Parser, new[]{ "Stats", "Port", "Cores" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.CoreRequest), global::Grpc.Testing.CoreRequest.Parser, null, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.CoreResponse), global::Grpc.Testing.CoreResponse.Parser, new[]{ "Cores" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Void), global::Grpc.Testing.Void.Parser, null, null, null, null)
+ new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.ClientType), typeof(global::Grpc.Testing.ServerType), typeof(global::Grpc.Testing.RpcType), }, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.PoissonParams), global::Grpc.Testing.PoissonParams.Parser, new[]{ "OfferedLoad" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClosedLoopParams), global::Grpc.Testing.ClosedLoopParams.Parser, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.LoadParams), global::Grpc.Testing.LoadParams.Parser, new[]{ "ClosedLoop", "Poisson" }, new[]{ "Load" }, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SecurityParams), global::Grpc.Testing.SecurityParams.Parser, new[]{ "UseTestCa", "ServerHostOverride" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientConfig), global::Grpc.Testing.ClientConfig.Parser, new[]{ "ServerTargets", "ClientType", "SecurityParams", "OutstandingRpcsPerChannel", "ClientChannels", "AsyncClientThreads", "RpcType", "LoadParams", "PayloadConfig", "HistogramParams", "CoreList", "CoreLimit", "OtherClientApi" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientStatus), global::Grpc.Testing.ClientStatus.Parser, new[]{ "Stats" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Mark), global::Grpc.Testing.Mark.Parser, new[]{ "Reset" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientArgs), global::Grpc.Testing.ClientArgs.Parser, new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ServerConfig), global::Grpc.Testing.ServerConfig.Parser, new[]{ "ServerType", "SecurityParams", "Port", "AsyncServerThreads", "CoreLimit", "PayloadConfig", "CoreList", "OtherServerApi" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ServerArgs), global::Grpc.Testing.ServerArgs.Parser, new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ServerStatus), global::Grpc.Testing.ServerStatus.Parser, new[]{ "Stats", "Port", "Cores" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.CoreRequest), global::Grpc.Testing.CoreRequest.Parser, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.CoreResponse), global::Grpc.Testing.CoreResponse.Parser, new[]{ "Cores" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Void), global::Grpc.Testing.Void.Parser, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Scenario), global::Grpc.Testing.Scenario.Parser, new[]{ "Name", "ClientConfig", "NumClients", "ServerConfig", "NumServers", "WarmupSeconds", "BenchmarkSeconds", "SpawnLocalWorkerCount" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Scenarios), global::Grpc.Testing.Scenarios.Parser, new[]{ "Scenarios_" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ScenarioResultSummary), global::Grpc.Testing.ScenarioResultSummary.Parser, new[]{ "Qps", "QpsPerServerCore", "ServerSystemTime", "ServerUserTime", "ClientSystemTime", "ClientUserTime", "Latency50", "Latency90", "Latency95", "Latency99", "Latency999" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ScenarioResult), global::Grpc.Testing.ScenarioResult.Parser, new[]{ "Scenario", "Latencies", "ClientStats", "ServerStats", "ServerCores", "Summary" }, null, null, null)
}));
}
#endregion
@@ -96,19 +111,31 @@ namespace Grpc.Testing {
}
#region Enums
public enum ClientType {
- SYNC_CLIENT = 0,
- ASYNC_CLIENT = 1,
+ /// <summary>
+ /// Many languages support a basic distinction between using
+ /// sync or async client, and this allows the specification
+ /// </summary>
+ [pbr::OriginalName("SYNC_CLIENT")] SyncClient = 0,
+ [pbr::OriginalName("ASYNC_CLIENT")] AsyncClient = 1,
+ /// <summary>
+ /// used for some language-specific variants
+ /// </summary>
+ [pbr::OriginalName("OTHER_CLIENT")] OtherClient = 2,
}
public enum ServerType {
- SYNC_SERVER = 0,
- ASYNC_SERVER = 1,
- ASYNC_GENERIC_SERVER = 2,
+ [pbr::OriginalName("SYNC_SERVER")] SyncServer = 0,
+ [pbr::OriginalName("ASYNC_SERVER")] AsyncServer = 1,
+ [pbr::OriginalName("ASYNC_GENERIC_SERVER")] AsyncGenericServer = 2,
+ /// <summary>
+ /// used for some language-specific variants
+ /// </summary>
+ [pbr::OriginalName("OTHER_SERVER")] OtherServer = 3,
}
public enum RpcType {
- UNARY = 0,
- STREAMING = 1,
+ [pbr::OriginalName("UNARY")] Unary = 0,
+ [pbr::OriginalName("STREAMING")] Streaming = 1,
}
#endregion
@@ -224,369 +251,6 @@ namespace Grpc.Testing {
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class UniformParams : pb::IMessage<UniformParams> {
- private static readonly pb::MessageParser<UniformParams> _parser = new pb::MessageParser<UniformParams>(() => new UniformParams());
- public static pb::MessageParser<UniformParams> Parser { get { return _parser; } }
-
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[1]; }
- }
-
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- public UniformParams() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- public UniformParams(UniformParams other) : this() {
- interarrivalLo_ = other.interarrivalLo_;
- interarrivalHi_ = other.interarrivalHi_;
- }
-
- public UniformParams Clone() {
- return new UniformParams(this);
- }
-
- /// <summary>Field number for the "interarrival_lo" field.</summary>
- public const int InterarrivalLoFieldNumber = 1;
- private double interarrivalLo_;
- public double InterarrivalLo {
- get { return interarrivalLo_; }
- set {
- interarrivalLo_ = value;
- }
- }
-
- /// <summary>Field number for the "interarrival_hi" field.</summary>
- public const int InterarrivalHiFieldNumber = 2;
- private double interarrivalHi_;
- public double InterarrivalHi {
- get { return interarrivalHi_; }
- set {
- interarrivalHi_ = value;
- }
- }
-
- public override bool Equals(object other) {
- return Equals(other as UniformParams);
- }
-
- public bool Equals(UniformParams other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (InterarrivalLo != other.InterarrivalLo) return false;
- if (InterarrivalHi != other.InterarrivalHi) return false;
- return true;
- }
-
- public override int GetHashCode() {
- int hash = 1;
- if (InterarrivalLo != 0D) hash ^= InterarrivalLo.GetHashCode();
- if (InterarrivalHi != 0D) hash ^= InterarrivalHi.GetHashCode();
- return hash;
- }
-
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- public void WriteTo(pb::CodedOutputStream output) {
- if (InterarrivalLo != 0D) {
- output.WriteRawTag(9);
- output.WriteDouble(InterarrivalLo);
- }
- if (InterarrivalHi != 0D) {
- output.WriteRawTag(17);
- output.WriteDouble(InterarrivalHi);
- }
- }
-
- public int CalculateSize() {
- int size = 0;
- if (InterarrivalLo != 0D) {
- size += 1 + 8;
- }
- if (InterarrivalHi != 0D) {
- size += 1 + 8;
- }
- return size;
- }
-
- public void MergeFrom(UniformParams other) {
- if (other == null) {
- return;
- }
- if (other.InterarrivalLo != 0D) {
- InterarrivalLo = other.InterarrivalLo;
- }
- if (other.InterarrivalHi != 0D) {
- InterarrivalHi = other.InterarrivalHi;
- }
- }
-
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- input.SkipLastField();
- break;
- case 9: {
- InterarrivalLo = input.ReadDouble();
- break;
- }
- case 17: {
- InterarrivalHi = input.ReadDouble();
- break;
- }
- }
- }
- }
-
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class DeterministicParams : pb::IMessage<DeterministicParams> {
- private static readonly pb::MessageParser<DeterministicParams> _parser = new pb::MessageParser<DeterministicParams>(() => new DeterministicParams());
- public static pb::MessageParser<DeterministicParams> Parser { get { return _parser; } }
-
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[2]; }
- }
-
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- public DeterministicParams() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- public DeterministicParams(DeterministicParams other) : this() {
- offeredLoad_ = other.offeredLoad_;
- }
-
- public DeterministicParams Clone() {
- return new DeterministicParams(this);
- }
-
- /// <summary>Field number for the "offered_load" field.</summary>
- public const int OfferedLoadFieldNumber = 1;
- private double offeredLoad_;
- public double OfferedLoad {
- get { return offeredLoad_; }
- set {
- offeredLoad_ = value;
- }
- }
-
- public override bool Equals(object other) {
- return Equals(other as DeterministicParams);
- }
-
- public bool Equals(DeterministicParams other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (OfferedLoad != other.OfferedLoad) return false;
- return true;
- }
-
- public override int GetHashCode() {
- int hash = 1;
- if (OfferedLoad != 0D) hash ^= OfferedLoad.GetHashCode();
- return hash;
- }
-
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- public void WriteTo(pb::CodedOutputStream output) {
- if (OfferedLoad != 0D) {
- output.WriteRawTag(9);
- output.WriteDouble(OfferedLoad);
- }
- }
-
- public int CalculateSize() {
- int size = 0;
- if (OfferedLoad != 0D) {
- size += 1 + 8;
- }
- return size;
- }
-
- public void MergeFrom(DeterministicParams other) {
- if (other == null) {
- return;
- }
- if (other.OfferedLoad != 0D) {
- OfferedLoad = other.OfferedLoad;
- }
- }
-
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- input.SkipLastField();
- break;
- case 9: {
- OfferedLoad = input.ReadDouble();
- break;
- }
- }
- }
- }
-
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class ParetoParams : pb::IMessage<ParetoParams> {
- private static readonly pb::MessageParser<ParetoParams> _parser = new pb::MessageParser<ParetoParams>(() => new ParetoParams());
- public static pb::MessageParser<ParetoParams> Parser { get { return _parser; } }
-
- public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[3]; }
- }
-
- pbr::MessageDescriptor pb::IMessage.Descriptor {
- get { return Descriptor; }
- }
-
- public ParetoParams() {
- OnConstruction();
- }
-
- partial void OnConstruction();
-
- public ParetoParams(ParetoParams other) : this() {
- interarrivalBase_ = other.interarrivalBase_;
- alpha_ = other.alpha_;
- }
-
- public ParetoParams Clone() {
- return new ParetoParams(this);
- }
-
- /// <summary>Field number for the "interarrival_base" field.</summary>
- public const int InterarrivalBaseFieldNumber = 1;
- private double interarrivalBase_;
- public double InterarrivalBase {
- get { return interarrivalBase_; }
- set {
- interarrivalBase_ = value;
- }
- }
-
- /// <summary>Field number for the "alpha" field.</summary>
- public const int AlphaFieldNumber = 2;
- private double alpha_;
- public double Alpha {
- get { return alpha_; }
- set {
- alpha_ = value;
- }
- }
-
- public override bool Equals(object other) {
- return Equals(other as ParetoParams);
- }
-
- public bool Equals(ParetoParams other) {
- if (ReferenceEquals(other, null)) {
- return false;
- }
- if (ReferenceEquals(other, this)) {
- return true;
- }
- if (InterarrivalBase != other.InterarrivalBase) return false;
- if (Alpha != other.Alpha) return false;
- return true;
- }
-
- public override int GetHashCode() {
- int hash = 1;
- if (InterarrivalBase != 0D) hash ^= InterarrivalBase.GetHashCode();
- if (Alpha != 0D) hash ^= Alpha.GetHashCode();
- return hash;
- }
-
- public override string ToString() {
- return pb::JsonFormatter.ToDiagnosticString(this);
- }
-
- public void WriteTo(pb::CodedOutputStream output) {
- if (InterarrivalBase != 0D) {
- output.WriteRawTag(9);
- output.WriteDouble(InterarrivalBase);
- }
- if (Alpha != 0D) {
- output.WriteRawTag(17);
- output.WriteDouble(Alpha);
- }
- }
-
- public int CalculateSize() {
- int size = 0;
- if (InterarrivalBase != 0D) {
- size += 1 + 8;
- }
- if (Alpha != 0D) {
- size += 1 + 8;
- }
- return size;
- }
-
- public void MergeFrom(ParetoParams other) {
- if (other == null) {
- return;
- }
- if (other.InterarrivalBase != 0D) {
- InterarrivalBase = other.InterarrivalBase;
- }
- if (other.Alpha != 0D) {
- Alpha = other.Alpha;
- }
- }
-
- public void MergeFrom(pb::CodedInputStream input) {
- uint tag;
- while ((tag = input.ReadTag()) != 0) {
- switch(tag) {
- default:
- input.SkipLastField();
- break;
- case 9: {
- InterarrivalBase = input.ReadDouble();
- break;
- }
- case 17: {
- Alpha = input.ReadDouble();
- break;
- }
- }
- }
- }
-
- }
-
/// <summary>
/// Once an RPC finishes, immediately start a new one.
/// No configuration parameters needed.
@@ -597,7 +261,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ClosedLoopParams> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[4]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[1]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -673,7 +337,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<LoadParams> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[5]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[2]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -694,15 +358,6 @@ namespace Grpc.Testing {
case LoadOneofCase.Poisson:
Poisson = other.Poisson.Clone();
break;
- case LoadOneofCase.Uniform:
- Uniform = other.Uniform.Clone();
- break;
- case LoadOneofCase.Determ:
- Determ = other.Determ.Clone();
- break;
- case LoadOneofCase.Pareto:
- Pareto = other.Pareto.Clone();
- break;
}
}
@@ -731,45 +386,12 @@ namespace Grpc.Testing {
}
}
- /// <summary>Field number for the "uniform" field.</summary>
- public const int UniformFieldNumber = 3;
- public global::Grpc.Testing.UniformParams Uniform {
- get { return loadCase_ == LoadOneofCase.Uniform ? (global::Grpc.Testing.UniformParams) load_ : null; }
- set {
- load_ = value;
- loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Uniform;
- }
- }
-
- /// <summary>Field number for the "determ" field.</summary>
- public const int DetermFieldNumber = 4;
- public global::Grpc.Testing.DeterministicParams Determ {
- get { return loadCase_ == LoadOneofCase.Determ ? (global::Grpc.Testing.DeterministicParams) load_ : null; }
- set {
- load_ = value;
- loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Determ;
- }
- }
-
- /// <summary>Field number for the "pareto" field.</summary>
- public const int ParetoFieldNumber = 5;
- public global::Grpc.Testing.ParetoParams Pareto {
- get { return loadCase_ == LoadOneofCase.Pareto ? (global::Grpc.Testing.ParetoParams) load_ : null; }
- set {
- load_ = value;
- loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Pareto;
- }
- }
-
private object load_;
/// <summary>Enum of possible cases for the "load" oneof.</summary>
public enum LoadOneofCase {
None = 0,
ClosedLoop = 1,
Poisson = 2,
- Uniform = 3,
- Determ = 4,
- Pareto = 5,
}
private LoadOneofCase loadCase_ = LoadOneofCase.None;
public LoadOneofCase LoadCase {
@@ -794,9 +416,6 @@ namespace Grpc.Testing {
}
if (!object.Equals(ClosedLoop, other.ClosedLoop)) return false;
if (!object.Equals(Poisson, other.Poisson)) return false;
- if (!object.Equals(Uniform, other.Uniform)) return false;
- if (!object.Equals(Determ, other.Determ)) return false;
- if (!object.Equals(Pareto, other.Pareto)) return false;
if (LoadCase != other.LoadCase) return false;
return true;
}
@@ -805,9 +424,6 @@ namespace Grpc.Testing {
int hash = 1;
if (loadCase_ == LoadOneofCase.ClosedLoop) hash ^= ClosedLoop.GetHashCode();
if (loadCase_ == LoadOneofCase.Poisson) hash ^= Poisson.GetHashCode();
- if (loadCase_ == LoadOneofCase.Uniform) hash ^= Uniform.GetHashCode();
- if (loadCase_ == LoadOneofCase.Determ) hash ^= Determ.GetHashCode();
- if (loadCase_ == LoadOneofCase.Pareto) hash ^= Pareto.GetHashCode();
hash ^= (int) loadCase_;
return hash;
}
@@ -825,18 +441,6 @@ namespace Grpc.Testing {
output.WriteRawTag(18);
output.WriteMessage(Poisson);
}
- if (loadCase_ == LoadOneofCase.Uniform) {
- output.WriteRawTag(26);
- output.WriteMessage(Uniform);
- }
- if (loadCase_ == LoadOneofCase.Determ) {
- output.WriteRawTag(34);
- output.WriteMessage(Determ);
- }
- if (loadCase_ == LoadOneofCase.Pareto) {
- output.WriteRawTag(42);
- output.WriteMessage(Pareto);
- }
}
public int CalculateSize() {
@@ -847,15 +451,6 @@ namespace Grpc.Testing {
if (loadCase_ == LoadOneofCase.Poisson) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Poisson);
}
- if (loadCase_ == LoadOneofCase.Uniform) {
- size += 1 + pb::CodedOutputStream.ComputeMessageSize(Uniform);
- }
- if (loadCase_ == LoadOneofCase.Determ) {
- size += 1 + pb::CodedOutputStream.ComputeMessageSize(Determ);
- }
- if (loadCase_ == LoadOneofCase.Pareto) {
- size += 1 + pb::CodedOutputStream.ComputeMessageSize(Pareto);
- }
return size;
}
@@ -870,15 +465,6 @@ namespace Grpc.Testing {
case LoadOneofCase.Poisson:
Poisson = other.Poisson;
break;
- case LoadOneofCase.Uniform:
- Uniform = other.Uniform;
- break;
- case LoadOneofCase.Determ:
- Determ = other.Determ;
- break;
- case LoadOneofCase.Pareto:
- Pareto = other.Pareto;
- break;
}
}
@@ -908,33 +494,6 @@ namespace Grpc.Testing {
Poisson = subBuilder;
break;
}
- case 26: {
- global::Grpc.Testing.UniformParams subBuilder = new global::Grpc.Testing.UniformParams();
- if (loadCase_ == LoadOneofCase.Uniform) {
- subBuilder.MergeFrom(Uniform);
- }
- input.ReadMessage(subBuilder);
- Uniform = subBuilder;
- break;
- }
- case 34: {
- global::Grpc.Testing.DeterministicParams subBuilder = new global::Grpc.Testing.DeterministicParams();
- if (loadCase_ == LoadOneofCase.Determ) {
- subBuilder.MergeFrom(Determ);
- }
- input.ReadMessage(subBuilder);
- Determ = subBuilder;
- break;
- }
- case 42: {
- global::Grpc.Testing.ParetoParams subBuilder = new global::Grpc.Testing.ParetoParams();
- if (loadCase_ == LoadOneofCase.Pareto) {
- subBuilder.MergeFrom(Pareto);
- }
- input.ReadMessage(subBuilder);
- Pareto = subBuilder;
- break;
- }
}
}
}
@@ -950,7 +509,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<SecurityParams> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[6]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[3]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -988,7 +547,7 @@ namespace Grpc.Testing {
public string ServerHostOverride {
get { return serverHostOverride_; }
set {
- serverHostOverride_ = pb::Preconditions.CheckNotNull(value, "value");
+ serverHostOverride_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
@@ -1080,7 +639,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ClientConfig> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[7]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[4]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1106,6 +665,7 @@ namespace Grpc.Testing {
HistogramParams = other.histogramParams_ != null ? other.HistogramParams.Clone() : null;
coreList_ = other.coreList_.Clone();
coreLimit_ = other.coreLimit_;
+ otherClientApi_ = other.otherClientApi_;
}
public ClientConfig Clone() {
@@ -1126,7 +686,7 @@ namespace Grpc.Testing {
/// <summary>Field number for the "client_type" field.</summary>
public const int ClientTypeFieldNumber = 2;
- private global::Grpc.Testing.ClientType clientType_ = global::Grpc.Testing.ClientType.SYNC_CLIENT;
+ private global::Grpc.Testing.ClientType clientType_ = 0;
public global::Grpc.Testing.ClientType ClientType {
get { return clientType_; }
set {
@@ -1187,7 +747,7 @@ namespace Grpc.Testing {
/// <summary>Field number for the "rpc_type" field.</summary>
public const int RpcTypeFieldNumber = 8;
- private global::Grpc.Testing.RpcType rpcType_ = global::Grpc.Testing.RpcType.UNARY;
+ private global::Grpc.Testing.RpcType rpcType_ = 0;
public global::Grpc.Testing.RpcType RpcType {
get { return rpcType_; }
set {
@@ -1250,6 +810,19 @@ namespace Grpc.Testing {
}
}
+ /// <summary>Field number for the "other_client_api" field.</summary>
+ public const int OtherClientApiFieldNumber = 15;
+ private string otherClientApi_ = "";
+ /// <summary>
+ /// If we use an OTHER_CLIENT client_type, this string gives more detail
+ /// </summary>
+ public string OtherClientApi {
+ get { return otherClientApi_; }
+ set {
+ otherClientApi_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
public override bool Equals(object other) {
return Equals(other as ClientConfig);
}
@@ -1273,23 +846,25 @@ namespace Grpc.Testing {
if (!object.Equals(HistogramParams, other.HistogramParams)) return false;
if(!coreList_.Equals(other.coreList_)) return false;
if (CoreLimit != other.CoreLimit) return false;
+ if (OtherClientApi != other.OtherClientApi) return false;
return true;
}
public override int GetHashCode() {
int hash = 1;
hash ^= serverTargets_.GetHashCode();
- if (ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) hash ^= ClientType.GetHashCode();
+ if (ClientType != 0) hash ^= ClientType.GetHashCode();
if (securityParams_ != null) hash ^= SecurityParams.GetHashCode();
if (OutstandingRpcsPerChannel != 0) hash ^= OutstandingRpcsPerChannel.GetHashCode();
if (ClientChannels != 0) hash ^= ClientChannels.GetHashCode();
if (AsyncClientThreads != 0) hash ^= AsyncClientThreads.GetHashCode();
- if (RpcType != global::Grpc.Testing.RpcType.UNARY) hash ^= RpcType.GetHashCode();
+ if (RpcType != 0) hash ^= RpcType.GetHashCode();
if (loadParams_ != null) hash ^= LoadParams.GetHashCode();
if (payloadConfig_ != null) hash ^= PayloadConfig.GetHashCode();
if (histogramParams_ != null) hash ^= HistogramParams.GetHashCode();
hash ^= coreList_.GetHashCode();
if (CoreLimit != 0) hash ^= CoreLimit.GetHashCode();
+ if (OtherClientApi.Length != 0) hash ^= OtherClientApi.GetHashCode();
return hash;
}
@@ -1299,7 +874,7 @@ namespace Grpc.Testing {
public void WriteTo(pb::CodedOutputStream output) {
serverTargets_.WriteTo(output, _repeated_serverTargets_codec);
- if (ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) {
+ if (ClientType != 0) {
output.WriteRawTag(16);
output.WriteEnum((int) ClientType);
}
@@ -1319,7 +894,7 @@ namespace Grpc.Testing {
output.WriteRawTag(56);
output.WriteInt32(AsyncClientThreads);
}
- if (RpcType != global::Grpc.Testing.RpcType.UNARY) {
+ if (RpcType != 0) {
output.WriteRawTag(64);
output.WriteEnum((int) RpcType);
}
@@ -1340,12 +915,16 @@ namespace Grpc.Testing {
output.WriteRawTag(112);
output.WriteInt32(CoreLimit);
}
+ if (OtherClientApi.Length != 0) {
+ output.WriteRawTag(122);
+ output.WriteString(OtherClientApi);
+ }
}
public int CalculateSize() {
int size = 0;
size += serverTargets_.CalculateSize(_repeated_serverTargets_codec);
- if (ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) {
+ if (ClientType != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ClientType);
}
if (securityParams_ != null) {
@@ -1360,7 +939,7 @@ namespace Grpc.Testing {
if (AsyncClientThreads != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(AsyncClientThreads);
}
- if (RpcType != global::Grpc.Testing.RpcType.UNARY) {
+ if (RpcType != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) RpcType);
}
if (loadParams_ != null) {
@@ -1376,6 +955,9 @@ namespace Grpc.Testing {
if (CoreLimit != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(CoreLimit);
}
+ if (OtherClientApi.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(OtherClientApi);
+ }
return size;
}
@@ -1384,7 +966,7 @@ namespace Grpc.Testing {
return;
}
serverTargets_.Add(other.serverTargets_);
- if (other.ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) {
+ if (other.ClientType != 0) {
ClientType = other.ClientType;
}
if (other.securityParams_ != null) {
@@ -1402,7 +984,7 @@ namespace Grpc.Testing {
if (other.AsyncClientThreads != 0) {
AsyncClientThreads = other.AsyncClientThreads;
}
- if (other.RpcType != global::Grpc.Testing.RpcType.UNARY) {
+ if (other.RpcType != 0) {
RpcType = other.RpcType;
}
if (other.loadParams_ != null) {
@@ -1427,6 +1009,9 @@ namespace Grpc.Testing {
if (other.CoreLimit != 0) {
CoreLimit = other.CoreLimit;
}
+ if (other.OtherClientApi.Length != 0) {
+ OtherClientApi = other.OtherClientApi;
+ }
}
public void MergeFrom(pb::CodedInputStream input) {
@@ -1497,6 +1082,10 @@ namespace Grpc.Testing {
CoreLimit = input.ReadInt32();
break;
}
+ case 122: {
+ OtherClientApi = input.ReadString();
+ break;
+ }
}
}
}
@@ -1509,7 +1098,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ClientStatus> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[8]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[5]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1621,7 +1210,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<Mark> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[9]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[6]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1727,7 +1316,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ClientArgs> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[10]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[7]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1896,7 +1485,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ServerConfig> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[11]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[8]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1917,6 +1506,7 @@ namespace Grpc.Testing {
coreLimit_ = other.coreLimit_;
PayloadConfig = other.payloadConfig_ != null ? other.PayloadConfig.Clone() : null;
coreList_ = other.coreList_.Clone();
+ otherServerApi_ = other.otherServerApi_;
}
public ServerConfig Clone() {
@@ -1925,7 +1515,7 @@ namespace Grpc.Testing {
/// <summary>Field number for the "server_type" field.</summary>
public const int ServerTypeFieldNumber = 1;
- private global::Grpc.Testing.ServerType serverType_ = global::Grpc.Testing.ServerType.SYNC_SERVER;
+ private global::Grpc.Testing.ServerType serverType_ = 0;
public global::Grpc.Testing.ServerType ServerType {
get { return serverType_; }
set {
@@ -2007,6 +1597,19 @@ namespace Grpc.Testing {
get { return coreList_; }
}
+ /// <summary>Field number for the "other_server_api" field.</summary>
+ public const int OtherServerApiFieldNumber = 11;
+ private string otherServerApi_ = "";
+ /// <summary>
+ /// If we use an OTHER_SERVER client_type, this string gives more detail
+ /// </summary>
+ public string OtherServerApi {
+ get { return otherServerApi_; }
+ set {
+ otherServerApi_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
public override bool Equals(object other) {
return Equals(other as ServerConfig);
}
@@ -2025,18 +1628,20 @@ namespace Grpc.Testing {
if (CoreLimit != other.CoreLimit) return false;
if (!object.Equals(PayloadConfig, other.PayloadConfig)) return false;
if(!coreList_.Equals(other.coreList_)) return false;
+ if (OtherServerApi != other.OtherServerApi) return false;
return true;
}
public override int GetHashCode() {
int hash = 1;
- if (ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) hash ^= ServerType.GetHashCode();
+ if (ServerType != 0) hash ^= ServerType.GetHashCode();
if (securityParams_ != null) hash ^= SecurityParams.GetHashCode();
if (Port != 0) hash ^= Port.GetHashCode();
if (AsyncServerThreads != 0) hash ^= AsyncServerThreads.GetHashCode();
if (CoreLimit != 0) hash ^= CoreLimit.GetHashCode();
if (payloadConfig_ != null) hash ^= PayloadConfig.GetHashCode();
hash ^= coreList_.GetHashCode();
+ if (OtherServerApi.Length != 0) hash ^= OtherServerApi.GetHashCode();
return hash;
}
@@ -2045,7 +1650,7 @@ namespace Grpc.Testing {
}
public void WriteTo(pb::CodedOutputStream output) {
- if (ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) {
+ if (ServerType != 0) {
output.WriteRawTag(8);
output.WriteEnum((int) ServerType);
}
@@ -2070,11 +1675,15 @@ namespace Grpc.Testing {
output.WriteMessage(PayloadConfig);
}
coreList_.WriteTo(output, _repeated_coreList_codec);
+ if (OtherServerApi.Length != 0) {
+ output.WriteRawTag(90);
+ output.WriteString(OtherServerApi);
+ }
}
public int CalculateSize() {
int size = 0;
- if (ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) {
+ if (ServerType != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ServerType);
}
if (securityParams_ != null) {
@@ -2093,6 +1702,9 @@ namespace Grpc.Testing {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(PayloadConfig);
}
size += coreList_.CalculateSize(_repeated_coreList_codec);
+ if (OtherServerApi.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(OtherServerApi);
+ }
return size;
}
@@ -2100,7 +1712,7 @@ namespace Grpc.Testing {
if (other == null) {
return;
}
- if (other.ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) {
+ if (other.ServerType != 0) {
ServerType = other.ServerType;
}
if (other.securityParams_ != null) {
@@ -2125,6 +1737,9 @@ namespace Grpc.Testing {
PayloadConfig.MergeFrom(other.PayloadConfig);
}
coreList_.Add(other.coreList_);
+ if (other.OtherServerApi.Length != 0) {
+ OtherServerApi = other.OtherServerApi;
+ }
}
public void MergeFrom(pb::CodedInputStream input) {
@@ -2169,6 +1784,10 @@ namespace Grpc.Testing {
coreList_.AddEntriesFrom(input, _repeated_coreList_codec);
break;
}
+ case 90: {
+ OtherServerApi = input.ReadString();
+ break;
+ }
}
}
}
@@ -2181,7 +1800,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ServerArgs> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[12]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[9]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2350,7 +1969,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ServerStatus> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[13]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[10]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2519,7 +2138,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<CoreRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[14]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[11]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2595,7 +2214,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<CoreResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[15]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[12]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2701,7 +2320,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<Void> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[16]; }
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[13]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2771,6 +2390,1087 @@ namespace Grpc.Testing {
}
+ /// <summary>
+ /// A single performance scenario: input to qps_json_driver
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class Scenario : pb::IMessage<Scenario> {
+ private static readonly pb::MessageParser<Scenario> _parser = new pb::MessageParser<Scenario>(() => new Scenario());
+ public static pb::MessageParser<Scenario> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[14]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public Scenario() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public Scenario(Scenario other) : this() {
+ name_ = other.name_;
+ ClientConfig = other.clientConfig_ != null ? other.ClientConfig.Clone() : null;
+ numClients_ = other.numClients_;
+ ServerConfig = other.serverConfig_ != null ? other.ServerConfig.Clone() : null;
+ numServers_ = other.numServers_;
+ warmupSeconds_ = other.warmupSeconds_;
+ benchmarkSeconds_ = other.benchmarkSeconds_;
+ spawnLocalWorkerCount_ = other.spawnLocalWorkerCount_;
+ }
+
+ public Scenario Clone() {
+ return new Scenario(this);
+ }
+
+ /// <summary>Field number for the "name" field.</summary>
+ public const int NameFieldNumber = 1;
+ private string name_ = "";
+ /// <summary>
+ /// Human readable name for this scenario
+ /// </summary>
+ public string Name {
+ get { return name_; }
+ set {
+ name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// <summary>Field number for the "client_config" field.</summary>
+ public const int ClientConfigFieldNumber = 2;
+ private global::Grpc.Testing.ClientConfig clientConfig_;
+ /// <summary>
+ /// Client configuration
+ /// </summary>
+ public global::Grpc.Testing.ClientConfig ClientConfig {
+ get { return clientConfig_; }
+ set {
+ clientConfig_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "num_clients" field.</summary>
+ public const int NumClientsFieldNumber = 3;
+ private int numClients_;
+ /// <summary>
+ /// Number of clients to start for the test
+ /// </summary>
+ public int NumClients {
+ get { return numClients_; }
+ set {
+ numClients_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "server_config" field.</summary>
+ public const int ServerConfigFieldNumber = 4;
+ private global::Grpc.Testing.ServerConfig serverConfig_;
+ /// <summary>
+ /// Server configuration
+ /// </summary>
+ public global::Grpc.Testing.ServerConfig ServerConfig {
+ get { return serverConfig_; }
+ set {
+ serverConfig_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "num_servers" field.</summary>
+ public const int NumServersFieldNumber = 5;
+ private int numServers_;
+ /// <summary>
+ /// Number of servers to start for the test
+ /// </summary>
+ public int NumServers {
+ get { return numServers_; }
+ set {
+ numServers_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "warmup_seconds" field.</summary>
+ public const int WarmupSecondsFieldNumber = 6;
+ private int warmupSeconds_;
+ /// <summary>
+ /// Warmup period, in seconds
+ /// </summary>
+ public int WarmupSeconds {
+ get { return warmupSeconds_; }
+ set {
+ warmupSeconds_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "benchmark_seconds" field.</summary>
+ public const int BenchmarkSecondsFieldNumber = 7;
+ private int benchmarkSeconds_;
+ /// <summary>
+ /// Benchmark time, in seconds
+ /// </summary>
+ public int BenchmarkSeconds {
+ get { return benchmarkSeconds_; }
+ set {
+ benchmarkSeconds_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "spawn_local_worker_count" field.</summary>
+ public const int SpawnLocalWorkerCountFieldNumber = 8;
+ private int spawnLocalWorkerCount_;
+ /// <summary>
+ /// Number of workers to spawn locally (usually zero)
+ /// </summary>
+ public int SpawnLocalWorkerCount {
+ get { return spawnLocalWorkerCount_; }
+ set {
+ spawnLocalWorkerCount_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as Scenario);
+ }
+
+ public bool Equals(Scenario other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Name != other.Name) return false;
+ if (!object.Equals(ClientConfig, other.ClientConfig)) return false;
+ if (NumClients != other.NumClients) return false;
+ if (!object.Equals(ServerConfig, other.ServerConfig)) return false;
+ if (NumServers != other.NumServers) return false;
+ if (WarmupSeconds != other.WarmupSeconds) return false;
+ if (BenchmarkSeconds != other.BenchmarkSeconds) return false;
+ if (SpawnLocalWorkerCount != other.SpawnLocalWorkerCount) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Name.Length != 0) hash ^= Name.GetHashCode();
+ if (clientConfig_ != null) hash ^= ClientConfig.GetHashCode();
+ if (NumClients != 0) hash ^= NumClients.GetHashCode();
+ if (serverConfig_ != null) hash ^= ServerConfig.GetHashCode();
+ if (NumServers != 0) hash ^= NumServers.GetHashCode();
+ if (WarmupSeconds != 0) hash ^= WarmupSeconds.GetHashCode();
+ if (BenchmarkSeconds != 0) hash ^= BenchmarkSeconds.GetHashCode();
+ if (SpawnLocalWorkerCount != 0) hash ^= SpawnLocalWorkerCount.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Name.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(Name);
+ }
+ if (clientConfig_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(ClientConfig);
+ }
+ if (NumClients != 0) {
+ output.WriteRawTag(24);
+ output.WriteInt32(NumClients);
+ }
+ if (serverConfig_ != null) {
+ output.WriteRawTag(34);
+ output.WriteMessage(ServerConfig);
+ }
+ if (NumServers != 0) {
+ output.WriteRawTag(40);
+ output.WriteInt32(NumServers);
+ }
+ if (WarmupSeconds != 0) {
+ output.WriteRawTag(48);
+ output.WriteInt32(WarmupSeconds);
+ }
+ if (BenchmarkSeconds != 0) {
+ output.WriteRawTag(56);
+ output.WriteInt32(BenchmarkSeconds);
+ }
+ if (SpawnLocalWorkerCount != 0) {
+ output.WriteRawTag(64);
+ output.WriteInt32(SpawnLocalWorkerCount);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Name.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+ }
+ if (clientConfig_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ClientConfig);
+ }
+ if (NumClients != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(NumClients);
+ }
+ if (serverConfig_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ServerConfig);
+ }
+ if (NumServers != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(NumServers);
+ }
+ if (WarmupSeconds != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(WarmupSeconds);
+ }
+ if (BenchmarkSeconds != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(BenchmarkSeconds);
+ }
+ if (SpawnLocalWorkerCount != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(SpawnLocalWorkerCount);
+ }
+ return size;
+ }
+
+ public void MergeFrom(Scenario other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Name.Length != 0) {
+ Name = other.Name;
+ }
+ if (other.clientConfig_ != null) {
+ if (clientConfig_ == null) {
+ clientConfig_ = new global::Grpc.Testing.ClientConfig();
+ }
+ ClientConfig.MergeFrom(other.ClientConfig);
+ }
+ if (other.NumClients != 0) {
+ NumClients = other.NumClients;
+ }
+ if (other.serverConfig_ != null) {
+ if (serverConfig_ == null) {
+ serverConfig_ = new global::Grpc.Testing.ServerConfig();
+ }
+ ServerConfig.MergeFrom(other.ServerConfig);
+ }
+ if (other.NumServers != 0) {
+ NumServers = other.NumServers;
+ }
+ if (other.WarmupSeconds != 0) {
+ WarmupSeconds = other.WarmupSeconds;
+ }
+ if (other.BenchmarkSeconds != 0) {
+ BenchmarkSeconds = other.BenchmarkSeconds;
+ }
+ if (other.SpawnLocalWorkerCount != 0) {
+ SpawnLocalWorkerCount = other.SpawnLocalWorkerCount;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ Name = input.ReadString();
+ break;
+ }
+ case 18: {
+ if (clientConfig_ == null) {
+ clientConfig_ = new global::Grpc.Testing.ClientConfig();
+ }
+ input.ReadMessage(clientConfig_);
+ break;
+ }
+ case 24: {
+ NumClients = input.ReadInt32();
+ break;
+ }
+ case 34: {
+ if (serverConfig_ == null) {
+ serverConfig_ = new global::Grpc.Testing.ServerConfig();
+ }
+ input.ReadMessage(serverConfig_);
+ break;
+ }
+ case 40: {
+ NumServers = input.ReadInt32();
+ break;
+ }
+ case 48: {
+ WarmupSeconds = input.ReadInt32();
+ break;
+ }
+ case 56: {
+ BenchmarkSeconds = input.ReadInt32();
+ break;
+ }
+ case 64: {
+ SpawnLocalWorkerCount = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// A set of scenarios to be run with qps_json_driver
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class Scenarios : pb::IMessage<Scenarios> {
+ private static readonly pb::MessageParser<Scenarios> _parser = new pb::MessageParser<Scenarios>(() => new Scenarios());
+ public static pb::MessageParser<Scenarios> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[15]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public Scenarios() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public Scenarios(Scenarios other) : this() {
+ scenarios_ = other.scenarios_.Clone();
+ }
+
+ public Scenarios Clone() {
+ return new Scenarios(this);
+ }
+
+ /// <summary>Field number for the "scenarios" field.</summary>
+ public const int Scenarios_FieldNumber = 1;
+ private static readonly pb::FieldCodec<global::Grpc.Testing.Scenario> _repeated_scenarios_codec
+ = pb::FieldCodec.ForMessage(10, global::Grpc.Testing.Scenario.Parser);
+ private readonly pbc::RepeatedField<global::Grpc.Testing.Scenario> scenarios_ = new pbc::RepeatedField<global::Grpc.Testing.Scenario>();
+ public pbc::RepeatedField<global::Grpc.Testing.Scenario> Scenarios_ {
+ get { return scenarios_; }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as Scenarios);
+ }
+
+ public bool Equals(Scenarios other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!scenarios_.Equals(other.scenarios_)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= scenarios_.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ scenarios_.WriteTo(output, _repeated_scenarios_codec);
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ size += scenarios_.CalculateSize(_repeated_scenarios_codec);
+ return size;
+ }
+
+ public void MergeFrom(Scenarios other) {
+ if (other == null) {
+ return;
+ }
+ scenarios_.Add(other.scenarios_);
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ scenarios_.AddEntriesFrom(input, _repeated_scenarios_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// Basic summary that can be computed from ClientStats and ServerStats
+ /// once the scenario has finished.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ScenarioResultSummary : pb::IMessage<ScenarioResultSummary> {
+ private static readonly pb::MessageParser<ScenarioResultSummary> _parser = new pb::MessageParser<ScenarioResultSummary>(() => new ScenarioResultSummary());
+ public static pb::MessageParser<ScenarioResultSummary> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[16]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ScenarioResultSummary() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ScenarioResultSummary(ScenarioResultSummary other) : this() {
+ qps_ = other.qps_;
+ qpsPerServerCore_ = other.qpsPerServerCore_;
+ serverSystemTime_ = other.serverSystemTime_;
+ serverUserTime_ = other.serverUserTime_;
+ clientSystemTime_ = other.clientSystemTime_;
+ clientUserTime_ = other.clientUserTime_;
+ latency50_ = other.latency50_;
+ latency90_ = other.latency90_;
+ latency95_ = other.latency95_;
+ latency99_ = other.latency99_;
+ latency999_ = other.latency999_;
+ }
+
+ public ScenarioResultSummary Clone() {
+ return new ScenarioResultSummary(this);
+ }
+
+ /// <summary>Field number for the "qps" field.</summary>
+ public const int QpsFieldNumber = 1;
+ private double qps_;
+ /// <summary>
+ /// Total number of operations per second over all clients.
+ /// </summary>
+ public double Qps {
+ get { return qps_; }
+ set {
+ qps_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "qps_per_server_core" field.</summary>
+ public const int QpsPerServerCoreFieldNumber = 2;
+ private double qpsPerServerCore_;
+ /// <summary>
+ /// QPS per one server core.
+ /// </summary>
+ public double QpsPerServerCore {
+ get { return qpsPerServerCore_; }
+ set {
+ qpsPerServerCore_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "server_system_time" field.</summary>
+ public const int ServerSystemTimeFieldNumber = 3;
+ private double serverSystemTime_;
+ /// <summary>
+ /// server load based on system_time (0.85 => 85%)
+ /// </summary>
+ public double ServerSystemTime {
+ get { return serverSystemTime_; }
+ set {
+ serverSystemTime_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "server_user_time" field.</summary>
+ public const int ServerUserTimeFieldNumber = 4;
+ private double serverUserTime_;
+ /// <summary>
+ /// server load based on user_time (0.85 => 85%)
+ /// </summary>
+ public double ServerUserTime {
+ get { return serverUserTime_; }
+ set {
+ serverUserTime_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "client_system_time" field.</summary>
+ public const int ClientSystemTimeFieldNumber = 5;
+ private double clientSystemTime_;
+ /// <summary>
+ /// client load based on system_time (0.85 => 85%)
+ /// </summary>
+ public double ClientSystemTime {
+ get { return clientSystemTime_; }
+ set {
+ clientSystemTime_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "client_user_time" field.</summary>
+ public const int ClientUserTimeFieldNumber = 6;
+ private double clientUserTime_;
+ /// <summary>
+ /// client load based on user_time (0.85 => 85%)
+ /// </summary>
+ public double ClientUserTime {
+ get { return clientUserTime_; }
+ set {
+ clientUserTime_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "latency_50" field.</summary>
+ public const int Latency50FieldNumber = 7;
+ private double latency50_;
+ /// <summary>
+ /// X% latency percentiles (in nanoseconds)
+ /// </summary>
+ public double Latency50 {
+ get { return latency50_; }
+ set {
+ latency50_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "latency_90" field.</summary>
+ public const int Latency90FieldNumber = 8;
+ private double latency90_;
+ public double Latency90 {
+ get { return latency90_; }
+ set {
+ latency90_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "latency_95" field.</summary>
+ public const int Latency95FieldNumber = 9;
+ private double latency95_;
+ public double Latency95 {
+ get { return latency95_; }
+ set {
+ latency95_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "latency_99" field.</summary>
+ public const int Latency99FieldNumber = 10;
+ private double latency99_;
+ public double Latency99 {
+ get { return latency99_; }
+ set {
+ latency99_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "latency_999" field.</summary>
+ public const int Latency999FieldNumber = 11;
+ private double latency999_;
+ public double Latency999 {
+ get { return latency999_; }
+ set {
+ latency999_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ScenarioResultSummary);
+ }
+
+ public bool Equals(ScenarioResultSummary other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Qps != other.Qps) return false;
+ if (QpsPerServerCore != other.QpsPerServerCore) return false;
+ if (ServerSystemTime != other.ServerSystemTime) return false;
+ if (ServerUserTime != other.ServerUserTime) return false;
+ if (ClientSystemTime != other.ClientSystemTime) return false;
+ if (ClientUserTime != other.ClientUserTime) return false;
+ if (Latency50 != other.Latency50) return false;
+ if (Latency90 != other.Latency90) return false;
+ if (Latency95 != other.Latency95) return false;
+ if (Latency99 != other.Latency99) return false;
+ if (Latency999 != other.Latency999) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Qps != 0D) hash ^= Qps.GetHashCode();
+ if (QpsPerServerCore != 0D) hash ^= QpsPerServerCore.GetHashCode();
+ if (ServerSystemTime != 0D) hash ^= ServerSystemTime.GetHashCode();
+ if (ServerUserTime != 0D) hash ^= ServerUserTime.GetHashCode();
+ if (ClientSystemTime != 0D) hash ^= ClientSystemTime.GetHashCode();
+ if (ClientUserTime != 0D) hash ^= ClientUserTime.GetHashCode();
+ if (Latency50 != 0D) hash ^= Latency50.GetHashCode();
+ if (Latency90 != 0D) hash ^= Latency90.GetHashCode();
+ if (Latency95 != 0D) hash ^= Latency95.GetHashCode();
+ if (Latency99 != 0D) hash ^= Latency99.GetHashCode();
+ if (Latency999 != 0D) hash ^= Latency999.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Qps != 0D) {
+ output.WriteRawTag(9);
+ output.WriteDouble(Qps);
+ }
+ if (QpsPerServerCore != 0D) {
+ output.WriteRawTag(17);
+ output.WriteDouble(QpsPerServerCore);
+ }
+ if (ServerSystemTime != 0D) {
+ output.WriteRawTag(25);
+ output.WriteDouble(ServerSystemTime);
+ }
+ if (ServerUserTime != 0D) {
+ output.WriteRawTag(33);
+ output.WriteDouble(ServerUserTime);
+ }
+ if (ClientSystemTime != 0D) {
+ output.WriteRawTag(41);
+ output.WriteDouble(ClientSystemTime);
+ }
+ if (ClientUserTime != 0D) {
+ output.WriteRawTag(49);
+ output.WriteDouble(ClientUserTime);
+ }
+ if (Latency50 != 0D) {
+ output.WriteRawTag(57);
+ output.WriteDouble(Latency50);
+ }
+ if (Latency90 != 0D) {
+ output.WriteRawTag(65);
+ output.WriteDouble(Latency90);
+ }
+ if (Latency95 != 0D) {
+ output.WriteRawTag(73);
+ output.WriteDouble(Latency95);
+ }
+ if (Latency99 != 0D) {
+ output.WriteRawTag(81);
+ output.WriteDouble(Latency99);
+ }
+ if (Latency999 != 0D) {
+ output.WriteRawTag(89);
+ output.WriteDouble(Latency999);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Qps != 0D) {
+ size += 1 + 8;
+ }
+ if (QpsPerServerCore != 0D) {
+ size += 1 + 8;
+ }
+ if (ServerSystemTime != 0D) {
+ size += 1 + 8;
+ }
+ if (ServerUserTime != 0D) {
+ size += 1 + 8;
+ }
+ if (ClientSystemTime != 0D) {
+ size += 1 + 8;
+ }
+ if (ClientUserTime != 0D) {
+ size += 1 + 8;
+ }
+ if (Latency50 != 0D) {
+ size += 1 + 8;
+ }
+ if (Latency90 != 0D) {
+ size += 1 + 8;
+ }
+ if (Latency95 != 0D) {
+ size += 1 + 8;
+ }
+ if (Latency99 != 0D) {
+ size += 1 + 8;
+ }
+ if (Latency999 != 0D) {
+ size += 1 + 8;
+ }
+ return size;
+ }
+
+ public void MergeFrom(ScenarioResultSummary other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Qps != 0D) {
+ Qps = other.Qps;
+ }
+ if (other.QpsPerServerCore != 0D) {
+ QpsPerServerCore = other.QpsPerServerCore;
+ }
+ if (other.ServerSystemTime != 0D) {
+ ServerSystemTime = other.ServerSystemTime;
+ }
+ if (other.ServerUserTime != 0D) {
+ ServerUserTime = other.ServerUserTime;
+ }
+ if (other.ClientSystemTime != 0D) {
+ ClientSystemTime = other.ClientSystemTime;
+ }
+ if (other.ClientUserTime != 0D) {
+ ClientUserTime = other.ClientUserTime;
+ }
+ if (other.Latency50 != 0D) {
+ Latency50 = other.Latency50;
+ }
+ if (other.Latency90 != 0D) {
+ Latency90 = other.Latency90;
+ }
+ if (other.Latency95 != 0D) {
+ Latency95 = other.Latency95;
+ }
+ if (other.Latency99 != 0D) {
+ Latency99 = other.Latency99;
+ }
+ if (other.Latency999 != 0D) {
+ Latency999 = other.Latency999;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 9: {
+ Qps = input.ReadDouble();
+ break;
+ }
+ case 17: {
+ QpsPerServerCore = input.ReadDouble();
+ break;
+ }
+ case 25: {
+ ServerSystemTime = input.ReadDouble();
+ break;
+ }
+ case 33: {
+ ServerUserTime = input.ReadDouble();
+ break;
+ }
+ case 41: {
+ ClientSystemTime = input.ReadDouble();
+ break;
+ }
+ case 49: {
+ ClientUserTime = input.ReadDouble();
+ break;
+ }
+ case 57: {
+ Latency50 = input.ReadDouble();
+ break;
+ }
+ case 65: {
+ Latency90 = input.ReadDouble();
+ break;
+ }
+ case 73: {
+ Latency95 = input.ReadDouble();
+ break;
+ }
+ case 81: {
+ Latency99 = input.ReadDouble();
+ break;
+ }
+ case 89: {
+ Latency999 = input.ReadDouble();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// Results of a single benchmark scenario.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ScenarioResult : pb::IMessage<ScenarioResult> {
+ private static readonly pb::MessageParser<ScenarioResult> _parser = new pb::MessageParser<ScenarioResult>(() => new ScenarioResult());
+ public static pb::MessageParser<ScenarioResult> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[17]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ScenarioResult() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ScenarioResult(ScenarioResult other) : this() {
+ Scenario = other.scenario_ != null ? other.Scenario.Clone() : null;
+ Latencies = other.latencies_ != null ? other.Latencies.Clone() : null;
+ clientStats_ = other.clientStats_.Clone();
+ serverStats_ = other.serverStats_.Clone();
+ serverCores_ = other.serverCores_.Clone();
+ Summary = other.summary_ != null ? other.Summary.Clone() : null;
+ }
+
+ public ScenarioResult Clone() {
+ return new ScenarioResult(this);
+ }
+
+ /// <summary>Field number for the "scenario" field.</summary>
+ public const int ScenarioFieldNumber = 1;
+ private global::Grpc.Testing.Scenario scenario_;
+ /// <summary>
+ /// Inputs used to run the scenario.
+ /// </summary>
+ public global::Grpc.Testing.Scenario Scenario {
+ get { return scenario_; }
+ set {
+ scenario_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "latencies" field.</summary>
+ public const int LatenciesFieldNumber = 2;
+ private global::Grpc.Testing.HistogramData latencies_;
+ /// <summary>
+ /// Histograms from all clients merged into one histogram.
+ /// </summary>
+ public global::Grpc.Testing.HistogramData Latencies {
+ get { return latencies_; }
+ set {
+ latencies_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "client_stats" field.</summary>
+ public const int ClientStatsFieldNumber = 3;
+ private static readonly pb::FieldCodec<global::Grpc.Testing.ClientStats> _repeated_clientStats_codec
+ = pb::FieldCodec.ForMessage(26, global::Grpc.Testing.ClientStats.Parser);
+ private readonly pbc::RepeatedField<global::Grpc.Testing.ClientStats> clientStats_ = new pbc::RepeatedField<global::Grpc.Testing.ClientStats>();
+ /// <summary>
+ /// Client stats for each client
+ /// </summary>
+ public pbc::RepeatedField<global::Grpc.Testing.ClientStats> ClientStats {
+ get { return clientStats_; }
+ }
+
+ /// <summary>Field number for the "server_stats" field.</summary>
+ public const int ServerStatsFieldNumber = 4;
+ private static readonly pb::FieldCodec<global::Grpc.Testing.ServerStats> _repeated_serverStats_codec
+ = pb::FieldCodec.ForMessage(34, global::Grpc.Testing.ServerStats.Parser);
+ private readonly pbc::RepeatedField<global::Grpc.Testing.ServerStats> serverStats_ = new pbc::RepeatedField<global::Grpc.Testing.ServerStats>();
+ /// <summary>
+ /// Server stats for each server
+ /// </summary>
+ public pbc::RepeatedField<global::Grpc.Testing.ServerStats> ServerStats {
+ get { return serverStats_; }
+ }
+
+ /// <summary>Field number for the "server_cores" field.</summary>
+ public const int ServerCoresFieldNumber = 5;
+ private static readonly pb::FieldCodec<int> _repeated_serverCores_codec
+ = pb::FieldCodec.ForInt32(42);
+ private readonly pbc::RepeatedField<int> serverCores_ = new pbc::RepeatedField<int>();
+ /// <summary>
+ /// Number of cores available to each server
+ /// </summary>
+ public pbc::RepeatedField<int> ServerCores {
+ get { return serverCores_; }
+ }
+
+ /// <summary>Field number for the "summary" field.</summary>
+ public const int SummaryFieldNumber = 6;
+ private global::Grpc.Testing.ScenarioResultSummary summary_;
+ /// <summary>
+ /// An after-the-fact computed summary
+ /// </summary>
+ public global::Grpc.Testing.ScenarioResultSummary Summary {
+ get { return summary_; }
+ set {
+ summary_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ScenarioResult);
+ }
+
+ public bool Equals(ScenarioResult other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Scenario, other.Scenario)) return false;
+ if (!object.Equals(Latencies, other.Latencies)) return false;
+ if(!clientStats_.Equals(other.clientStats_)) return false;
+ if(!serverStats_.Equals(other.serverStats_)) return false;
+ if(!serverCores_.Equals(other.serverCores_)) return false;
+ if (!object.Equals(Summary, other.Summary)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (scenario_ != null) hash ^= Scenario.GetHashCode();
+ if (latencies_ != null) hash ^= Latencies.GetHashCode();
+ hash ^= clientStats_.GetHashCode();
+ hash ^= serverStats_.GetHashCode();
+ hash ^= serverCores_.GetHashCode();
+ if (summary_ != null) hash ^= Summary.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (scenario_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Scenario);
+ }
+ if (latencies_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(Latencies);
+ }
+ clientStats_.WriteTo(output, _repeated_clientStats_codec);
+ serverStats_.WriteTo(output, _repeated_serverStats_codec);
+ serverCores_.WriteTo(output, _repeated_serverCores_codec);
+ if (summary_ != null) {
+ output.WriteRawTag(50);
+ output.WriteMessage(Summary);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (scenario_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Scenario);
+ }
+ if (latencies_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Latencies);
+ }
+ size += clientStats_.CalculateSize(_repeated_clientStats_codec);
+ size += serverStats_.CalculateSize(_repeated_serverStats_codec);
+ size += serverCores_.CalculateSize(_repeated_serverCores_codec);
+ if (summary_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Summary);
+ }
+ return size;
+ }
+
+ public void MergeFrom(ScenarioResult other) {
+ if (other == null) {
+ return;
+ }
+ if (other.scenario_ != null) {
+ if (scenario_ == null) {
+ scenario_ = new global::Grpc.Testing.Scenario();
+ }
+ Scenario.MergeFrom(other.Scenario);
+ }
+ if (other.latencies_ != null) {
+ if (latencies_ == null) {
+ latencies_ = new global::Grpc.Testing.HistogramData();
+ }
+ Latencies.MergeFrom(other.Latencies);
+ }
+ clientStats_.Add(other.clientStats_);
+ serverStats_.Add(other.serverStats_);
+ serverCores_.Add(other.serverCores_);
+ if (other.summary_ != null) {
+ if (summary_ == null) {
+ summary_ = new global::Grpc.Testing.ScenarioResultSummary();
+ }
+ Summary.MergeFrom(other.Summary);
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ if (scenario_ == null) {
+ scenario_ = new global::Grpc.Testing.Scenario();
+ }
+ input.ReadMessage(scenario_);
+ break;
+ }
+ case 18: {
+ if (latencies_ == null) {
+ latencies_ = new global::Grpc.Testing.HistogramData();
+ }
+ input.ReadMessage(latencies_);
+ break;
+ }
+ case 26: {
+ clientStats_.AddEntriesFrom(input, _repeated_clientStats_codec);
+ break;
+ }
+ case 34: {
+ serverStats_.AddEntriesFrom(input, _repeated_serverStats_codec);
+ break;
+ }
+ case 42:
+ case 40: {
+ serverCores_.AddEntriesFrom(input, _repeated_serverCores_codec);
+ break;
+ }
+ case 50: {
+ if (summary_ == null) {
+ summary_ = new global::Grpc.Testing.ScenarioResultSummary();
+ }
+ input.ReadMessage(summary_);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
#endregion
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Empty.cs b/src/csharp/Grpc.IntegrationTesting/Empty.cs
index 4323c5a09f..cf1c23fb0f 100644
--- a/src/csharp/Grpc.IntegrationTesting/Empty.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Empty.cs
@@ -27,8 +27,8 @@ namespace Grpc.Testing {
"c3RpbmciBwoFRW1wdHliBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
- new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Empty), global::Grpc.Testing.Empty.Parser, null, null, null, null)
+ new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Empty), global::Grpc.Testing.Empty.Parser, null, null, null, null)
}));
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs b/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
new file mode 100644
index 0000000000..37786b6c30
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
@@ -0,0 +1,106 @@
+#region Copyright notice and license
+
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Testing;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+ public class GeneratedClientTest
+ {
+ TestService.TestServiceClient unimplementedClient = new UnimplementedTestServiceClient();
+
+ [Test]
+ public void ExpandedParamOverloadCanBeMocked()
+ {
+ var expected = new SimpleResponse();
+
+ var mockClient = new Mock<TestService.TestServiceClient>();
+ // mocking is relatively clumsy because one needs to specify value for all the optional params.
+ mockClient.Setup(m => m.UnaryCall(It.IsAny<SimpleRequest>(), null, null, CancellationToken.None)).Returns(expected);
+
+ Assert.AreSame(expected, mockClient.Object.UnaryCall(new SimpleRequest()));
+ }
+
+ [Test]
+ public void CallOptionsOverloadCanBeMocked()
+ {
+ var expected = new SimpleResponse();
+
+ var mockClient = new Mock<TestService.TestServiceClient>();
+ mockClient.Setup(m => m.UnaryCall(It.IsAny<SimpleRequest>(), It.IsAny<CallOptions>())).Returns(expected);
+
+ Assert.AreSame(expected, mockClient.Object.UnaryCall(new SimpleRequest(), new CallOptions()));
+ }
+
+ [Test]
+ public void DefaultMethodStubThrows_UnaryCall()
+ {
+ Assert.Throws(typeof(NotImplementedException), () => unimplementedClient.UnaryCall(new SimpleRequest()));
+ }
+
+ [Test]
+ public void DefaultMethodStubThrows_ClientStreaming()
+ {
+ Assert.Throws(typeof(NotImplementedException), () => unimplementedClient.StreamingInputCall());
+ }
+
+ [Test]
+ public void DefaultMethodStubThrows_ServerStreaming()
+ {
+ Assert.Throws(typeof(NotImplementedException), () => unimplementedClient.StreamingOutputCall(new StreamingOutputCallRequest()));
+ }
+
+ [Test]
+ public void DefaultMethodStubThrows_DuplexStreaming()
+ {
+ Assert.Throws(typeof(NotImplementedException), () => unimplementedClient.FullDuplexCall());
+ }
+
+ /// <summary>
+ /// Subclass of the generated client that doesn't override any method stubs.
+ /// </summary>
+ private class UnimplementedTestServiceClient : TestService.TestServiceClient
+ {
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs b/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
index 1d758b7540..5fd0e14e78 100644
--- a/src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -33,38 +33,39 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
+using Moq;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
{
- public class HeaderInterceptorTest
+ public class GeneratedServiceBaseTest
{
const string Host = "localhost";
Server server;
Channel channel;
TestService.TestServiceClient client;
- [TestFixtureSetUp]
+ [SetUp]
public void Init()
{
server = new Server
{
- Services = { TestService.BindService(new TestServiceImpl()) },
- Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
+ Services = { TestService.BindService(new UnimplementedTestServiceImpl()) },
+ Ports = { { Host, ServerPort.PickUnused, SslServerCredentials.Insecure } }
};
server.Start();
-
channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
client = TestService.NewClient(channel);
}
- [TestFixtureTearDown]
+ [TearDown]
public void Cleanup()
{
channel.ShutdownAsync().Wait();
@@ -72,42 +73,44 @@ namespace Grpc.IntegrationTesting
}
[Test]
- public async Task HeaderInterceptor_CreateMetadata()
+ public void UnimplementedByDefault_Unary()
{
- var key = "x-grpc-test-echo-initial";
- client.HeaderInterceptor = new HeaderInterceptor((method, metadata) =>
- {
- metadata.Add(key, "ABC");
- });
+ var ex = Assert.Throws<RpcException>(() => client.UnaryCall(new SimpleRequest { }));
+ Assert.AreEqual(StatusCode.Unimplemented, ex.Status.StatusCode);
+ }
- var call = client.UnaryCallAsync(new SimpleRequest());
- await call;
+ [Test]
+ public async Task UnimplementedByDefault_ClientStreaming()
+ {
+ var call = client.StreamingInputCall();
- var responseHeaders = await call.ResponseHeadersAsync;
- Assert.AreEqual("ABC", responseHeaders.First((entry) => entry.Key == key).Value);
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await call);
+ Assert.AreEqual(StatusCode.Unimplemented, ex.Status.StatusCode);
}
[Test]
- public async Task HeaderInterceptor_AppendMetadata()
+ public async Task UnimplementedByDefault_ServerStreamingCall()
{
- var initialKey = "x-grpc-test-echo-initial";
- var trailingKey = "x-grpc-test-echo-trailing-bin";
+ var call = client.StreamingOutputCall(new StreamingOutputCallRequest());
- client.HeaderInterceptor = new HeaderInterceptor((method, metadata) =>
- {
- metadata.Add(initialKey, "ABC");
- });
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
+ Assert.AreEqual(StatusCode.Unimplemented, ex.Status.StatusCode);
+ }
- var headers = new Metadata
- {
- { trailingKey, new byte[] {0xaa} }
- };
- var call = client.UnaryCallAsync(new SimpleRequest(), headers: headers);
- await call;
+ [Test]
+ public async Task UnimplementedByDefault_DuplexStreamingCall()
+ {
+ var call = client.FullDuplexCall();
- var responseHeaders = await call.ResponseHeadersAsync;
- Assert.AreEqual("ABC", responseHeaders.First((entry) => entry.Key == initialKey).Value);
- CollectionAssert.AreEqual(new byte[] {0xaa}, call.GetTrailers().First((entry) => entry.Key == trailingKey).ValueBytes);
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
+ Assert.AreEqual(StatusCode.Unimplemented, ex.Status.StatusCode);
+ }
+
+ /// <summary>
+ /// Implementation of TestService that doesn't override any methods.
+ /// </summary>
+ private class UnimplementedTestServiceImpl : TestService.TestServiceBase
+ {
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/GenericService.cs b/src/csharp/Grpc.IntegrationTesting/GenericService.cs
new file mode 100644
index 0000000000..c6128264ac
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/GenericService.cs
@@ -0,0 +1,71 @@
+#region Copyright notice and license
+
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// Utility methods for defining and calling a service that doesn't use protobufs
+ /// for serialization/deserialization.
+ /// </summary>
+ public static class GenericService
+ {
+ readonly static Marshaller<byte[]> ByteArrayMarshaller = new Marshaller<byte[]>((b) => b, (b) => b);
+
+ public readonly static Method<byte[], byte[]> StreamingCallMethod = new Method<byte[], byte[]>(
+ MethodType.DuplexStreaming,
+ "grpc.testing.BenchmarkService",
+ "StreamingCall",
+ ByteArrayMarshaller,
+ ByteArrayMarshaller
+ );
+
+ public static ServerServiceDefinition BindHandler(DuplexStreamingServerMethod<byte[], byte[]> handler)
+ {
+ return ServerServiceDefinition.CreateBuilder(StreamingCallMethod.ServiceName)
+ .AddMethod(StreamingCallMethod, handler).Build();
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 372991374e..0089049408 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -4,11 +4,11 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C61154BA-DD4A-4838-8420-0162A28925E0}</ProjectGuid>
- <OutputType>Library</OutputType>
+ <OutputType>Exe</OutputType>
<RootNamespace>Grpc.IntegrationTesting</RootNamespace>
<AssemblyName>Grpc.IntegrationTesting</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <NuGetPackageImportStamp>6566287f</NuGetPackageImportStamp>
+ <NuGetPackageImportStamp>3a1c655d</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -41,57 +41,45 @@
<Reference Include="CommandLine">
<HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth, Version=1.10.0.25333, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.10.0\lib\net40\Google.Apis.Auth.dll</HintPath>
- </Reference>
- <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.10.0.25333, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.10.0\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
- </Reference>
- <Reference Include="Google.Apis.Core, Version=1.10.0.25331, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Core.1.10.0\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
- </Reference>
- <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Protobuf.3.0.0-beta2\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
- </Reference>
<Reference Include="Moq">
<HintPath>..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll</HintPath>
</Reference>
- <Reference Include="nunit.framework">
- <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
- </Reference>
<Reference Include="System" />
- <Reference Include="System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Ix-Async.1.2.5\lib\net45\System.Interactive.Async.dll</HintPath>
- </Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="BouncyCastle.Crypto">
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks">
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+ <Reference Include="Google.Apis.Auth">
+ <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions">
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+ <Reference Include="Google.Apis.Auth.PlatformServices">
+ <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+ <Reference Include="Google.Apis.Core">
+ <HintPath>..\packages\Google.Apis.Core.1.11.1\lib\net45\Google.Apis.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Protobuf">
+ <HintPath>..\packages\Google.Protobuf.3.0.0-beta3\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
+ <Reference Include="nunit.framework">
+ <HintPath>..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Interactive.Async">
+ <HintPath>..\packages\Ix-Async.1.2.5\lib\net45\System.Interactive.Async.dll</HintPath>
+ </Reference>
+ <Reference Include="nunitlite">
+ <HintPath>..\packages\NUnitLite.3.2.0\lib\net45\nunitlite.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
- <Compile Include="HeaderInterceptorTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Empty.cs" />
<Compile Include="Messages.cs" />
@@ -120,6 +108,14 @@
<Compile Include="WorkerServiceImpl.cs" />
<Compile Include="QpsWorker.cs" />
<Compile Include="WallClockStopwatch.cs" />
+ <Compile Include="GenericService.cs" />
+ <Compile Include="GeneratedServiceBaseTest.cs" />
+ <Compile Include="GeneratedClientTest.cs" />
+ <Compile Include="InterarrivalTimers.cs" />
+ <Compile Include="NUnitMain.cs" />
+ <Compile Include="StressTestClient.cs" />
+ <Compile Include="Metrics.cs" />
+ <Compile Include="MetricsGrpc.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -133,8 +129,9 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <None Include="app.config" />
- <None Include="packages.config" />
+ <None Include="packages.config">
+ <SubType>Designer</SubType>
+ </None>
<None Include="data\README">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@@ -151,11 +148,4 @@
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
- <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
- <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
- <PropertyGroup>
- <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
- </PropertyGroup>
- <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
- </Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/Histogram.cs b/src/csharp/Grpc.IntegrationTesting/Histogram.cs
index 08a674d817..28d1f078a9 100644
--- a/src/csharp/Grpc.IntegrationTesting/Histogram.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Histogram.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.IntegrationTesting/InterarrivalTimers.cs b/src/csharp/Grpc.IntegrationTesting/InterarrivalTimers.cs
new file mode 100644
index 0000000000..6492d34890
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/InterarrivalTimers.cs
@@ -0,0 +1,148 @@
+#region Copyright notice and license
+
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+ public interface IInterarrivalTimer
+ {
+ void WaitForNext();
+
+ Task WaitForNextAsync();
+ }
+
+ /// <summary>
+ /// Interarrival timer that doesn't wait at all.
+ /// </summary>
+ public class ClosedLoopInterarrivalTimer : IInterarrivalTimer
+ {
+ public ClosedLoopInterarrivalTimer()
+ {
+ }
+
+ public void WaitForNext()
+ {
+ // NOP
+ }
+
+ public Task WaitForNextAsync()
+ {
+ return Task.FromResult<object>(null);
+ }
+ }
+
+ /// <summary>
+ /// Interarrival timer that generates Poisson process load.
+ /// </summary>
+ public class PoissonInterarrivalTimer : IInterarrivalTimer
+ {
+ readonly ExponentialDistribution exponentialDistribution;
+ DateTime? lastEventTime;
+
+ public PoissonInterarrivalTimer(double offeredLoad)
+ {
+ this.exponentialDistribution = new ExponentialDistribution(new Random(), offeredLoad);
+ this.lastEventTime = DateTime.UtcNow;
+ }
+
+ public void WaitForNext()
+ {
+ var waitDuration = GetNextWaitDuration();
+ int millisTimeout = (int) Math.Round(waitDuration.TotalMilliseconds);
+ if (millisTimeout > 0)
+ {
+ // TODO(jtattermusch): probably only works well for a relatively low interarrival rate
+ Thread.Sleep(millisTimeout);
+ }
+ }
+
+ public async Task WaitForNextAsync()
+ {
+ var waitDuration = GetNextWaitDuration();
+ int millisTimeout = (int) Math.Round(waitDuration.TotalMilliseconds);
+ if (millisTimeout > 0)
+ {
+ // TODO(jtattermusch): probably only works well for a relatively low interarrival rate
+ await Task.Delay(millisTimeout);
+ }
+ }
+
+ private TimeSpan GetNextWaitDuration()
+ {
+ if (!lastEventTime.HasValue)
+ {
+ this.lastEventTime = DateTime.Now;
+ }
+
+ var origLastEventTime = this.lastEventTime.Value;
+ this.lastEventTime = origLastEventTime + TimeSpan.FromSeconds(exponentialDistribution.Next());
+ return this.lastEventTime.Value - origLastEventTime;
+ }
+
+ /// <summary>
+ /// Exp generator.
+ /// </summary>
+ private class ExponentialDistribution
+ {
+ readonly Random random;
+ readonly double lambda;
+ readonly double lambdaReciprocal;
+
+ public ExponentialDistribution(Random random, double lambda)
+ {
+ this.random = random;
+ this.lambda = lambda;
+ this.lambdaReciprocal = 1.0 / lambda;
+ }
+
+ public double Next()
+ {
+ double uniform = random.NextDouble();
+ // Use 1.0-uni above to avoid NaN if uni is 0
+ return lambdaReciprocal * (-Math.Log(1.0 - uniform));
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index b0e33e49f7..aea40afee2 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -217,7 +217,7 @@ namespace Grpc.IntegrationTesting
}
}
- public static void RunEmptyUnary(TestService.ITestServiceClient client)
+ public static void RunEmptyUnary(TestService.TestServiceClient client)
{
Console.WriteLine("running empty_unary");
var response = client.EmptyCall(new Empty());
@@ -225,23 +225,23 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static void RunLargeUnary(TestService.ITestServiceClient client)
+ public static void RunLargeUnary(TestService.TestServiceClient client)
{
Console.WriteLine("running large_unary");
var request = new SimpleRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseSize = 314159,
Payload = CreateZerosPayload(271828)
};
var response = client.UnaryCall(request);
- Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
+ Assert.AreEqual(PayloadType.Compressable, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
Console.WriteLine("Passed!");
}
- public static async Task RunClientStreamingAsync(TestService.ITestServiceClient client)
+ public static async Task RunClientStreamingAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running client_streaming");
@@ -257,7 +257,7 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static async Task RunServerStreamingAsync(TestService.ITestServiceClient client)
+ public static async Task RunServerStreamingAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running server_streaming");
@@ -265,7 +265,7 @@ namespace Grpc.IntegrationTesting
var request = new StreamingOutputCallRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseParameters = { bodySizes.ConvertAll((size) => new ResponseParameters { Size = size }) }
};
@@ -274,14 +274,14 @@ namespace Grpc.IntegrationTesting
var responseList = await call.ResponseStream.ToListAsync();
foreach (var res in responseList)
{
- Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type);
+ Assert.AreEqual(PayloadType.Compressable, res.Payload.Type);
}
CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length));
}
Console.WriteLine("Passed!");
}
- public static async Task RunPingPongAsync(TestService.ITestServiceClient client)
+ public static async Task RunPingPongAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running ping_pong");
@@ -289,46 +289,46 @@ namespace Grpc.IntegrationTesting
{
await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 31415 } },
Payload = CreateZerosPayload(27182)
});
Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+ Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 9 } },
Payload = CreateZerosPayload(8)
});
Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+ Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length);
await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 2653 } },
Payload = CreateZerosPayload(1828)
});
Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+ Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length);
await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 58979 } },
Payload = CreateZerosPayload(45904)
});
Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+ Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length);
await call.RequestStream.CompleteAsync();
@@ -338,7 +338,7 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static async Task RunEmptyStreamAsync(TestService.ITestServiceClient client)
+ public static async Task RunEmptyStreamAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running empty_stream");
using (var call = client.FullDuplexCall())
@@ -357,7 +357,7 @@ namespace Grpc.IntegrationTesting
var request = new SimpleRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseSize = 314159,
Payload = CreateZerosPayload(271828),
FillUsername = true,
@@ -367,7 +367,7 @@ namespace Grpc.IntegrationTesting
// not setting credentials here because they were set on channel already
var response = client.UnaryCall(request);
- Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
+ Assert.AreEqual(PayloadType.Compressable, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
Assert.False(string.IsNullOrEmpty(response.OauthScope));
Assert.True(oauthScope.Contains(response.OauthScope));
@@ -381,7 +381,7 @@ namespace Grpc.IntegrationTesting
var request = new SimpleRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseSize = 314159,
Payload = CreateZerosPayload(271828),
FillUsername = true,
@@ -390,7 +390,7 @@ namespace Grpc.IntegrationTesting
// not setting credentials here because they were set on channel already
var response = client.UnaryCall(request);
- Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
+ Assert.AreEqual(PayloadType.Compressable, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
@@ -434,7 +434,7 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static async Task RunCancelAfterBeginAsync(TestService.ITestServiceClient client)
+ public static async Task RunCancelAfterBeginAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running cancel_after_begin");
@@ -445,13 +445,13 @@ namespace Grpc.IntegrationTesting
await Task.Delay(1000);
cts.Cancel();
- var ex = Assert.Throws<RpcException>(async () => await call.ResponseAsync);
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseAsync);
Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
}
Console.WriteLine("Passed!");
}
- public static async Task RunCancelAfterFirstResponseAsync(TestService.ITestServiceClient client)
+ public static async Task RunCancelAfterFirstResponseAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running cancel_after_first_response");
@@ -460,24 +460,32 @@ namespace Grpc.IntegrationTesting
{
await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 31415 } },
Payload = CreateZerosPayload(27182)
});
Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+ Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
cts.Cancel();
- var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.MoveNext());
- Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
+ try
+ {
+ // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
+ await call.ResponseStream.MoveNext();
+ Assert.Fail();
+ }
+ catch (RpcException ex)
+ {
+ Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
+ }
}
Console.WriteLine("Passed!");
}
- public static async Task RunTimeoutOnSleepingServerAsync(TestService.ITestServiceClient client)
+ public static async Task RunTimeoutOnSleepingServerAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running timeout_on_sleeping_server");
@@ -492,21 +500,33 @@ namespace Grpc.IntegrationTesting
{
// Deadline was reached before write has started. Eat the exception and continue.
}
+ catch (RpcException)
+ {
+ // Deadline was reached before write has started. Eat the exception and continue.
+ }
- var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.MoveNext());
- Assert.AreEqual(StatusCode.DeadlineExceeded, ex.Status.StatusCode);
+ try
+ {
+ await call.ResponseStream.MoveNext();
+ Assert.Fail();
+ }
+ catch (RpcException ex)
+ {
+ // We can't guarantee the status code always DeadlineExceeded. See issue #2685.
+ Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal });
+ }
}
Console.WriteLine("Passed!");
}
- public static async Task RunCustomMetadataAsync(TestService.ITestServiceClient client)
+ public static async Task RunCustomMetadataAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running custom_metadata");
{
// step 1: test unary call
var request = new SimpleRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseSize = 314159,
Payload = CreateZerosPayload(271828)
};
@@ -525,7 +545,7 @@ namespace Grpc.IntegrationTesting
// step 2: test full duplex call
var request = new StreamingOutputCallRequest
{
- ResponseType = PayloadType.COMPRESSABLE,
+ ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 31415 } },
Payload = CreateZerosPayload(27182)
};
@@ -546,7 +566,7 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static async Task RunStatusCodeAndMessageAsync(TestService.ITestServiceClient client)
+ public static async Task RunStatusCodeAndMessageAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running status_code_and_message");
var echoStatus = new EchoStatus
@@ -572,15 +592,23 @@ namespace Grpc.IntegrationTesting
await call.RequestStream.WriteAsync(request);
await call.RequestStream.CompleteAsync();
- var e = Assert.Throws<RpcException>(async () => await call.ResponseStream.ToListAsync());
- Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
- Assert.AreEqual(echoStatus.Message, e.Status.Detail);
+ try
+ {
+ // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
+ await call.ResponseStream.ToListAsync();
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
+ Assert.AreEqual(echoStatus.Message, e.Status.Detail);
+ }
}
Console.WriteLine("Passed!");
}
- public static void RunUnimplementedMethod(UnimplementedService.IUnimplementedServiceClient client)
+ public static void RunUnimplementedMethod(UnimplementedService.UnimplementedServiceClient client)
{
Console.WriteLine("running unimplemented_method");
var e = Assert.Throws<RpcException>(() => client.UnimplementedCall(new Empty()));
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index 0d12c4168c..4ee1ff5ec8 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -51,7 +51,7 @@ namespace Grpc.IntegrationTesting
const string Host = "localhost";
Server server;
Channel channel;
- TestService.ITestServiceClient client;
+ TestService.TestServiceClient client;
[TestFixtureSetUp]
public void Init()
diff --git a/src/csharp/Grpc.IntegrationTesting/Messages.cs b/src/csharp/Grpc.IntegrationTesting/Messages.cs
index 7ca47860f6..d42501aa5b 100644
--- a/src/csharp/Grpc.IntegrationTesting/Messages.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Messages.cs
@@ -47,24 +47,26 @@ namespace Grpc.Testing {
"c3Npb24YBiABKA4yHS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEK",
"D3Jlc3BvbnNlX3N0YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3Rh",
"dHVzIkUKG1N0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZRImCgdwYXlsb2Fk",
- "GAEgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiMwoNUmVjb25uZWN0SW5m",
- "bxIOCgZwYXNzZWQYASABKAgSEgoKYmFja29mZl9tcxgCIAMoBSo/CgtQYXls",
- "b2FkVHlwZRIQCgxDT01QUkVTU0FCTEUQABISCg5VTkNPTVBSRVNTQUJMRRAB",
- "EgoKBlJBTkRPTRACKjIKD0NvbXByZXNzaW9uVHlwZRIICgROT05FEAASCAoE",
- "R1pJUBABEgsKB0RFRkxBVEUQAmIGcHJvdG8z"));
+ "GAEgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiMwoPUmVjb25uZWN0UGFy",
+ "YW1zEiAKGG1heF9yZWNvbm5lY3RfYmFja29mZl9tcxgBIAEoBSIzCg1SZWNv",
+ "bm5lY3RJbmZvEg4KBnBhc3NlZBgBIAEoCBISCgpiYWNrb2ZmX21zGAIgAygF",
+ "Kj8KC1BheWxvYWRUeXBlEhAKDENPTVBSRVNTQUJMRRAAEhIKDlVOQ09NUFJF",
+ "U1NBQkxFEAESCgoGUkFORE9NEAIqMgoPQ29tcHJlc3Npb25UeXBlEggKBE5P",
+ "TkUQABIICgRHWklQEAESCwoHREVGTEFURRACYgZwcm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
- new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), typeof(global::Grpc.Testing.CompressionType), }, new pbr::GeneratedCodeInfo[] {
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Payload), global::Grpc.Testing.Payload.Parser, new[]{ "Type", "Body" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.EchoStatus), global::Grpc.Testing.EchoStatus.Parser, new[]{ "Code", "Message" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), global::Grpc.Testing.SimpleRequest.Parser, new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", "ResponseCompression", "ResponseStatus" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleResponse), global::Grpc.Testing.SimpleResponse.Parser, new[]{ "Payload", "Username", "OauthScope" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), global::Grpc.Testing.StreamingInputCallRequest.Parser, new[]{ "Payload" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), global::Grpc.Testing.StreamingInputCallResponse.Parser, new[]{ "AggregatedPayloadSize" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ResponseParameters), global::Grpc.Testing.ResponseParameters.Parser, new[]{ "Size", "IntervalUs" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), global::Grpc.Testing.StreamingOutputCallRequest.Parser, new[]{ "ResponseType", "ResponseParameters", "Payload", "ResponseCompression", "ResponseStatus" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), global::Grpc.Testing.StreamingOutputCallResponse.Parser, new[]{ "Payload" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ReconnectInfo), global::Grpc.Testing.ReconnectInfo.Parser, new[]{ "Passed", "BackoffMs" }, null, null, null)
+ new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), typeof(global::Grpc.Testing.CompressionType), }, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Payload), global::Grpc.Testing.Payload.Parser, new[]{ "Type", "Body" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.EchoStatus), global::Grpc.Testing.EchoStatus.Parser, new[]{ "Code", "Message" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SimpleRequest), global::Grpc.Testing.SimpleRequest.Parser, new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", "ResponseCompression", "ResponseStatus" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SimpleResponse), global::Grpc.Testing.SimpleResponse.Parser, new[]{ "Payload", "Username", "OauthScope" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), global::Grpc.Testing.StreamingInputCallRequest.Parser, new[]{ "Payload" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), global::Grpc.Testing.StreamingInputCallResponse.Parser, new[]{ "AggregatedPayloadSize" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ResponseParameters), global::Grpc.Testing.ResponseParameters.Parser, new[]{ "Size", "IntervalUs" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), global::Grpc.Testing.StreamingOutputCallRequest.Parser, new[]{ "ResponseType", "ResponseParameters", "Payload", "ResponseCompression", "ResponseStatus" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), global::Grpc.Testing.StreamingOutputCallResponse.Parser, new[]{ "Payload" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ReconnectParams), global::Grpc.Testing.ReconnectParams.Parser, new[]{ "MaxReconnectBackoffMs" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ReconnectInfo), global::Grpc.Testing.ReconnectInfo.Parser, new[]{ "Passed", "BackoffMs" }, null, null, null)
}));
}
#endregion
@@ -78,15 +80,15 @@ namespace Grpc.Testing {
/// <summary>
/// Compressable text format.
/// </summary>
- COMPRESSABLE = 0,
+ [pbr::OriginalName("COMPRESSABLE")] Compressable = 0,
/// <summary>
/// Uncompressable binary format.
/// </summary>
- UNCOMPRESSABLE = 1,
+ [pbr::OriginalName("UNCOMPRESSABLE")] Uncompressable = 1,
/// <summary>
/// Randomly chosen from all other formats defined in this enum.
/// </summary>
- RANDOM = 2,
+ [pbr::OriginalName("RANDOM")] Random = 2,
}
/// <summary>
@@ -96,9 +98,9 @@ namespace Grpc.Testing {
/// <summary>
/// No compression
/// </summary>
- NONE = 0,
- GZIP = 1,
- DEFLATE = 2,
+ [pbr::OriginalName("NONE")] None = 0,
+ [pbr::OriginalName("GZIP")] Gzip = 1,
+ [pbr::OriginalName("DEFLATE")] Deflate = 2,
}
#endregion
@@ -137,7 +139,7 @@ namespace Grpc.Testing {
/// <summary>Field number for the "type" field.</summary>
public const int TypeFieldNumber = 1;
- private global::Grpc.Testing.PayloadType type_ = global::Grpc.Testing.PayloadType.COMPRESSABLE;
+ private global::Grpc.Testing.PayloadType type_ = 0;
/// <summary>
/// The type of data in body.
/// </summary>
@@ -157,7 +159,7 @@ namespace Grpc.Testing {
public pb::ByteString Body {
get { return body_; }
set {
- body_ = pb::Preconditions.CheckNotNull(value, "value");
+ body_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
@@ -179,7 +181,7 @@ namespace Grpc.Testing {
public override int GetHashCode() {
int hash = 1;
- if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= Type.GetHashCode();
+ if (Type != 0) hash ^= Type.GetHashCode();
if (Body.Length != 0) hash ^= Body.GetHashCode();
return hash;
}
@@ -189,7 +191,7 @@ namespace Grpc.Testing {
}
public void WriteTo(pb::CodedOutputStream output) {
- if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ if (Type != 0) {
output.WriteRawTag(8);
output.WriteEnum((int) Type);
}
@@ -201,7 +203,7 @@ namespace Grpc.Testing {
public int CalculateSize() {
int size = 0;
- if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ if (Type != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type);
}
if (Body.Length != 0) {
@@ -214,7 +216,7 @@ namespace Grpc.Testing {
if (other == null) {
return;
}
- if (other.Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ if (other.Type != 0) {
Type = other.Type;
}
if (other.Body.Length != 0) {
@@ -291,7 +293,7 @@ namespace Grpc.Testing {
public string Message {
get { return message_; }
set {
- message_ = pb::Preconditions.CheckNotNull(value, "value");
+ message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
@@ -415,7 +417,7 @@ namespace Grpc.Testing {
/// <summary>Field number for the "response_type" field.</summary>
public const int ResponseTypeFieldNumber = 1;
- private global::Grpc.Testing.PayloadType responseType_ = global::Grpc.Testing.PayloadType.COMPRESSABLE;
+ private global::Grpc.Testing.PayloadType responseType_ = 0;
/// <summary>
/// Desired payload type in the response from the server.
/// If response_type is RANDOM, server randomly chooses one from other formats.
@@ -482,7 +484,7 @@ namespace Grpc.Testing {
/// <summary>Field number for the "response_compression" field.</summary>
public const int ResponseCompressionFieldNumber = 6;
- private global::Grpc.Testing.CompressionType responseCompression_ = global::Grpc.Testing.CompressionType.NONE;
+ private global::Grpc.Testing.CompressionType responseCompression_ = 0;
/// <summary>
/// Compression algorithm to be used by the server for the response (stream)
/// </summary>
@@ -529,12 +531,12 @@ namespace Grpc.Testing {
public override int GetHashCode() {
int hash = 1;
- if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode();
+ if (ResponseType != 0) hash ^= ResponseType.GetHashCode();
if (ResponseSize != 0) hash ^= ResponseSize.GetHashCode();
if (payload_ != null) hash ^= Payload.GetHashCode();
if (FillUsername != false) hash ^= FillUsername.GetHashCode();
if (FillOauthScope != false) hash ^= FillOauthScope.GetHashCode();
- if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) hash ^= ResponseCompression.GetHashCode();
+ if (ResponseCompression != 0) hash ^= ResponseCompression.GetHashCode();
if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
return hash;
}
@@ -544,7 +546,7 @@ namespace Grpc.Testing {
}
public void WriteTo(pb::CodedOutputStream output) {
- if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ if (ResponseType != 0) {
output.WriteRawTag(8);
output.WriteEnum((int) ResponseType);
}
@@ -564,7 +566,7 @@ namespace Grpc.Testing {
output.WriteRawTag(40);
output.WriteBool(FillOauthScope);
}
- if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ if (ResponseCompression != 0) {
output.WriteRawTag(48);
output.WriteEnum((int) ResponseCompression);
}
@@ -576,7 +578,7 @@ namespace Grpc.Testing {
public int CalculateSize() {
int size = 0;
- if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ if (ResponseType != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseType);
}
if (ResponseSize != 0) {
@@ -591,7 +593,7 @@ namespace Grpc.Testing {
if (FillOauthScope != false) {
size += 1 + 1;
}
- if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ if (ResponseCompression != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
}
if (responseStatus_ != null) {
@@ -604,7 +606,7 @@ namespace Grpc.Testing {
if (other == null) {
return;
}
- if (other.ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ if (other.ResponseType != 0) {
ResponseType = other.ResponseType;
}
if (other.ResponseSize != 0) {
@@ -622,7 +624,7 @@ namespace Grpc.Testing {
if (other.FillOauthScope != false) {
FillOauthScope = other.FillOauthScope;
}
- if (other.ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ if (other.ResponseCompression != 0) {
ResponseCompression = other.ResponseCompression;
}
if (other.responseStatus_ != null) {
@@ -735,7 +737,7 @@ namespace Grpc.Testing {
public string Username {
get { return username_; }
set {
- username_ = pb::Preconditions.CheckNotNull(value, "value");
+ username_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
@@ -748,7 +750,7 @@ namespace Grpc.Testing {
public string OauthScope {
get { return oauthScope_; }
set {
- oauthScope_ = pb::Preconditions.CheckNotNull(value, "value");
+ oauthScope_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
@@ -1257,7 +1259,7 @@ namespace Grpc.Testing {
/// <summary>Field number for the "response_type" field.</summary>
public const int ResponseTypeFieldNumber = 1;
- private global::Grpc.Testing.PayloadType responseType_ = global::Grpc.Testing.PayloadType.COMPRESSABLE;
+ private global::Grpc.Testing.PayloadType responseType_ = 0;
/// <summary>
/// Desired payload type in the response from the server.
/// If response_type is RANDOM, the payload from each response in the stream
@@ -1298,7 +1300,7 @@ namespace Grpc.Testing {
/// <summary>Field number for the "response_compression" field.</summary>
public const int ResponseCompressionFieldNumber = 6;
- private global::Grpc.Testing.CompressionType responseCompression_ = global::Grpc.Testing.CompressionType.NONE;
+ private global::Grpc.Testing.CompressionType responseCompression_ = 0;
/// <summary>
/// Compression algorithm to be used by the server for the response (stream)
/// </summary>
@@ -1343,10 +1345,10 @@ namespace Grpc.Testing {
public override int GetHashCode() {
int hash = 1;
- if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode();
+ if (ResponseType != 0) hash ^= ResponseType.GetHashCode();
hash ^= responseParameters_.GetHashCode();
if (payload_ != null) hash ^= Payload.GetHashCode();
- if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) hash ^= ResponseCompression.GetHashCode();
+ if (ResponseCompression != 0) hash ^= ResponseCompression.GetHashCode();
if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
return hash;
}
@@ -1356,7 +1358,7 @@ namespace Grpc.Testing {
}
public void WriteTo(pb::CodedOutputStream output) {
- if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ if (ResponseType != 0) {
output.WriteRawTag(8);
output.WriteEnum((int) ResponseType);
}
@@ -1365,7 +1367,7 @@ namespace Grpc.Testing {
output.WriteRawTag(26);
output.WriteMessage(Payload);
}
- if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ if (ResponseCompression != 0) {
output.WriteRawTag(48);
output.WriteEnum((int) ResponseCompression);
}
@@ -1377,14 +1379,14 @@ namespace Grpc.Testing {
public int CalculateSize() {
int size = 0;
- if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ if (ResponseType != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseType);
}
size += responseParameters_.CalculateSize(_repeated_responseParameters_codec);
if (payload_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
- if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ if (ResponseCompression != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
}
if (responseStatus_ != null) {
@@ -1397,7 +1399,7 @@ namespace Grpc.Testing {
if (other == null) {
return;
}
- if (other.ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ if (other.ResponseType != 0) {
ResponseType = other.ResponseType;
}
responseParameters_.Add(other.responseParameters_);
@@ -1407,7 +1409,7 @@ namespace Grpc.Testing {
}
Payload.MergeFrom(other.Payload);
}
- if (other.ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ if (other.ResponseCompression != 0) {
ResponseCompression = other.ResponseCompression;
}
if (other.responseStatus_ != null) {
@@ -1574,6 +1576,113 @@ namespace Grpc.Testing {
/// <summary>
/// For reconnect interop test only.
+ /// Client tells server what reconnection parameters it used.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ReconnectParams : pb::IMessage<ReconnectParams> {
+ private static readonly pb::MessageParser<ReconnectParams> _parser = new pb::MessageParser<ReconnectParams>(() => new ReconnectParams());
+ public static pb::MessageParser<ReconnectParams> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[9]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ReconnectParams() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ReconnectParams(ReconnectParams other) : this() {
+ maxReconnectBackoffMs_ = other.maxReconnectBackoffMs_;
+ }
+
+ public ReconnectParams Clone() {
+ return new ReconnectParams(this);
+ }
+
+ /// <summary>Field number for the "max_reconnect_backoff_ms" field.</summary>
+ public const int MaxReconnectBackoffMsFieldNumber = 1;
+ private int maxReconnectBackoffMs_;
+ public int MaxReconnectBackoffMs {
+ get { return maxReconnectBackoffMs_; }
+ set {
+ maxReconnectBackoffMs_ = value;
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ReconnectParams);
+ }
+
+ public bool Equals(ReconnectParams other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (MaxReconnectBackoffMs != other.MaxReconnectBackoffMs) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (MaxReconnectBackoffMs != 0) hash ^= MaxReconnectBackoffMs.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (MaxReconnectBackoffMs != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(MaxReconnectBackoffMs);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (MaxReconnectBackoffMs != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(MaxReconnectBackoffMs);
+ }
+ return size;
+ }
+
+ public void MergeFrom(ReconnectParams other) {
+ if (other == null) {
+ return;
+ }
+ if (other.MaxReconnectBackoffMs != 0) {
+ MaxReconnectBackoffMs = other.MaxReconnectBackoffMs;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ MaxReconnectBackoffMs = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// For reconnect interop test only.
/// Server tells client whether its reconnects are following the spec and the
/// reconnect backoffs it saw.
/// </summary>
@@ -1583,7 +1692,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ReconnectInfo> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[9]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[10]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
index 1c8bfed1f6..f95af5008f 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -50,15 +50,15 @@ namespace Grpc.IntegrationTesting
const string Host = "localhost";
Server server;
Channel channel;
- TestService.ITestServiceClient client;
+ TestService.TestServiceClient client;
List<ChannelOption> options;
- Mock<TestService.ITestService> serviceMock;
+ Mock<TestService.TestServiceBase> serviceMock;
AsyncAuthInterceptor asyncAuthInterceptor;
[SetUp]
public void Init()
{
- serviceMock = new Mock<TestService.ITestService>();
+ serviceMock = new Mock<TestService.TestServiceBase>();
serviceMock.Setup(m => m.UnaryCall(It.IsAny<SimpleRequest>(), It.IsAny<ServerCallContext>()))
.Returns(new Func<SimpleRequest, ServerCallContext, Task<SimpleResponse>>(UnaryCallHandler));
diff --git a/src/csharp/Grpc.IntegrationTesting/Metrics.cs b/src/csharp/Grpc.IntegrationTesting/Metrics.cs
new file mode 100644
index 0000000000..8f31fbc2a9
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Metrics.cs
@@ -0,0 +1,452 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: src/proto/grpc/testing/metrics.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Grpc.Testing {
+
+ /// <summary>Holder for reflection information generated from src/proto/grpc/testing/metrics.proto</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public static partial class MetricsReflection {
+
+ #region Descriptor
+ /// <summary>File descriptor for src/proto/grpc/testing/metrics.proto</summary>
+ public static pbr::FileDescriptor Descriptor {
+ get { return descriptor; }
+ }
+ private static pbr::FileDescriptor descriptor;
+
+ static MetricsReflection() {
+ byte[] descriptorData = global::System.Convert.FromBase64String(
+ string.Concat(
+ "CiRzcmMvcHJvdG8vZ3JwYy90ZXN0aW5nL21ldHJpY3MucHJvdG8SDGdycGMu",
+ "dGVzdGluZyJsCg1HYXVnZVJlc3BvbnNlEgwKBG5hbWUYASABKAkSFAoKbG9u",
+ "Z192YWx1ZRgCIAEoA0gAEhYKDGRvdWJsZV92YWx1ZRgDIAEoAUgAEhYKDHN0",
+ "cmluZ192YWx1ZRgEIAEoCUgAQgcKBXZhbHVlIhwKDEdhdWdlUmVxdWVzdBIM",
+ "CgRuYW1lGAEgASgJIg4KDEVtcHR5TWVzc2FnZTKgAQoOTWV0cmljc1NlcnZp",
+ "Y2USSQoMR2V0QWxsR2F1Z2VzEhouZ3JwYy50ZXN0aW5nLkVtcHR5TWVzc2Fn",
+ "ZRobLmdycGMudGVzdGluZy5HYXVnZVJlc3BvbnNlMAESQwoIR2V0R2F1Z2US",
+ "Gi5ncnBjLnRlc3RpbmcuR2F1Z2VSZXF1ZXN0GhsuZ3JwYy50ZXN0aW5nLkdh",
+ "dWdlUmVzcG9uc2ViBnByb3RvMw=="));
+ descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+ new pbr::FileDescriptor[] { },
+ new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.GaugeResponse), global::Grpc.Testing.GaugeResponse.Parser, new[]{ "Name", "LongValue", "DoubleValue", "StringValue" }, new[]{ "Value" }, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.GaugeRequest), global::Grpc.Testing.GaugeRequest.Parser, new[]{ "Name" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.EmptyMessage), global::Grpc.Testing.EmptyMessage.Parser, null, null, null, null)
+ }));
+ }
+ #endregion
+
+ }
+ #region Messages
+ /// <summary>
+ /// Reponse message containing the gauge name and value
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class GaugeResponse : pb::IMessage<GaugeResponse> {
+ private static readonly pb::MessageParser<GaugeResponse> _parser = new pb::MessageParser<GaugeResponse>(() => new GaugeResponse());
+ public static pb::MessageParser<GaugeResponse> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.MetricsReflection.Descriptor.MessageTypes[0]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public GaugeResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public GaugeResponse(GaugeResponse other) : this() {
+ name_ = other.name_;
+ switch (other.ValueCase) {
+ case ValueOneofCase.LongValue:
+ LongValue = other.LongValue;
+ break;
+ case ValueOneofCase.DoubleValue:
+ DoubleValue = other.DoubleValue;
+ break;
+ case ValueOneofCase.StringValue:
+ StringValue = other.StringValue;
+ break;
+ }
+
+ }
+
+ public GaugeResponse Clone() {
+ return new GaugeResponse(this);
+ }
+
+ /// <summary>Field number for the "name" field.</summary>
+ public const int NameFieldNumber = 1;
+ private string name_ = "";
+ public string Name {
+ get { return name_; }
+ set {
+ name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// <summary>Field number for the "long_value" field.</summary>
+ public const int LongValueFieldNumber = 2;
+ public long LongValue {
+ get { return valueCase_ == ValueOneofCase.LongValue ? (long) value_ : 0L; }
+ set {
+ value_ = value;
+ valueCase_ = ValueOneofCase.LongValue;
+ }
+ }
+
+ /// <summary>Field number for the "double_value" field.</summary>
+ public const int DoubleValueFieldNumber = 3;
+ public double DoubleValue {
+ get { return valueCase_ == ValueOneofCase.DoubleValue ? (double) value_ : 0D; }
+ set {
+ value_ = value;
+ valueCase_ = ValueOneofCase.DoubleValue;
+ }
+ }
+
+ /// <summary>Field number for the "string_value" field.</summary>
+ public const int StringValueFieldNumber = 4;
+ public string StringValue {
+ get { return valueCase_ == ValueOneofCase.StringValue ? (string) value_ : ""; }
+ set {
+ value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ valueCase_ = ValueOneofCase.StringValue;
+ }
+ }
+
+ private object value_;
+ /// <summary>Enum of possible cases for the "value" oneof.</summary>
+ public enum ValueOneofCase {
+ None = 0,
+ LongValue = 2,
+ DoubleValue = 3,
+ StringValue = 4,
+ }
+ private ValueOneofCase valueCase_ = ValueOneofCase.None;
+ public ValueOneofCase ValueCase {
+ get { return valueCase_; }
+ }
+
+ public void ClearValue() {
+ valueCase_ = ValueOneofCase.None;
+ value_ = null;
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as GaugeResponse);
+ }
+
+ public bool Equals(GaugeResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Name != other.Name) return false;
+ if (LongValue != other.LongValue) return false;
+ if (DoubleValue != other.DoubleValue) return false;
+ if (StringValue != other.StringValue) return false;
+ if (ValueCase != other.ValueCase) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Name.Length != 0) hash ^= Name.GetHashCode();
+ if (valueCase_ == ValueOneofCase.LongValue) hash ^= LongValue.GetHashCode();
+ if (valueCase_ == ValueOneofCase.DoubleValue) hash ^= DoubleValue.GetHashCode();
+ if (valueCase_ == ValueOneofCase.StringValue) hash ^= StringValue.GetHashCode();
+ hash ^= (int) valueCase_;
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Name.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(Name);
+ }
+ if (valueCase_ == ValueOneofCase.LongValue) {
+ output.WriteRawTag(16);
+ output.WriteInt64(LongValue);
+ }
+ if (valueCase_ == ValueOneofCase.DoubleValue) {
+ output.WriteRawTag(25);
+ output.WriteDouble(DoubleValue);
+ }
+ if (valueCase_ == ValueOneofCase.StringValue) {
+ output.WriteRawTag(34);
+ output.WriteString(StringValue);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Name.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+ }
+ if (valueCase_ == ValueOneofCase.LongValue) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(LongValue);
+ }
+ if (valueCase_ == ValueOneofCase.DoubleValue) {
+ size += 1 + 8;
+ }
+ if (valueCase_ == ValueOneofCase.StringValue) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(StringValue);
+ }
+ return size;
+ }
+
+ public void MergeFrom(GaugeResponse other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Name.Length != 0) {
+ Name = other.Name;
+ }
+ switch (other.ValueCase) {
+ case ValueOneofCase.LongValue:
+ LongValue = other.LongValue;
+ break;
+ case ValueOneofCase.DoubleValue:
+ DoubleValue = other.DoubleValue;
+ break;
+ case ValueOneofCase.StringValue:
+ StringValue = other.StringValue;
+ break;
+ }
+
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ Name = input.ReadString();
+ break;
+ }
+ case 16: {
+ LongValue = input.ReadInt64();
+ break;
+ }
+ case 25: {
+ DoubleValue = input.ReadDouble();
+ break;
+ }
+ case 34: {
+ StringValue = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// Request message containing the gauge name
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class GaugeRequest : pb::IMessage<GaugeRequest> {
+ private static readonly pb::MessageParser<GaugeRequest> _parser = new pb::MessageParser<GaugeRequest>(() => new GaugeRequest());
+ public static pb::MessageParser<GaugeRequest> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.MetricsReflection.Descriptor.MessageTypes[1]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public GaugeRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public GaugeRequest(GaugeRequest other) : this() {
+ name_ = other.name_;
+ }
+
+ public GaugeRequest Clone() {
+ return new GaugeRequest(this);
+ }
+
+ /// <summary>Field number for the "name" field.</summary>
+ public const int NameFieldNumber = 1;
+ private string name_ = "";
+ public string Name {
+ get { return name_; }
+ set {
+ name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as GaugeRequest);
+ }
+
+ public bool Equals(GaugeRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Name != other.Name) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Name.Length != 0) hash ^= Name.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Name.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(Name);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Name.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+ }
+ return size;
+ }
+
+ public void MergeFrom(GaugeRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Name.Length != 0) {
+ Name = other.Name;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ Name = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class EmptyMessage : pb::IMessage<EmptyMessage> {
+ private static readonly pb::MessageParser<EmptyMessage> _parser = new pb::MessageParser<EmptyMessage>(() => new EmptyMessage());
+ public static pb::MessageParser<EmptyMessage> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.MetricsReflection.Descriptor.MessageTypes[2]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public EmptyMessage() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public EmptyMessage(EmptyMessage other) : this() {
+ }
+
+ public EmptyMessage Clone() {
+ return new EmptyMessage(this);
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as EmptyMessage);
+ }
+
+ public bool Equals(EmptyMessage other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ return size;
+ }
+
+ public void MergeFrom(EmptyMessage other) {
+ if (other == null) {
+ return;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ }
+ }
+ }
+
+ }
+
+ #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
new file mode 100644
index 0000000000..9d31d1c514
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
@@ -0,0 +1,242 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: src/proto/grpc/testing/metrics.proto
+// Original file comments:
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Contains the definitions for a metrics service and the type of metrics
+// exposed by the service.
+//
+// Currently, 'Gauge' (i.e a metric that represents the measured value of
+// something at an instant of time) is the only metric type supported by the
+// service.
+#region Designer generated code
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+
+namespace Grpc.Testing {
+ public static class MetricsService
+ {
+ static readonly string __ServiceName = "grpc.testing.MetricsService";
+
+ static readonly Marshaller<global::Grpc.Testing.EmptyMessage> __Marshaller_EmptyMessage = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.EmptyMessage.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.GaugeResponse> __Marshaller_GaugeResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.GaugeResponse.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.GaugeRequest> __Marshaller_GaugeRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.GaugeRequest.Parser.ParseFrom);
+
+ static readonly Method<global::Grpc.Testing.EmptyMessage, global::Grpc.Testing.GaugeResponse> __Method_GetAllGauges = new Method<global::Grpc.Testing.EmptyMessage, global::Grpc.Testing.GaugeResponse>(
+ MethodType.ServerStreaming,
+ __ServiceName,
+ "GetAllGauges",
+ __Marshaller_EmptyMessage,
+ __Marshaller_GaugeResponse);
+
+ static readonly Method<global::Grpc.Testing.GaugeRequest, global::Grpc.Testing.GaugeResponse> __Method_GetGauge = new Method<global::Grpc.Testing.GaugeRequest, global::Grpc.Testing.GaugeResponse>(
+ MethodType.Unary,
+ __ServiceName,
+ "GetGauge",
+ __Marshaller_GaugeRequest,
+ __Marshaller_GaugeResponse);
+
+ /// <summary>Service descriptor</summary>
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Grpc.Testing.MetricsReflection.Descriptor.Services[0]; }
+ }
+
+ /// <summary>Client for MetricsService</summary>
+ [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
+ public interface IMetricsServiceClient
+ {
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
+ AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
+ AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, CallOptions options);
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
+ global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
+ global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, CallOptions options);
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
+ AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
+ AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, CallOptions options);
+ }
+
+ /// <summary>Interface of server-side implementations of MetricsService</summary>
+ [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
+ public interface IMetricsService
+ {
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
+ global::System.Threading.Tasks.Task GetAllGauges(global::Grpc.Testing.EmptyMessage request, IServerStreamWriter<global::Grpc.Testing.GaugeResponse> responseStream, ServerCallContext context);
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
+ global::System.Threading.Tasks.Task<global::Grpc.Testing.GaugeResponse> GetGauge(global::Grpc.Testing.GaugeRequest request, ServerCallContext context);
+ }
+
+ /// <summary>Base class for server-side implementations of MetricsService</summary>
+ public abstract class MetricsServiceBase
+ {
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task GetAllGauges(global::Grpc.Testing.EmptyMessage request, IServerStreamWriter<global::Grpc.Testing.GaugeResponse> responseStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.GaugeResponse> GetGauge(global::Grpc.Testing.GaugeRequest request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// <summary>Client for MetricsService</summary>
+ #pragma warning disable 0618
+ public class MetricsServiceClient : ClientBase<MetricsServiceClient>, IMetricsServiceClient
+ #pragma warning restore 0618
+ {
+ public MetricsServiceClient(Channel channel) : base(channel)
+ {
+ }
+ public MetricsServiceClient(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ protected MetricsServiceClient() : base()
+ {
+ }
+ ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ protected MetricsServiceClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
+ public virtual AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return GetAllGauges(request, new CallOptions(headers, deadline, cancellationToken));
+ }
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
+ public virtual AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, CallOptions options)
+ {
+ return CallInvoker.AsyncServerStreamingCall(__Method_GetAllGauges, null, options, request);
+ }
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
+ public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return GetGauge(request, new CallOptions(headers, deadline, cancellationToken));
+ }
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
+ public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, CallOptions options)
+ {
+ return CallInvoker.BlockingUnaryCall(__Method_GetGauge, null, options, request);
+ }
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return GetGaugeAsync(request, new CallOptions(headers, deadline, cancellationToken));
+ }
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, CallOptions options)
+ {
+ return CallInvoker.AsyncUnaryCall(__Method_GetGauge, null, options, request);
+ }
+ protected override MetricsServiceClient NewInstance(ClientBaseConfiguration configuration)
+ {
+ return new MetricsServiceClient(configuration);
+ }
+ }
+
+ /// <summary>Creates a new client for MetricsService</summary>
+ public static MetricsServiceClient NewClient(Channel channel)
+ {
+ return new MetricsServiceClient(channel);
+ }
+
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
+ public static ServerServiceDefinition BindService(IMetricsService serviceImpl)
+ #pragma warning restore 0618
+ {
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_GetAllGauges, serviceImpl.GetAllGauges)
+ .AddMethod(__Method_GetGauge, serviceImpl.GetGauge).Build();
+ }
+
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
+ public static ServerServiceDefinition BindService(MetricsServiceBase serviceImpl)
+ #pragma warning restore 0618
+ {
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_GetAllGauges, serviceImpl.GetAllGauges)
+ .AddMethod(__Method_GetGauge, serviceImpl.GetGauge).Build();
+ }
+
+ }
+}
+#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs b/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
new file mode 100644
index 0000000000..d8902de08f
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
@@ -0,0 +1,59 @@
+#region Copyright notice and license
+
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Reflection;
+using Grpc.Core;
+using Grpc.Core.Logging;
+using NUnit.Common;
+using NUnitLite;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// Provides entry point for NUnitLite
+ /// </summary>
+ public class NUnitMain
+ {
+ public static int Main(string[] args)
+ {
+ // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
+ GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
+#if DOTNET5_4
+ return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
+#else
+ return new AutoRun().Execute(args);
+#endif
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Payloads.cs b/src/csharp/Grpc.IntegrationTesting/Payloads.cs
index 663f625aa7..3ad7a44f4b 100644
--- a/src/csharp/Grpc.IntegrationTesting/Payloads.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Payloads.cs
@@ -34,11 +34,11 @@ namespace Grpc.Testing {
"aW5nLkNvbXBsZXhQcm90b1BhcmFtc0gAQgkKB3BheWxvYWRiBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
- new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ByteBufferParams), global::Grpc.Testing.ByteBufferParams.Parser, new[]{ "ReqSize", "RespSize" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleProtoParams), global::Grpc.Testing.SimpleProtoParams.Parser, new[]{ "ReqSize", "RespSize" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ComplexProtoParams), global::Grpc.Testing.ComplexProtoParams.Parser, null, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.PayloadConfig), global::Grpc.Testing.PayloadConfig.Parser, new[]{ "BytebufParams", "SimpleParams", "ComplexParams" }, new[]{ "Payload" }, null, null)
+ new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ByteBufferParams), global::Grpc.Testing.ByteBufferParams.Parser, new[]{ "ReqSize", "RespSize" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SimpleProtoParams), global::Grpc.Testing.SimpleProtoParams.Parser, new[]{ "ReqSize", "RespSize" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ComplexProtoParams), global::Grpc.Testing.ComplexProtoParams.Parser, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.PayloadConfig), global::Grpc.Testing.PayloadConfig.Parser, new[]{ "BytebufParams", "SimpleParams", "ComplexParams" }, new[]{ "Payload" }, null, null)
}));
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs b/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs
index e407792c4b..a7c9fa894d 100644
--- a/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs
+++ b/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
diff --git a/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
index 06d5ee93d8..b2f2e4d691 100644
--- a/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -55,14 +55,7 @@ namespace Grpc.IntegrationTesting
{
var serverConfig = new ServerConfig
{
- ServerType = ServerType.ASYNC_SERVER,
- PayloadConfig = new PayloadConfig
- {
- SimpleParams = new SimpleProtoParams
- {
- RespSize = 100
- }
- }
+ ServerType = ServerType.AsyncServer
};
serverRunner = ServerRunners.CreateStarted(serverConfig);
}
@@ -82,13 +75,14 @@ namespace Grpc.IntegrationTesting
var config = new ClientConfig
{
ServerTargets = { string.Format("{0}:{1}", "localhost", serverRunner.BoundPort) },
- RpcType = RpcType.UNARY,
+ RpcType = RpcType.Unary,
LoadParams = new LoadParams { ClosedLoop = new ClosedLoopParams() },
PayloadConfig = new PayloadConfig
{
SimpleParams = new SimpleProtoParams
{
- ReqSize = 100
+ ReqSize = 100,
+ RespSize = 100
}
},
HistogramParams = new HistogramParams
diff --git a/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
index 4a73645e6c..8689d188ae 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -41,6 +41,7 @@ using System.Threading;
using System.Threading.Tasks;
using Google.Protobuf;
using Grpc.Core;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
using NUnit.Framework;
using Grpc.Testing;
@@ -50,27 +51,78 @@ namespace Grpc.IntegrationTesting
/// <summary>
/// Helper methods to start server runners for performance testing.
/// </summary>
- public static class ServerRunners
+ public class ServerRunners
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<ServerRunners>();
+
/// <summary>
/// Creates a started server runner.
/// </summary>
public static IServerRunner CreateStarted(ServerConfig config)
{
- GrpcPreconditions.CheckArgument(config.ServerType == ServerType.ASYNC_SERVER);
+ Logger.Debug("ServerConfig: {0}", config);
var credentials = config.SecurityParams != null ? TestCredentials.CreateSslServerCredentials() : ServerCredentials.Insecure;
- // TODO: qps_driver needs to setup payload properly...
- int responseSize = config.PayloadConfig != null ? config.PayloadConfig.SimpleParams.RespSize : 0;
+ if (config.AsyncServerThreads != 0)
+ {
+ Logger.Warning("ServerConfig.AsyncServerThreads is not supported for C#. Ignoring the value");
+ }
+ if (config.CoreLimit != 0)
+ {
+ Logger.Warning("ServerConfig.CoreLimit is not supported for C#. Ignoring the value");
+ }
+ if (config.CoreList.Count > 0)
+ {
+ Logger.Warning("ServerConfig.CoreList is not supported for C#. Ignoring the value");
+ }
+
+ ServerServiceDefinition service = null;
+ if (config.ServerType == ServerType.AsyncServer)
+ {
+ GrpcPreconditions.CheckArgument(config.PayloadConfig == null,
+ "ServerConfig.PayloadConfig shouldn't be set for BenchmarkService based server.");
+ service = BenchmarkService.BindService(new BenchmarkServiceImpl());
+ }
+ else if (config.ServerType == ServerType.AsyncGenericServer)
+ {
+ var genericService = new GenericServiceImpl(config.PayloadConfig.BytebufParams.RespSize);
+ service = GenericService.BindHandler(genericService.StreamingCall);
+ }
+ else
+ {
+ throw new ArgumentException("Unsupported ServerType");
+ }
+
var server = new Server
{
- Services = { BenchmarkService.BindService(new BenchmarkServiceImpl(responseSize)) },
+ Services = { service },
Ports = { new ServerPort("[::]", config.Port, credentials) }
};
server.Start();
return new ServerRunnerImpl(server);
}
+
+ private class GenericServiceImpl
+ {
+ readonly byte[] response;
+
+ public GenericServiceImpl(int responseSize)
+ {
+ this.response = new byte[responseSize];
+ }
+
+ /// <summary>
+ /// Generic streaming call handler.
+ /// </summary>
+ public async Task StreamingCall(IAsyncStreamReader<byte[]> requestStream, IServerStreamWriter<byte[]> responseStream, ServerCallContext context)
+ {
+ await requestStream.ForEachAsync(async request =>
+ {
+ await responseStream.WriteAsync(response);
+ });
+ }
+ }
}
/// <summary>
@@ -119,6 +171,5 @@ namespace Grpc.IntegrationTesting
{
return server.ShutdownAsync();
}
- }
-
+ }
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Services.cs b/src/csharp/Grpc.IntegrationTesting/Services.cs
index a8475c1817..e10b45c9a2 100644
--- a/src/csharp/Grpc.IntegrationTesting/Services.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Services.cs
@@ -39,7 +39,7 @@ namespace Grpc.Testing {
"YgZwcm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Grpc.Testing.MessagesReflection.Descriptor, global::Grpc.Testing.ControlReflection.Descriptor, },
- new pbr::GeneratedCodeInfo(null, null));
+ new pbr::GeneratedClrTypeInfo(null, null));
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
index 996439afbf..f7071ebf6b 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
@@ -1,5 +1,37 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: src/proto/grpc/testing/services.proto
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
#region Designer generated code
using System;
@@ -29,80 +61,185 @@ namespace Grpc.Testing {
__Marshaller_SimpleRequest,
__Marshaller_SimpleResponse);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.ServicesReflection.Descriptor.Services[0]; }
}
- // client interface
+ /// <summary>Client for BenchmarkService</summary>
+ [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IBenchmarkServiceClient
{
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of BenchmarkService</summary>
+ [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IBenchmarkService
{
- Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
- Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context);
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
+ global::System.Threading.Tasks.Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
+ global::System.Threading.Tasks.Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context);
}
- // client stub
- public class BenchmarkServiceClient : ClientBase, IBenchmarkServiceClient
+ /// <summary>Base class for server-side implementations of BenchmarkService</summary>
+ public abstract class BenchmarkServiceBase
+ {
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// <summary>Client for BenchmarkService</summary>
+ #pragma warning disable 0618
+ public class BenchmarkServiceClient : ClientBase<BenchmarkServiceClient>, IBenchmarkServiceClient
+ #pragma warning restore 0618
{
public BenchmarkServiceClient(Channel channel) : base(channel)
{
}
- public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public BenchmarkServiceClient(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ protected BenchmarkServiceClient() : base()
+ {
+ }
+ ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ protected BenchmarkServiceClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
+ public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return UnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
+ }
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
+ public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
- var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.BlockingUnaryCall(call, request);
+ return CallInvoker.BlockingUnaryCall(__Method_UnaryCall, null, options, request);
}
- public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_UnaryCall, options);
- return Calls.BlockingUnaryCall(call, request);
+ return UnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
- var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncUnaryCall(call, request);
+ return CallInvoker.AsyncUnaryCall(__Method_UnaryCall, null, options, request);
}
- public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_UnaryCall, options);
- return Calls.AsyncUnaryCall(call, request);
+ return StreamingCall(new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options)
{
- var call = CreateCall(__Method_StreamingCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncDuplexStreamingCall(call);
+ return CallInvoker.AsyncDuplexStreamingCall(__Method_StreamingCall, null, options);
}
- public AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options)
+ protected override BenchmarkServiceClient NewInstance(ClientBaseConfiguration configuration)
{
- var call = CreateCall(__Method_StreamingCall, options);
- return Calls.AsyncDuplexStreamingCall(call);
+ return new BenchmarkServiceClient(configuration);
}
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates a new client for BenchmarkService</summary>
+ public static BenchmarkServiceClient NewClient(Channel channel)
+ {
+ return new BenchmarkServiceClient(channel);
+ }
+
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
public static ServerServiceDefinition BindService(IBenchmarkService serviceImpl)
+ #pragma warning restore 0618
{
return ServerServiceDefinition.CreateBuilder(__ServiceName)
.AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
.AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
}
- // creates a new client
- public static BenchmarkServiceClient NewClient(Channel channel)
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
+ public static ServerServiceDefinition BindService(BenchmarkServiceBase serviceImpl)
+ #pragma warning restore 0618
{
- return new BenchmarkServiceClient(channel);
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
+ .AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
}
}
@@ -146,108 +283,305 @@ namespace Grpc.Testing {
__Marshaller_Void,
__Marshaller_Void);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.ServicesReflection.Descriptor.Services[1]; }
}
- // client interface
+ /// <summary>Client for WorkerService</summary>
+ [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IWorkerServiceClient
{
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// 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.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// 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.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options);
+ /// <summary>
+ /// 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.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// 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.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options);
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options);
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options);
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options);
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of WorkerService</summary>
+ [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IWorkerService
{
- Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context);
- Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context);
- Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context);
- Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context);
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// 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.
+ /// </summary>
+ global::System.Threading.Tasks.Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context);
+ /// <summary>
+ /// 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.
+ /// </summary>
+ global::System.Threading.Tasks.Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context);
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
+ global::System.Threading.Tasks.Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context);
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
+ global::System.Threading.Tasks.Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context);
+ }
+
+ /// <summary>Base class for server-side implementations of WorkerService</summary>
+ public abstract class WorkerServiceBase
+ {
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// 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.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
}
- // client stub
- public class WorkerServiceClient : ClientBase, IWorkerServiceClient
+ /// <summary>Client for WorkerService</summary>
+ #pragma warning disable 0618
+ public class WorkerServiceClient : ClientBase<WorkerServiceClient>, IWorkerServiceClient
+ #pragma warning restore 0618
{
public WorkerServiceClient(Channel channel) : base(channel)
{
}
- public AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public WorkerServiceClient(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ protected WorkerServiceClient() : base()
+ {
+ }
+ ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ protected WorkerServiceClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// 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.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return RunServer(new CallOptions(headers, deadline, cancellationToken));
+ }
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// 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.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options)
{
- var call = CreateCall(__Method_RunServer, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncDuplexStreamingCall(call);
+ return CallInvoker.AsyncDuplexStreamingCall(__Method_RunServer, null, options);
}
- public AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options)
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_RunServer, options);
- return Calls.AsyncDuplexStreamingCall(call);
+ return RunClient(new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options)
{
- var call = CreateCall(__Method_RunClient, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncDuplexStreamingCall(call);
+ return CallInvoker.AsyncDuplexStreamingCall(__Method_RunClient, null, options);
}
- public AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options)
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
+ public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_RunClient, options);
- return Calls.AsyncDuplexStreamingCall(call);
+ return CoreCount(request, new CallOptions(headers, deadline, cancellationToken));
}
- public global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
+ public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options)
{
- var call = CreateCall(__Method_CoreCount, new CallOptions(headers, deadline, cancellationToken));
- return Calls.BlockingUnaryCall(call, request);
+ return CallInvoker.BlockingUnaryCall(__Method_CoreCount, null, options, request);
}
- public global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options)
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_CoreCount, options);
- return Calls.BlockingUnaryCall(call, request);
+ return CoreCountAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options)
{
- var call = CreateCall(__Method_CoreCount, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncUnaryCall(call, request);
+ return CallInvoker.AsyncUnaryCall(__Method_CoreCount, null, options, request);
}
- public AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options)
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
+ public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_CoreCount, options);
- return Calls.AsyncUnaryCall(call, request);
+ return QuitWorker(request, new CallOptions(headers, deadline, cancellationToken));
}
- public global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
+ public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options)
{
- var call = CreateCall(__Method_QuitWorker, new CallOptions(headers, deadline, cancellationToken));
- return Calls.BlockingUnaryCall(call, request);
+ return CallInvoker.BlockingUnaryCall(__Method_QuitWorker, null, options, request);
}
- public global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options)
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_QuitWorker, options);
- return Calls.BlockingUnaryCall(call, request);
+ return QuitWorkerAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options)
{
- var call = CreateCall(__Method_QuitWorker, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncUnaryCall(call, request);
+ return CallInvoker.AsyncUnaryCall(__Method_QuitWorker, null, options, request);
}
- public AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options)
+ protected override WorkerServiceClient NewInstance(ClientBaseConfiguration configuration)
{
- var call = CreateCall(__Method_QuitWorker, options);
- return Calls.AsyncUnaryCall(call, request);
+ return new WorkerServiceClient(configuration);
}
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates a new client for WorkerService</summary>
+ public static WorkerServiceClient NewClient(Channel channel)
+ {
+ return new WorkerServiceClient(channel);
+ }
+
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
public static ServerServiceDefinition BindService(IWorkerService serviceImpl)
+ #pragma warning restore 0618
{
return ServerServiceDefinition.CreateBuilder(__ServiceName)
.AddMethod(__Method_RunServer, serviceImpl.RunServer)
@@ -256,10 +590,16 @@ namespace Grpc.Testing {
.AddMethod(__Method_QuitWorker, serviceImpl.QuitWorker).Build();
}
- // creates a new client
- public static WorkerServiceClient NewClient(Channel channel)
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
+ public static ServerServiceDefinition BindService(WorkerServiceBase serviceImpl)
+ #pragma warning restore 0618
{
- return new WorkerServiceClient(channel);
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_RunServer, serviceImpl.RunServer)
+ .AddMethod(__Method_RunClient, serviceImpl.RunClient)
+ .AddMethod(__Method_CoreCount, serviceImpl.CoreCount)
+ .AddMethod(__Method_QuitWorker, serviceImpl.QuitWorker).Build();
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
index 37b2518c21..3df45b5f70 100644
--- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -53,7 +53,7 @@ namespace Grpc.IntegrationTesting
const string Host = "localhost";
Server server;
Channel channel;
- TestService.ITestServiceClient client;
+ TestService.TestServiceClient client;
[TestFixtureSetUp]
public void Init()
diff --git a/src/csharp/Grpc.IntegrationTesting/Stats.cs b/src/csharp/Grpc.IntegrationTesting/Stats.cs
index 39c00ea88c..304d676113 100644
--- a/src/csharp/Grpc.IntegrationTesting/Stats.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Stats.cs
@@ -35,11 +35,11 @@ namespace Grpc.Testing {
"ZXIYAyABKAESEwoLdGltZV9zeXN0ZW0YBCABKAFiBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
- new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerStats), global::Grpc.Testing.ServerStats.Parser, new[]{ "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.HistogramParams), global::Grpc.Testing.HistogramParams.Parser, new[]{ "Resolution", "MaxPossible" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.HistogramData), global::Grpc.Testing.HistogramData.Parser, new[]{ "Bucket", "MinSeen", "MaxSeen", "Sum", "SumOfSquares", "Count" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientStats), global::Grpc.Testing.ClientStats.Parser, new[]{ "Latencies", "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null)
+ new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ServerStats), global::Grpc.Testing.ServerStats.Parser, new[]{ "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.HistogramParams), global::Grpc.Testing.HistogramParams.Parser, new[]{ "Resolution", "MaxPossible" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.HistogramData), global::Grpc.Testing.HistogramData.Parser, new[]{ "Bucket", "MinSeen", "MaxSeen", "Sum", "SumOfSquares", "Count" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientStats), global::Grpc.Testing.ClientStats.Parser, new[]{ "Latencies", "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null)
}));
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs b/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
new file mode 100644
index 0000000000..4d6ca7ece5
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
@@ -0,0 +1,318 @@
+#region Copyright notice and license
+
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using CommandLine;
+using CommandLine.Text;
+using Grpc.Core;
+using Grpc.Core.Logging;
+using Grpc.Core.Utils;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+ public class StressTestClient
+ {
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<StressTestClient>();
+ const double SecondsToNanos = 1e9;
+
+ private class ClientOptions
+ {
+ [Option("server_addresses", DefaultValue = "localhost:8080")]
+ public string ServerAddresses { get; set; }
+
+ [Option("test_cases", DefaultValue = "large_unary:100")]
+ public string TestCases { get; set; }
+
+ [Option("test_duration_secs", DefaultValue = -1)]
+ public int TestDurationSecs { get; set; }
+
+ [Option("num_channels_per_server", DefaultValue = 1)]
+ public int NumChannelsPerServer { get; set; }
+
+ [Option("num_stubs_per_channel", DefaultValue = 1)]
+ public int NumStubsPerChannel { get; set; }
+
+ [Option("metrics_port", DefaultValue = 8081)]
+ public int MetricsPort { get; set; }
+
+ [HelpOption]
+ public string GetUsage()
+ {
+ var help = new HelpText
+ {
+ Heading = "gRPC C# stress test client",
+ AddDashesToOption = true
+ };
+ help.AddPreOptionsLine("Usage:");
+ help.AddOptions(this);
+ return help;
+ }
+ }
+
+ ClientOptions options;
+ List<string> serverAddresses;
+ Dictionary<string, int> weightedTestCases;
+ WeightedRandomGenerator testCaseGenerator;
+
+ // cancellation will be emitted once test_duration_secs has elapsed.
+ CancellationTokenSource finishedTokenSource = new CancellationTokenSource();
+ Histogram histogram = new Histogram(0.01, 60 * SecondsToNanos);
+
+ private StressTestClient(ClientOptions options, List<string> serverAddresses, Dictionary<string, int> weightedTestCases)
+ {
+ this.options = options;
+ this.serverAddresses = serverAddresses;
+ this.weightedTestCases = weightedTestCases;
+ this.testCaseGenerator = new WeightedRandomGenerator(this.weightedTestCases);
+ }
+
+ public static void Run(string[] args)
+ {
+ var options = new ClientOptions();
+ if (!Parser.Default.ParseArguments(args, options))
+ {
+ Environment.Exit(1);
+ }
+
+ GrpcPreconditions.CheckArgument(options.NumChannelsPerServer > 0);
+ GrpcPreconditions.CheckArgument(options.NumStubsPerChannel > 0);
+
+ var serverAddresses = options.ServerAddresses.Split(',');
+ GrpcPreconditions.CheckArgument(serverAddresses.Length > 0, "You need to provide at least one server address");
+
+ var testCases = ParseWeightedTestCases(options.TestCases);
+ GrpcPreconditions.CheckArgument(testCases.Count > 0, "You need to provide at least one test case");
+
+ var interopClient = new StressTestClient(options, serverAddresses.ToList(), testCases);
+ interopClient.Run().Wait();
+ }
+
+ async Task Run()
+ {
+ var metricsServer = new Server()
+ {
+ Services = { MetricsService.BindService(new MetricsServiceImpl(histogram)) },
+ Ports = { { "[::]", options.MetricsPort, ServerCredentials.Insecure } }
+ };
+ metricsServer.Start();
+
+ if (options.TestDurationSecs >= 0)
+ {
+ finishedTokenSource.CancelAfter(TimeSpan.FromSeconds(options.TestDurationSecs));
+ }
+
+ var tasks = new List<Task>();
+ var channels = new List<Channel>();
+ foreach (var serverAddress in serverAddresses)
+ {
+ for (int i = 0; i < options.NumChannelsPerServer; i++)
+ {
+ var channel = new Channel(serverAddress, ChannelCredentials.Insecure);
+ channels.Add(channel);
+ for (int j = 0; j < options.NumStubsPerChannel; j++)
+ {
+ var client = TestService.NewClient(channel);
+ var task = Task.Factory.StartNew(() => RunBodyAsync(client).GetAwaiter().GetResult(),
+ TaskCreationOptions.LongRunning);
+ tasks.Add(task);
+ }
+ }
+ }
+ await Task.WhenAll(tasks);
+
+ foreach (var channel in channels)
+ {
+ await channel.ShutdownAsync();
+ }
+
+ await metricsServer.ShutdownAsync();
+ }
+
+ async Task RunBodyAsync(TestService.TestServiceClient client)
+ {
+ Logger.Info("Starting stress test client thread.");
+ while (!finishedTokenSource.Token.IsCancellationRequested)
+ {
+ var testCase = testCaseGenerator.GetNext();
+
+ var stopwatch = Stopwatch.StartNew();
+
+ await RunTestCaseAsync(client, testCase);
+
+ stopwatch.Stop();
+ histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
+ }
+ Logger.Info("Stress test client thread finished.");
+ }
+
+ async Task RunTestCaseAsync(TestService.TestServiceClient client, string testCase)
+ {
+ switch (testCase)
+ {
+ case "empty_unary":
+ InteropClient.RunEmptyUnary(client);
+ break;
+ case "large_unary":
+ InteropClient.RunLargeUnary(client);
+ break;
+ case "client_streaming":
+ await InteropClient.RunClientStreamingAsync(client);
+ break;
+ case "server_streaming":
+ await InteropClient.RunServerStreamingAsync(client);
+ break;
+ case "ping_pong":
+ await InteropClient.RunPingPongAsync(client);
+ break;
+ case "empty_stream":
+ await InteropClient.RunEmptyStreamAsync(client);
+ break;
+ case "cancel_after_begin":
+ await InteropClient.RunCancelAfterBeginAsync(client);
+ break;
+ case "cancel_after_first_response":
+ await InteropClient.RunCancelAfterFirstResponseAsync(client);
+ break;
+ case "timeout_on_sleeping_server":
+ await InteropClient.RunTimeoutOnSleepingServerAsync(client);
+ break;
+ case "custom_metadata":
+ await InteropClient.RunCustomMetadataAsync(client);
+ break;
+ case "status_code_and_message":
+ await InteropClient.RunStatusCodeAndMessageAsync(client);
+ break;
+ default:
+ throw new ArgumentException("Unsupported test case " + testCase);
+ }
+ }
+
+ static Dictionary<string, int> ParseWeightedTestCases(string weightedTestCases)
+ {
+ var result = new Dictionary<string, int>();
+ foreach (var weightedTestCase in weightedTestCases.Split(','))
+ {
+ var parts = weightedTestCase.Split(new char[] {':'}, 2);
+ GrpcPreconditions.CheckArgument(parts.Length == 2, "Malformed test_cases option.");
+ result.Add(parts[0], int.Parse(parts[1]));
+ }
+ return result;
+ }
+
+ class WeightedRandomGenerator
+ {
+ readonly Random random = new Random();
+ readonly List<Tuple<int, string>> cumulativeSums;
+ readonly int weightSum;
+
+ public WeightedRandomGenerator(Dictionary<string, int> weightedItems)
+ {
+ cumulativeSums = new List<Tuple<int, string>>();
+ weightSum = 0;
+ foreach (var entry in weightedItems)
+ {
+ weightSum += entry.Value;
+ cumulativeSums.Add(Tuple.Create(weightSum, entry.Key));
+ }
+ }
+
+ public string GetNext()
+ {
+ int rand = random.Next(weightSum);
+ foreach (var entry in cumulativeSums)
+ {
+ if (rand < entry.Item1)
+ {
+ return entry.Item2;
+ }
+ }
+ throw new InvalidOperationException("GetNext() failed.");
+ }
+ }
+
+ class MetricsServiceImpl : MetricsService.MetricsServiceBase
+ {
+ const string GaugeName = "csharp_overall_qps";
+
+ readonly Histogram histogram;
+ readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
+
+ public MetricsServiceImpl(Histogram histogram)
+ {
+ this.histogram = histogram;
+ }
+
+ public override Task<GaugeResponse> GetGauge(GaugeRequest request, ServerCallContext context)
+ {
+ if (request.Name == GaugeName)
+ {
+ long qps = GetQpsAndReset();
+
+ return Task.FromResult(new GaugeResponse
+ {
+ Name = GaugeName,
+ LongValue = qps
+ });
+ }
+ throw new RpcException(new Status(StatusCode.InvalidArgument, "Gauge does not exist"));
+ }
+
+ public override async Task GetAllGauges(EmptyMessage request, IServerStreamWriter<GaugeResponse> responseStream, ServerCallContext context)
+ {
+ long qps = GetQpsAndReset();
+
+ var response = new GaugeResponse
+ {
+ Name = GaugeName,
+ LongValue = qps
+ };
+ await responseStream.WriteAsync(response);
+ }
+
+ long GetQpsAndReset()
+ {
+ var snapshot = histogram.GetSnapshot(true);
+ var elapsedSnapshot = wallClockStopwatch.GetElapsedSnapshot(true);
+
+ return (long) (snapshot.Count / elapsedSnapshot.TotalSeconds);
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Test.cs b/src/csharp/Grpc.IntegrationTesting/Test.cs
index 91e0a1e04c..9258dc185d 100644
--- a/src/csharp/Grpc.IntegrationTesting/Test.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Test.cs
@@ -40,13 +40,13 @@ namespace Grpc.Testing {
"bWluZ091dHB1dENhbGxSZXF1ZXN0GikuZ3JwYy50ZXN0aW5nLlN0cmVhbWlu",
"Z091dHB1dENhbGxSZXNwb25zZSgBMAEyVQoUVW5pbXBsZW1lbnRlZFNlcnZp",
"Y2USPQoRVW5pbXBsZW1lbnRlZENhbGwSEy5ncnBjLnRlc3RpbmcuRW1wdHka",
- "Ey5ncnBjLnRlc3RpbmcuRW1wdHkyfwoQUmVjb25uZWN0U2VydmljZRIxCgVT",
- "dGFydBITLmdycGMudGVzdGluZy5FbXB0eRoTLmdycGMudGVzdGluZy5FbXB0",
- "eRI4CgRTdG9wEhMuZ3JwYy50ZXN0aW5nLkVtcHR5GhsuZ3JwYy50ZXN0aW5n",
- "LlJlY29ubmVjdEluZm9iBnByb3RvMw=="));
+ "Ey5ncnBjLnRlc3RpbmcuRW1wdHkyiQEKEFJlY29ubmVjdFNlcnZpY2USOwoF",
+ "U3RhcnQSHS5ncnBjLnRlc3RpbmcuUmVjb25uZWN0UGFyYW1zGhMuZ3JwYy50",
+ "ZXN0aW5nLkVtcHR5EjgKBFN0b3ASEy5ncnBjLnRlc3RpbmcuRW1wdHkaGy5n",
+ "cnBjLnRlc3RpbmcuUmVjb25uZWN0SW5mb2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Grpc.Testing.EmptyReflection.Descriptor, global::Grpc.Testing.MessagesReflection.Descriptor, },
- new pbr::GeneratedCodeInfo(null, null));
+ new pbr::GeneratedClrTypeInfo(null, null));
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
index ce108d808b..774563d752 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
@@ -35,6 +35,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Grpc.Core;
@@ -50,9 +51,29 @@ namespace Grpc.IntegrationTesting
{
public const string DefaultHostOverride = "foo.test.google.fr";
- public const string ClientCertAuthorityPath = "data/ca.pem";
- public const string ServerCertChainPath = "data/server1.pem";
- public const string ServerPrivateKeyPath = "data/server1.key";
+ public static string ClientCertAuthorityPath
+ {
+ get
+ {
+ return GetPath("data/ca.pem");
+ }
+ }
+
+ public static string ServerCertChainPath
+ {
+ get
+ {
+ return GetPath("data/server1.pem");
+ }
+ }
+
+ public static string ServerPrivateKeyPath
+ {
+ get
+ {
+ return GetPath("data/server1.key");
+ }
+ }
public static SslCredentials CreateSslCredentials()
{
@@ -66,5 +87,11 @@ namespace Grpc.IntegrationTesting
File.ReadAllText(ServerPrivateKeyPath));
return new SslServerCredentials(new[] { keyCertPair });
}
+
+ private static string GetPath(string relativePath)
+ {
+ var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ return Path.Combine(assemblyDir, relativePath);
+ }
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index 2c469080d9..cf43a77118 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -1,5 +1,38 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: src/proto/grpc/testing/test.proto
+// Original file comments:
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+//
#region Designer generated code
using System;
@@ -8,6 +41,10 @@ using System.Threading.Tasks;
using Grpc.Core;
namespace Grpc.Testing {
+ /// <summary>
+ /// A simple service to test the various types of RPCs and experiment with
+ /// performance with various types of payload.
+ /// </summary>
public static class TestService
{
static readonly string __ServiceName = "grpc.testing.TestService";
@@ -62,134 +99,355 @@ namespace Grpc.Testing {
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[0]; }
}
- // client interface
+ /// <summary>Client for TestService</summary>
+ [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface ITestServiceClient
{
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options);
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options);
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options);
+ /// <summary>
+ /// 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.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// 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.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options);
+ /// <summary>
+ /// 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.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// 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.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of TestService</summary>
+ [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface ITestService
{
- Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context);
- Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
- Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
- Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context);
- Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
- Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
+ global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context);
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
+ global::System.Threading.Tasks.Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
+ global::System.Threading.Tasks.Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
+ global::System.Threading.Tasks.Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context);
+ /// <summary>
+ /// 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.
+ /// </summary>
+ global::System.Threading.Tasks.Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
+ /// <summary>
+ /// 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.
+ /// </summary>
+ global::System.Threading.Tasks.Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
}
- // client stub
- public class TestServiceClient : ClientBase, ITestServiceClient
+ /// <summary>Base class for server-side implementations of TestService</summary>
+ public abstract class TestServiceBase
+ {
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// <summary>Client for TestService</summary>
+ #pragma warning disable 0618
+ public class TestServiceClient : ClientBase<TestServiceClient>, ITestServiceClient
+ #pragma warning restore 0618
{
public TestServiceClient(Channel channel) : base(channel)
{
}
- public global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public TestServiceClient(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ protected TestServiceClient() : base()
{
- var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.BlockingUnaryCall(call, request);
}
- public global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options)
+ ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ protected TestServiceClient(ClientBaseConfiguration configuration) : base(configuration)
{
- var call = CreateCall(__Method_EmptyCall, options);
- return Calls.BlockingUnaryCall(call, request);
}
- public AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
+ public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncUnaryCall(call, request);
+ return EmptyCall(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
+ public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options)
{
- var call = CreateCall(__Method_EmptyCall, options);
- return Calls.AsyncUnaryCall(call, request);
+ return CallInvoker.BlockingUnaryCall(__Method_EmptyCall, null, options, request);
}
- public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.BlockingUnaryCall(call, request);
+ return EmptyCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
- public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
- var call = CreateCall(__Method_UnaryCall, options);
- return Calls.BlockingUnaryCall(call, request);
+ return CallInvoker.AsyncUnaryCall(__Method_EmptyCall, null, options, request);
}
- public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
+ public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncUnaryCall(call, request);
+ return UnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
+ public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
- var call = CreateCall(__Method_UnaryCall, options);
- return Calls.AsyncUnaryCall(call, request);
+ return CallInvoker.BlockingUnaryCall(__Method_UnaryCall, null, options, request);
}
- public AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_StreamingOutputCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncServerStreamingCall(call, request);
+ return UnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options)
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
- var call = CreateCall(__Method_StreamingOutputCall, options);
- return Calls.AsyncServerStreamingCall(call, request);
+ return CallInvoker.AsyncUnaryCall(__Method_UnaryCall, null, options, request);
}
- public AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
+ public virtual AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_StreamingInputCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncClientStreamingCall(call);
+ return StreamingOutputCall(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options)
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
+ public virtual AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options)
{
- var call = CreateCall(__Method_StreamingInputCall, options);
- return Calls.AsyncClientStreamingCall(call);
+ return CallInvoker.AsyncServerStreamingCall(__Method_StreamingOutputCall, null, options, request);
}
- public AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
+ public virtual AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_FullDuplexCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncDuplexStreamingCall(call);
+ return StreamingInputCall(new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options)
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
+ public virtual AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options)
{
- var call = CreateCall(__Method_FullDuplexCall, options);
- return Calls.AsyncDuplexStreamingCall(call);
+ return CallInvoker.AsyncClientStreamingCall(__Method_StreamingInputCall, null, options);
}
- public AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_HalfDuplexCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncDuplexStreamingCall(call);
+ return FullDuplexCall(new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options)
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options)
{
- var call = CreateCall(__Method_HalfDuplexCall, options);
- return Calls.AsyncDuplexStreamingCall(call);
+ return CallInvoker.AsyncDuplexStreamingCall(__Method_FullDuplexCall, null, options);
}
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return HalfDuplexCall(new CallOptions(headers, deadline, cancellationToken));
+ }
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options)
+ {
+ return CallInvoker.AsyncDuplexStreamingCall(__Method_HalfDuplexCall, null, options);
+ }
+ protected override TestServiceClient NewInstance(ClientBaseConfiguration configuration)
+ {
+ return new TestServiceClient(configuration);
+ }
+ }
+
+ /// <summary>Creates a new client for TestService</summary>
+ public static TestServiceClient NewClient(Channel channel)
+ {
+ return new TestServiceClient(channel);
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
public static ServerServiceDefinition BindService(ITestService serviceImpl)
+ #pragma warning restore 0618
{
return ServerServiceDefinition.CreateBuilder(__ServiceName)
.AddMethod(__Method_EmptyCall, serviceImpl.EmptyCall)
@@ -200,13 +458,25 @@ namespace Grpc.Testing {
.AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall).Build();
}
- // creates a new client
- public static TestServiceClient NewClient(Channel channel)
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
+ public static ServerServiceDefinition BindService(TestServiceBase serviceImpl)
+ #pragma warning restore 0618
{
- return new TestServiceClient(channel);
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_EmptyCall, serviceImpl.EmptyCall)
+ .AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
+ .AddMethod(__Method_StreamingOutputCall, serviceImpl.StreamingOutputCall)
+ .AddMethod(__Method_StreamingInputCall, serviceImpl.StreamingInputCall)
+ .AddMethod(__Method_FullDuplexCall, serviceImpl.FullDuplexCall)
+ .AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall).Build();
}
}
+ /// <summary>
+ /// A simple service NOT implemented at servers so clients can test for
+ /// that case.
+ /// </summary>
public static class UnimplementedService
{
static readonly string __ServiceName = "grpc.testing.UnimplementedService";
@@ -220,81 +490,152 @@ namespace Grpc.Testing {
__Marshaller_Empty,
__Marshaller_Empty);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[1]; }
}
- // client interface
+ /// <summary>Client for UnimplementedService</summary>
+ [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IUnimplementedServiceClient
{
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options);
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of UnimplementedService</summary>
+ [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IUnimplementedService
{
- Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context);
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
+ global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context);
}
- // client stub
- public class UnimplementedServiceClient : ClientBase, IUnimplementedServiceClient
+ /// <summary>Base class for server-side implementations of UnimplementedService</summary>
+ public abstract class UnimplementedServiceBase
+ {
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// <summary>Client for UnimplementedService</summary>
+ #pragma warning disable 0618
+ public class UnimplementedServiceClient : ClientBase<UnimplementedServiceClient>, IUnimplementedServiceClient
+ #pragma warning restore 0618
{
public UnimplementedServiceClient(Channel channel) : base(channel)
{
}
- public global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public UnimplementedServiceClient(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ protected UnimplementedServiceClient() : base()
+ {
+ }
+ ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ protected UnimplementedServiceClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
+ public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return UnimplementedCall(request, new CallOptions(headers, deadline, cancellationToken));
+ }
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
+ public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options)
{
- var call = CreateCall(__Method_UnimplementedCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.BlockingUnaryCall(call, request);
+ return CallInvoker.BlockingUnaryCall(__Method_UnimplementedCall, null, options, request);
}
- public global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options)
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_UnimplementedCall, options);
- return Calls.BlockingUnaryCall(call, request);
+ return UnimplementedCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
+ public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
- var call = CreateCall(__Method_UnimplementedCall, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncUnaryCall(call, request);
+ return CallInvoker.AsyncUnaryCall(__Method_UnimplementedCall, null, options, request);
}
- public AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
+ protected override UnimplementedServiceClient NewInstance(ClientBaseConfiguration configuration)
{
- var call = CreateCall(__Method_UnimplementedCall, options);
- return Calls.AsyncUnaryCall(call, request);
+ return new UnimplementedServiceClient(configuration);
}
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates a new client for UnimplementedService</summary>
+ public static UnimplementedServiceClient NewClient(Channel channel)
+ {
+ return new UnimplementedServiceClient(channel);
+ }
+
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
public static ServerServiceDefinition BindService(IUnimplementedService serviceImpl)
+ #pragma warning restore 0618
{
return ServerServiceDefinition.CreateBuilder(__ServiceName)
.AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
}
- // creates a new client
- public static UnimplementedServiceClient NewClient(Channel channel)
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
+ public static ServerServiceDefinition BindService(UnimplementedServiceBase serviceImpl)
+ #pragma warning restore 0618
{
- return new UnimplementedServiceClient(channel);
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
}
}
+ /// <summary>
+ /// A service used to control reconnect server.
+ /// </summary>
public static class ReconnectService
{
static readonly string __ServiceName = "grpc.testing.ReconnectService";
+ static readonly Marshaller<global::Grpc.Testing.ReconnectParams> __Marshaller_ReconnectParams = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectParams.Parser.ParseFrom);
static readonly Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
static readonly Marshaller<global::Grpc.Testing.ReconnectInfo> __Marshaller_ReconnectInfo = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectInfo.Parser.ParseFrom);
- static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_Start = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
+ static readonly Method<global::Grpc.Testing.ReconnectParams, global::Grpc.Testing.Empty> __Method_Start = new Method<global::Grpc.Testing.ReconnectParams, global::Grpc.Testing.Empty>(
MethodType.Unary,
__ServiceName,
"Start",
- __Marshaller_Empty,
+ __Marshaller_ReconnectParams,
__Marshaller_Empty);
static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo> __Method_Stop = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo>(
@@ -304,92 +645,131 @@ namespace Grpc.Testing {
__Marshaller_Empty,
__Marshaller_ReconnectInfo);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[2]; }
}
- // client interface
+ /// <summary>Client for ReconnectService</summary>
+ [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IReconnectServiceClient
{
- global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, CallOptions options);
- AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, CallOptions options);
+ global::Grpc.Testing.Empty Start(global::Grpc.Testing.ReconnectParams request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Testing.Empty Start(global::Grpc.Testing.ReconnectParams request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.ReconnectParams request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.ReconnectParams request, CallOptions options);
global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options);
AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of ReconnectService</summary>
+ [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IReconnectService
{
- Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.Empty request, ServerCallContext context);
- Task<global::Grpc.Testing.ReconnectInfo> Stop(global::Grpc.Testing.Empty request, ServerCallContext context);
+ global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.ReconnectParams request, ServerCallContext context);
+ global::System.Threading.Tasks.Task<global::Grpc.Testing.ReconnectInfo> Stop(global::Grpc.Testing.Empty request, ServerCallContext context);
+ }
+
+ /// <summary>Base class for server-side implementations of ReconnectService</summary>
+ public abstract class ReconnectServiceBase
+ {
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.ReconnectParams request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.ReconnectInfo> Stop(global::Grpc.Testing.Empty request, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
}
- // client stub
- public class ReconnectServiceClient : ClientBase, IReconnectServiceClient
+ /// <summary>Client for ReconnectService</summary>
+ #pragma warning disable 0618
+ public class ReconnectServiceClient : ClientBase<ReconnectServiceClient>, IReconnectServiceClient
+ #pragma warning restore 0618
{
public ReconnectServiceClient(Channel channel) : base(channel)
{
}
- public global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public ReconnectServiceClient(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ protected ReconnectServiceClient() : base()
+ {
+ }
+ ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ protected ReconnectServiceClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ public virtual global::Grpc.Testing.Empty Start(global::Grpc.Testing.ReconnectParams request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return Start(request, new CallOptions(headers, deadline, cancellationToken));
+ }
+ public virtual global::Grpc.Testing.Empty Start(global::Grpc.Testing.ReconnectParams request, CallOptions options)
{
- var call = CreateCall(__Method_Start, new CallOptions(headers, deadline, cancellationToken));
- return Calls.BlockingUnaryCall(call, request);
+ return CallInvoker.BlockingUnaryCall(__Method_Start, null, options, request);
}
- public global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, CallOptions options)
+ public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.ReconnectParams request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_Start, options);
- return Calls.BlockingUnaryCall(call, request);
+ return StartAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.ReconnectParams request, CallOptions options)
{
- var call = CreateCall(__Method_Start, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncUnaryCall(call, request);
+ return CallInvoker.AsyncUnaryCall(__Method_Start, null, options, request);
}
- public AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, CallOptions options)
+ public virtual global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_Start, options);
- return Calls.AsyncUnaryCall(call, request);
+ return Stop(request, new CallOptions(headers, deadline, cancellationToken));
}
- public global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public virtual global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options)
{
- var call = CreateCall(__Method_Stop, new CallOptions(headers, deadline, cancellationToken));
- return Calls.BlockingUnaryCall(call, request);
+ return CallInvoker.BlockingUnaryCall(__Method_Stop, null, options, request);
}
- public global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options)
+ public virtual AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__Method_Stop, options);
- return Calls.BlockingUnaryCall(call, request);
+ return StopAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
- public AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public virtual AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
- var call = CreateCall(__Method_Stop, new CallOptions(headers, deadline, cancellationToken));
- return Calls.AsyncUnaryCall(call, request);
+ return CallInvoker.AsyncUnaryCall(__Method_Stop, null, options, request);
}
- public AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options)
+ protected override ReconnectServiceClient NewInstance(ClientBaseConfiguration configuration)
{
- var call = CreateCall(__Method_Stop, options);
- return Calls.AsyncUnaryCall(call, request);
+ return new ReconnectServiceClient(configuration);
}
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates a new client for ReconnectService</summary>
+ public static ReconnectServiceClient NewClient(Channel channel)
+ {
+ return new ReconnectServiceClient(channel);
+ }
+
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
public static ServerServiceDefinition BindService(IReconnectService serviceImpl)
+ #pragma warning restore 0618
{
return ServerServiceDefinition.CreateBuilder(__ServiceName)
.AddMethod(__Method_Start, serviceImpl.Start)
.AddMethod(__Method_Stop, serviceImpl.Stop).Build();
}
- // creates a new client
- public static ReconnectServiceClient NewClient(Channel channel)
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ #pragma warning disable 0618
+ public static ServerServiceDefinition BindService(ReconnectServiceBase serviceImpl)
+ #pragma warning restore 0618
{
- return new ReconnectServiceClient(channel);
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_Start, serviceImpl.Start)
+ .AddMethod(__Method_Stop, serviceImpl.Stop).Build();
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs
deleted file mode 100644
index 9f14dad6c0..0000000000
--- a/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs
+++ /dev/null
@@ -1,204 +0,0 @@
-#region Copyright notice and license
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using Grpc.Core;
-
-namespace grpc.testing
-{
- /// <summary>
- /// TestService (this is handwritten version of code that will normally be generated).
- /// </summary>
- public class TestServiceGrpc
- {
- static readonly string ServiceName = "/grpc.testing.TestService";
-
- static readonly Marshaller<Empty> EmptyMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), Empty.ParseFrom);
- static readonly Marshaller<SimpleRequest> SimpleRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), SimpleRequest.ParseFrom);
- static readonly Marshaller<SimpleResponse> SimpleResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), SimpleResponse.ParseFrom);
- static readonly Marshaller<StreamingOutputCallRequest> StreamingOutputCallRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingOutputCallRequest.ParseFrom);
- static readonly Marshaller<StreamingOutputCallResponse> StreamingOutputCallResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingOutputCallResponse.ParseFrom);
- static readonly Marshaller<StreamingInputCallRequest> StreamingInputCallRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingInputCallRequest.ParseFrom);
- static readonly Marshaller<StreamingInputCallResponse> StreamingInputCallResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingInputCallResponse.ParseFrom);
-
- static readonly Method<Empty, Empty> EmptyCallMethod = new Method<Empty, Empty>(
- MethodType.Unary,
- "EmptyCall",
- EmptyMarshaller,
- EmptyMarshaller);
-
- static readonly Method<SimpleRequest, SimpleResponse> UnaryCallMethod = new Method<SimpleRequest, SimpleResponse>(
- MethodType.Unary,
- "UnaryCall",
- SimpleRequestMarshaller,
- SimpleResponseMarshaller);
-
- static readonly Method<StreamingOutputCallRequest, StreamingOutputCallResponse> StreamingOutputCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>(
- MethodType.ServerStreaming,
- "StreamingOutputCall",
- StreamingOutputCallRequestMarshaller,
- StreamingOutputCallResponseMarshaller);
-
- static readonly Method<StreamingInputCallRequest, StreamingInputCallResponse> StreamingInputCallMethod = new Method<StreamingInputCallRequest, StreamingInputCallResponse>(
- MethodType.ClientStreaming,
- "StreamingInputCall",
- StreamingInputCallRequestMarshaller,
- StreamingInputCallResponseMarshaller);
-
- static readonly Method<StreamingOutputCallRequest, StreamingOutputCallResponse> FullDuplexCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>(
- MethodType.DuplexStreaming,
- "FullDuplexCall",
- StreamingOutputCallRequestMarshaller,
- StreamingOutputCallResponseMarshaller);
-
- static readonly Method<StreamingOutputCallRequest, StreamingOutputCallResponse> HalfDuplexCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>(
- MethodType.DuplexStreaming,
- "HalfDuplexCall",
- StreamingOutputCallRequestMarshaller,
- StreamingOutputCallResponseMarshaller);
-
- public interface ITestServiceClient
- {
- Empty EmptyCall(Empty request, CancellationToken token = default(CancellationToken));
-
- Task<Empty> EmptyCallAsync(Empty request, CancellationToken token = default(CancellationToken));
-
- SimpleResponse UnaryCall(SimpleRequest request, CancellationToken token = default(CancellationToken));
-
- Task<SimpleResponse> UnaryCallAsync(SimpleRequest request, CancellationToken token = default(CancellationToken));
-
- AsyncServerStreamingCall<StreamingOutputCallResponse> StreamingOutputCall(StreamingOutputCallRequest request, CancellationToken token = default(CancellationToken));
-
- AsyncClientStreamingCall<StreamingInputCallRequest, StreamingInputCallResponse> StreamingInputCall(CancellationToken token = default(CancellationToken));
-
- AsyncDuplexStreamingCall<StreamingOutputCallRequest, StreamingOutputCallResponse> FullDuplexCall(CancellationToken token = default(CancellationToken));
-
- AsyncDuplexStreamingCall<StreamingOutputCallRequest, StreamingOutputCallResponse> HalfDuplexCall(CancellationToken token = default(CancellationToken));
- }
-
- public class TestServiceClientStub : AbstractStub<TestServiceClientStub, StubConfiguration>, ITestServiceClient
- {
- public TestServiceClientStub(Channel channel) : base(channel, StubConfiguration.Default)
- {
- }
-
- public TestServiceClientStub(Channel channel, StubConfiguration config) : base(channel, config)
- {
- }
-
- public Empty EmptyCall(Empty request, CancellationToken token = default(CancellationToken))
- {
- var call = CreateCall(ServiceName, EmptyCallMethod);
- return Calls.BlockingUnaryCall(call, request, token);
- }
-
- public Task<Empty> EmptyCallAsync(Empty request, CancellationToken token = default(CancellationToken))
- {
- var call = CreateCall(ServiceName, EmptyCallMethod);
- return Calls.AsyncUnaryCall(call, request, token);
- }
-
- public SimpleResponse UnaryCall(SimpleRequest request, CancellationToken token = default(CancellationToken))
- {
- var call = CreateCall(ServiceName, UnaryCallMethod);
- return Calls.BlockingUnaryCall(call, request, token);
- }
-
- public Task<SimpleResponse> UnaryCallAsync(SimpleRequest request, CancellationToken token = default(CancellationToken))
- {
- var call = CreateCall(ServiceName, UnaryCallMethod);
- return Calls.AsyncUnaryCall(call, request, token);
- }
-
- public AsyncServerStreamingCall<StreamingOutputCallResponse> StreamingOutputCall(StreamingOutputCallRequest request, CancellationToken token = default(CancellationToken))
- {
- var call = CreateCall(ServiceName, StreamingOutputCallMethod);
- return Calls.AsyncServerStreamingCall(call, request, token);
- }
-
- public AsyncClientStreamingCall<StreamingInputCallRequest, StreamingInputCallResponse> StreamingInputCall(CancellationToken token = default(CancellationToken))
- {
- var call = CreateCall(ServiceName, StreamingInputCallMethod);
- return Calls.AsyncClientStreamingCall(call, token);
- }
-
- public AsyncDuplexStreamingCall<StreamingOutputCallRequest, StreamingOutputCallResponse> FullDuplexCall(CancellationToken token = default(CancellationToken))
- {
- var call = CreateCall(ServiceName, FullDuplexCallMethod);
- return Calls.AsyncDuplexStreamingCall(call, token);
- }
-
- public AsyncDuplexStreamingCall<StreamingOutputCallRequest, StreamingOutputCallResponse> HalfDuplexCall(CancellationToken token = default(CancellationToken))
- {
- var call = CreateCall(ServiceName, HalfDuplexCallMethod);
- return Calls.AsyncDuplexStreamingCall(call, token);
- }
- }
-
- // server-side interface
- public interface ITestService
- {
- Task<Empty> EmptyCall(ServerCallContext context, Empty request);
-
- Task<SimpleResponse> UnaryCall(ServerCallContext context, SimpleRequest request);
-
- Task StreamingOutputCall(ServerCallContext context, StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream);
-
- Task<StreamingInputCallResponse> StreamingInputCall(ServerCallContext context, IAsyncStreamReader<StreamingInputCallRequest> requestStream);
-
- Task FullDuplexCall(ServerCallContext context, IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream);
-
- Task HalfDuplexCall(ServerCallContext context, IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream);
- }
-
- public static ServerServiceDefinition BindService(ITestService serviceImpl)
- {
- return ServerServiceDefinition.CreateBuilder(ServiceName)
- .AddMethod(EmptyCallMethod, serviceImpl.EmptyCall)
- .AddMethod(UnaryCallMethod, serviceImpl.UnaryCall)
- .AddMethod(StreamingOutputCallMethod, serviceImpl.StreamingOutputCall)
- .AddMethod(StreamingInputCallMethod, serviceImpl.StreamingInputCall)
- .AddMethod(FullDuplexCallMethod, serviceImpl.FullDuplexCall)
- .AddMethod(HalfDuplexCallMethod, serviceImpl.HalfDuplexCall)
- .Build();
- }
-
- public static ITestServiceClient NewStub(Channel channel)
- {
- return new TestServiceClientStub(channel);
- }
- }
-}
diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
index 5a1b4cf319..354318e80e 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -45,14 +45,14 @@ namespace Grpc.Testing
/// <summary>
/// Implementation of TestService server
/// </summary>
- public class TestServiceImpl : TestService.ITestService
+ public class TestServiceImpl : TestService.TestServiceBase
{
- public Task<Empty> EmptyCall(Empty request, ServerCallContext context)
+ public override Task<Empty> EmptyCall(Empty request, ServerCallContext context)
{
return Task.FromResult(new Empty());
}
- public async Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
+ public override async Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
{
await EnsureEchoMetadataAsync(context);
EnsureEchoStatus(request.ResponseStatus, context);
@@ -61,7 +61,7 @@ namespace Grpc.Testing
return response;
}
- public async Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
+ public override async Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
await EnsureEchoMetadataAsync(context);
EnsureEchoStatus(request.ResponseStatus, context);
@@ -73,7 +73,7 @@ namespace Grpc.Testing
}
}
- public async Task<StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<StreamingInputCallRequest> requestStream, ServerCallContext context)
+ public override async Task<StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<StreamingInputCallRequest> requestStream, ServerCallContext context)
{
await EnsureEchoMetadataAsync(context);
@@ -85,7 +85,7 @@ namespace Grpc.Testing
return new StreamingInputCallResponse { AggregatedPayloadSize = sum };
}
- public async Task FullDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
+ public override async Task FullDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
await EnsureEchoMetadataAsync(context);
@@ -100,7 +100,7 @@ namespace Grpc.Testing
});
}
- public async Task HalfDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
+ public override async Task HalfDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
throw new NotImplementedException();
}
diff --git a/src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs
index cab299a137..c9eca73452 100644
--- a/src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs
+++ b/src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015-2016, Google Inc.
+// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@ namespace Grpc.Testing
/// <summary>
/// Implementation of WorkerService server
/// </summary>
- public class WorkerServiceImpl : WorkerService.IWorkerService
+ public class WorkerServiceImpl : WorkerService.WorkerServiceBase
{
readonly Action stopRequestHandler;
@@ -54,7 +54,7 @@ namespace Grpc.Testing
this.stopRequestHandler = GrpcPreconditions.CheckNotNull(stopRequestHandler);
}
- public async Task RunServer(IAsyncStreamReader<ServerArgs> requestStream, IServerStreamWriter<ServerStatus> responseStream, ServerCallContext context)
+ public override async Task RunServer(IAsyncStreamReader<ServerArgs> requestStream, IServerStreamWriter<ServerStatus> responseStream, ServerCallContext context)
{
GrpcPreconditions.CheckState(await requestStream.MoveNext());
var serverConfig = requestStream.Current.Setup;
@@ -64,7 +64,7 @@ namespace Grpc.Testing
{
Stats = runner.GetStats(false),
Port = runner.BoundPort,
- Cores = 0, // TODO: set number of cores
+ Cores = Environment.ProcessorCount,
});
while (await requestStream.MoveNext())
@@ -78,7 +78,7 @@ namespace Grpc.Testing
await runner.StopAsync();
}
- public async Task RunClient(IAsyncStreamReader<ClientArgs> requestStream, IServerStreamWriter<ClientStatus> responseStream, ServerCallContext context)
+ public override async Task RunClient(IAsyncStreamReader<ClientArgs> requestStream, IServerStreamWriter<ClientStatus> responseStream, ServerCallContext context)
{
GrpcPreconditions.CheckState(await requestStream.MoveNext());
var clientConfig = requestStream.Current.Setup;
@@ -100,12 +100,12 @@ namespace Grpc.Testing
await runner.StopAsync();
}
- public Task<CoreResponse> CoreCount(CoreRequest request, ServerCallContext context)
+ public override Task<CoreResponse> CoreCount(CoreRequest request, ServerCallContext context)
{
return Task.FromResult(new CoreResponse { Cores = Environment.ProcessorCount });
}
- public Task<Void> QuitWorker(Void request, ServerCallContext context)
+ public override Task<Void> QuitWorker(Void request, ServerCallContext context)
{
stopRequestHandler();
return Task.FromResult(new Void());
diff --git a/src/csharp/Grpc.IntegrationTesting/app.config b/src/csharp/Grpc.IntegrationTesting/app.config
deleted file mode 100644
index 84d7534d65..0000000000
--- a/src/csharp/Grpc.IntegrationTesting/app.config
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
- <runtime>
- <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Google.Apis.Core" publicKeyToken="4b01fa6e34db77ab" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-1.9.2.38523" newVersion="1.9.2.38523" />
- </dependentAssembly>
- </assemblyBinding>
- </runtime>
-</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index 462dc9d604..3161c5b755 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -2,15 +2,12 @@
<packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
<package id="CommandLineParser" version="1.9.71" targetFramework="net45" />
- <package id="Google.Apis.Auth" version="1.10.0" targetFramework="net45" />
- <package id="Google.Apis.Core" version="1.10.0" targetFramework="net45" />
- <package id="Google.Protobuf" version="3.0.0-beta2" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.11.1" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.11.1" targetFramework="net45" />
+ <package id="Google.Protobuf" version="3.0.0-beta3" targetFramework="net45" />
<package id="Ix-Async" version="1.2.5" targetFramework="net45" />
- <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
- <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
- <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
- <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
<package id="Moq" version="4.2.1510.2205" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
- <package id="NUnit" version="2.6.4" targetFramework="net45" />
+ <package id="NUnit" version="3.2.0" targetFramework="net45" />
+ <package id="NUnitLite" version="3.2.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 8ff35e8c0d..9be36c0caa 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -34,6 +34,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "G
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.QpsWorker", "Grpc.IntegrationTesting.QpsWorker\Grpc.IntegrationTesting.QpsWorker.csproj", "{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.StressClient", "Grpc.IntegrationTesting.StressClient\Grpc.IntegrationTesting.StressClient.csproj", "{ADEBA147-80AE-4710-82E9-5B7F93690266}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -83,6 +85,12 @@ Global
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {ADEBA147-80AE-4710-82E9-5B7F93690266}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ADEBA147-80AE-4710-82E9-5B7F93690266}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ADEBA147-80AE-4710-82E9-5B7F93690266}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ADEBA147-80AE-4710-82E9-5B7F93690266}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ADEBA147-80AE-4710-82E9-5B7F93690266}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU
+ {ADEBA147-80AE-4710-82E9-5B7F93690266}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/src/csharp/README.md b/src/csharp/README.md
index b4fa945ac9..201c5ab0b5 100644
--- a/src/csharp/README.md
+++ b/src/csharp/README.md
@@ -55,16 +55,11 @@ If you are a user of gRPC C#, go to Usage section above.
**Windows**
-- The grpc_csharp_ext native library needs to be built so you can build the gRPC C# solution. You can
- either build the native solution in `vsprojects/grpc_csharp_ext.sln` from Visual Studio manually, or you can use
- a convenience batch script that builds everything for you.
+- The grpc_csharp_ext native library needs to be built so you can build the gRPC C# solution. Open the
+ solution `vsprojects/grpc_csharp_ext.sln` in Visual Studio and build it.
- ```
- > REM From src/csharp directory
- > buildall.bat
- ```
-
-- Open Grpc.sln using Visual Studio.
+- Open `src\csharp\Grpc.sln` (path is relative to gRPC repository root)
+ using Visual Studio
**Linux**
@@ -79,7 +74,7 @@ If you are a user of gRPC C#, go to Usage section above.
**Mac OS X**
- The grpc_csharp_ext native library needs to be built so you can build the gRPC C# solution.
-
+
```sh
# from the gRPC repository root
$ tools/run_tests/run_tests.py -c dbg -l csharp --build_only
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index 7c42a6d3fc..1cc63da970 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -1,8 +1,37 @@
+@rem Copyright 2016, Google Inc.
+@rem All rights reserved.
+@rem
+@rem Redistribution and use in source and binary forms, with or without
+@rem modification, are permitted provided that the following conditions are
+@rem met:
+@rem
+@rem * Redistributions of source code must retain the above copyright
+@rem notice, this list of conditions and the following disclaimer.
+@rem * Redistributions in binary form must reproduce the above
+@rem copyright notice, this list of conditions and the following disclaimer
+@rem in the documentation and/or other materials provided with the
+@rem distribution.
+@rem * Neither the name of Google Inc. nor the names of its
+@rem contributors may be used to endorse or promote products derived from
+@rem this software without specific prior written permission.
+@rem
+@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
@rem Builds gRPC NuGet packages
@rem Current package versions
-set VERSION=0.14.0-dev
-set PROTOBUF_VERSION=3.0.0-beta2
+set VERSION=0.15.0-dev
+set PROTOBUF_VERSION=3.0.0-beta3
@rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
set VERSION_WITH_BETA=%VERSION%-beta
@@ -12,12 +41,12 @@ set NUGET=C:\nuget\nuget.exe
@rem Collect the artifacts built by the previous build step if running on Jenkins
@rem TODO(jtattermusch): is there a better way to do this?
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* grpc.native.csharp\windows_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* grpc.native.csharp\windows_x64\
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* grpc.native.csharp\linux_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* grpc.native.csharp\linux_x64\
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* grpc.native.csharp\macosx_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* grpc.native.csharp\macosx_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x64\
@rem Collect protoc artifacts built by the previous build step
xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x86\
@@ -42,7 +71,6 @@ msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error
endlocal
-%NUGET% pack grpc.native.csharp\grpc.native.csharp.nuspec -Version %VERSION% || goto :error
%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error
%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
diff --git a/src/csharp/buildall.bat b/src/csharp/buildall.bat
index fcc8442656..0beb30c198 100644
--- a/src/csharp/buildall.bat
+++ b/src/csharp/buildall.bat
@@ -1,3 +1,32 @@
+@rem Copyright 2016, Google Inc.
+@rem All rights reserved.
+@rem
+@rem Redistribution and use in source and binary forms, with or without
+@rem modification, are permitted provided that the following conditions are
+@rem met:
+@rem
+@rem * Redistributions of source code must retain the above copyright
+@rem notice, this list of conditions and the following disclaimer.
+@rem * Redistributions in binary form must reproduce the above
+@rem copyright notice, this list of conditions and the following disclaimer
+@rem in the documentation and/or other materials provided with the
+@rem distribution.
+@rem * Neither the name of Google Inc. nor the names of its
+@rem contributors may be used to endorse or promote products derived from
+@rem this software without specific prior written permission.
+@rem
+@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
@rem Convenience script to build gRPC C# from command line
setlocal
@@ -8,6 +37,12 @@ cd /d %~dp0
@rem Set VS variables (uses Visual Studio 2013)
@call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
+@rem Fetch all dependencies
+nuget restore ..\..\vsprojects\grpc.sln || goto :error
+nuget restore ..\..\vsprojects\grpc_csharp_ext.sln || goto :error
+nuget restore ..\..\vsprojects\grpc_protoc_plugins.sln || goto :error
+nuget restore Grpc.sln || goto :error
+
@rem Build the C# native extension
msbuild ..\..\vsprojects\grpc_csharp_ext.sln /p:Configuration=Debug /p:PlatformToolset=v120 || goto :error
msbuild ..\..\vsprojects\grpc_csharp_ext.sln /p:Configuration=Release /p:PlatformToolset=v120 || goto :error
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 1df74a0993..4beef9ded8 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
*
*/
-#include "src/core/support/string.h"
+#include "src/core/lib/support/string.h"
#include <grpc/byte_buffer_reader.h>
#include <grpc/support/port_platform.h>
@@ -715,10 +715,11 @@ grpcsharp_call_send_close_from_client(grpc_call *call,
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
grpc_call *call, grpcsharp_batch_context *ctx, grpc_status_code status_code,
const char *status_details, grpc_metadata_array *trailing_metadata,
- int32_t send_empty_initial_metadata) {
+ int32_t send_empty_initial_metadata, const char* optional_send_buffer,
+ size_t optional_send_buffer_len, uint32_t write_flags) {
/* TODO: don't use magic number */
- grpc_op ops[2];
- size_t nops = send_empty_initial_metadata ? 2 : 1;
+ grpc_op ops[3];
+ size_t nops = 1;
ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
ops[0].data.send_status_from_server.status = status_code;
ops[0].data.send_status_from_server.status_details =
@@ -731,12 +732,23 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
ctx->send_status_from_server.trailing_metadata.metadata;
ops[0].flags = 0;
ops[0].reserved = NULL;
- ops[1].op = GRPC_OP_SEND_INITIAL_METADATA;
- ops[1].data.send_initial_metadata.count = 0;
- ops[1].data.send_initial_metadata.metadata = NULL;
- ops[1].flags = 0;
- ops[1].reserved = NULL;
-
+ if (optional_send_buffer) {
+ ops[nops].op = GRPC_OP_SEND_MESSAGE;
+ ctx->send_message = string_to_byte_buffer(optional_send_buffer,
+ optional_send_buffer_len);
+ ops[nops].data.send_message = ctx->send_message;
+ ops[nops].flags = write_flags;
+ ops[nops].reserved = NULL;
+ nops ++;
+ }
+ if (send_empty_initial_metadata) {
+ ops[nops].op = GRPC_OP_SEND_INITIAL_METADATA;
+ ops[nops].data.send_initial_metadata.count = 0;
+ ops[nops].data.send_initial_metadata.metadata = NULL;
+ ops[nops].flags = 0;
+ ops[nops].reserved = NULL;
+ nops++;
+ }
return grpc_call_start_batch(call, ops, nops, ctx, NULL);
}
@@ -794,11 +806,14 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_set_credentials(
/* Server */
GPR_EXPORT grpc_server *GPR_CALLTYPE
-grpcsharp_server_create(grpc_completion_queue *cq,
- const grpc_channel_args *args) {
- grpc_server *server = grpc_server_create(args, NULL);
+grpcsharp_server_create(const grpc_channel_args *args) {
+ return grpc_server_create(args, NULL);
+}
+
+GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_server_register_completion_queue(grpc_server *server,
+ grpc_completion_queue *cq) {
grpc_server_register_completion_queue(server, cq, NULL);
- return server;
}
GPR_EXPORT int32_t GPR_CALLTYPE
@@ -911,9 +926,12 @@ grpcsharp_ssl_server_credentials_create(
key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i];
}
}
- creds = grpc_ssl_server_credentials_create(pem_root_certs, key_cert_pairs,
- num_key_cert_pairs,
- force_client_auth, NULL);
+ creds = grpc_ssl_server_credentials_create_ex(
+ pem_root_certs, key_cert_pairs, num_key_cert_pairs,
+ force_client_auth
+ ? GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
+ : GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE,
+ NULL);
gpr_free(key_cert_pairs);
return creds;
}
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index 23e0540253..79488e02a5 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright 2015-2016, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -45,4 +45,4 @@ $PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_D
-I src/proto/grpc/health/v1 src/proto/grpc/health/v1/health.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \
- -I . src/proto/grpc/testing/{control,empty,messages,payloads,services,stats,test}.proto
+ -I . src/proto/grpc/testing/{control,empty,messages,metrics,payloads,services,stats,test}.proto
diff --git a/src/csharp/grpc.native.csharp/README.md b/src/csharp/grpc.native.csharp/README.md
deleted file mode 100644
index 77f1cb9b1f..0000000000
--- a/src/csharp/grpc.native.csharp/README.md
+++ /dev/null
@@ -1,22 +0,0 @@
-gRPC Native Nuget package
-=========================
-
-Prerequisites
--------------
-
-NuGet binary
-
-Building the package
---------------------
-
-To build the native package, you need precompiled versions
-of grpc_csharp_ext library artifacts for Windows, Linux and Mac.
-In the normal gRPC release process, these are built by a Jenkins
-job and they are copied to the expected location before building
-the native nuget package is attempted.
-
-See tools/run_tests/build_artifacts.py for more details how
-precompiled artifacts are built.
-
-When building the native NuGet package, ignore the "Assembly outside lib folder"
-warnings (the DLLs are not assemblies, they are native libraries).
diff --git a/src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec b/src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec
index 6a1795b709..cc688e2bc7 100644
--- a/src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec
+++ b/src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec
@@ -10,7 +10,7 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Native extension needed by gRPC C# library. This is not the package you are looking for, it is only meant to be used as a dependency.</description>
<releaseNotes>Release of gRPC C core $version$ libraries.</releaseNotes>
- <copyright>Copyright 2015-2016</copyright>
+ <copyright>Copyright 2015</copyright>
<title>gRPC C# Native Extension</title>
<summary>Native library required by gRPC C#</summary>
<tags>gRPC native</tags>
diff --git a/src/csharp/tests.json b/src/csharp/tests.json
index 4aa93668ad..f6af3408d5 100644
--- a/src/csharp/tests.json
+++ b/src/csharp/tests.json
@@ -1,11 +1,6 @@
{
- "assemblies": [
- "Grpc.Core.Tests",
- "Grpc.Examples.Tests",
- "Grpc.HealthCheck.Tests",
- "Grpc.IntegrationTesting"
- ],
- "tests": [
+ "Grpc.Core.Tests": [
+ "Grpc.Core.Internal.Tests.AsyncCallServerTest",
"Grpc.Core.Internal.Tests.AsyncCallTest",
"Grpc.Core.Internal.Tests.ChannelArgsSafeHandleTest",
"Grpc.Core.Internal.Tests.CompletionQueueEventTest",
@@ -21,6 +16,7 @@
"Grpc.Core.Tests.CompressionTest",
"Grpc.Core.Tests.ContextPropagationTest",
"Grpc.Core.Tests.GrpcEnvironmentTest",
+ "Grpc.Core.Tests.HalfcloseTest",
"Grpc.Core.Tests.MarshallingErrorsTest",
"Grpc.Core.Tests.MetadataTest",
"Grpc.Core.Tests.NUnitVersionTest",
@@ -31,11 +27,18 @@
"Grpc.Core.Tests.ServerTest",
"Grpc.Core.Tests.ShutdownTest",
"Grpc.Core.Tests.TimeoutsTest",
- "Grpc.Core.Tests.UserAgentStringTest",
- "Math.Tests.MathClientServerTest",
+ "Grpc.Core.Tests.UserAgentStringTest"
+ ],
+ "Grpc.Examples.Tests": [
+ "Math.Tests.MathClientServerTest"
+ ],
+ "Grpc.HealthCheck.Tests": [
"Grpc.HealthCheck.Tests.HealthClientServerTest",
- "Grpc.HealthCheck.Tests.HealthServiceImplTest",
- "Grpc.IntegrationTesting.HeaderInterceptorTest",
+ "Grpc.HealthCheck.Tests.HealthServiceImplTest"
+ ],
+ "Grpc.IntegrationTesting": [
+ "Grpc.IntegrationTesting.GeneratedClientTest",
+ "Grpc.IntegrationTesting.GeneratedServiceBaseTest",
"Grpc.IntegrationTesting.HistogramTest",
"Grpc.IntegrationTesting.InteropClientServerTest",
"Grpc.IntegrationTesting.MetadataCredentialsTest",