aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/csharp/Grpc.Core.Tests/CallOptionsTest.cs88
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/ClientServerTest.cs57
-rw-r--r--src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs32
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj1
-rw-r--r--src/csharp/Grpc.Core/CallOptions.cs1
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs14
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj1
-rw-r--r--src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs113
9 files changed, 286 insertions, 23 deletions
diff --git a/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs b/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
new file mode 100644
index 0000000000..a3a613be74
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
@@ -0,0 +1,88 @@
+#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 Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class CallOptionsTest
+ {
+ [Test]
+ public void WithMethods()
+ {
+ var options = new CallOptions();
+
+ var metadata = new Metadata();
+ Assert.AreSame(metadata, options.WithHeaders(metadata).Headers);
+
+ var deadline = DateTime.UtcNow;
+ Assert.AreEqual(deadline, options.WithDeadline(deadline).Deadline.Value);
+
+ var token = new CancellationTokenSource().Token;
+ Assert.AreEqual(token, options.WithCancellationToken(token).CancellationToken);
+
+ // Change original instance is unchanged.
+ Assert.IsNull(options.Headers);
+ Assert.IsNull(options.Deadline);
+ Assert.AreEqual(CancellationToken.None, options.CancellationToken);
+ Assert.IsNull(options.WriteOptions);
+ Assert.IsNull(options.PropagationToken);
+ Assert.IsNull(options.Credentials);
+ }
+
+ [Test]
+ public void Normalize()
+ {
+ Assert.AreSame(Metadata.Empty, new CallOptions().Normalize().Headers);
+ Assert.AreEqual(DateTime.MaxValue, new CallOptions().Normalize().Deadline.Value);
+
+ var deadline = DateTime.UtcNow;
+ var propagationToken1 = new ContextPropagationToken(CallSafeHandle.NullInstance, deadline, CancellationToken.None,
+ new ContextPropagationOptions(propagateDeadline: true, propagateCancellation: false));
+ Assert.AreEqual(deadline, new CallOptions(propagationToken: propagationToken1).Normalize().Deadline.Value);
+ Assert.Throws(typeof(ArgumentException), () => new CallOptions(deadline: deadline, propagationToken: propagationToken1).Normalize());
+
+ var token = new CancellationTokenSource().Token;
+ var propagationToken2 = new ContextPropagationToken(CallSafeHandle.NullInstance, deadline, token,
+ new ContextPropagationOptions(propagateDeadline: false, propagateCancellation: true));
+ Assert.AreEqual(token, new CallOptions(propagationToken: propagationToken2).Normalize().CancellationToken);
+ Assert.Throws(typeof(ArgumentException), () => new CallOptions(cancellationToken: token, propagationToken: propagationToken2).Normalize());
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
index 52be77c846..d2b5a436fd 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
@@ -38,7 +38,7 @@ using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
-namespace Grpc.Core.Internal.Tests
+namespace Grpc.Core.Tests
{
public class ChannelOptionsTest
{
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index b683751bc0..e324471120 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -32,6 +32,7 @@
#endregion
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
@@ -144,6 +145,48 @@ namespace Grpc.Core.Tests
var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
Assert.AreEqual("ABC", await call.ResponseAsync);
+
+ Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
+ Assert.IsNotNull(call.GetTrailers());
+ }
+
+ [Test]
+ public async Task ServerStreamingCall()
+ {
+ helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) =>
+ {
+ foreach (string response in request.Split(new []{' '}))
+ {
+ await responseStream.WriteAsync(response);
+ }
+ context.ResponseTrailers.Add("xyz", "");
+ });
+
+ var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "A B C");
+ CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, await call.ResponseStream.ToListAsync());
+
+ Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
+ Assert.IsNotNull("xyz", call.GetTrailers()[0].Key);
+ }
+
+ [Test]
+ public async Task DuplexStreamingCall()
+ {
+ helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
+ {
+ while (await requestStream.MoveNext())
+ {
+ await responseStream.WriteAsync(requestStream.Current);
+ }
+ context.ResponseTrailers.Add("xyz", "xyz-value");
+ });
+
+ var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall());
+ await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
+ CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, await call.ResponseStream.ToListAsync());
+
+ Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
+ Assert.IsNotNull("xyz-value", call.GetTrailers()[0].Value);
}
[Test]
@@ -219,7 +262,7 @@ namespace Grpc.Core.Tests
}
[Test]
- public void PeerInfoPresent()
+ public void ServerCallContext_PeerInfoPresent()
{
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{
@@ -231,6 +274,18 @@ namespace Grpc.Core.Tests
}
[Test]
+ public void ServerCallContext_HostAndMethodPresent()
+ {
+ helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
+ {
+ Assert.IsTrue(context.Host.Contains(Host));
+ Assert.AreEqual("/tests.Test/Unary", context.Method);
+ return "PASS";
+ });
+ Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
+ }
+
+ [Test]
public async Task Channel_WaitForStateChangedAsync()
{
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
diff --git a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
index 2db3f286f7..90c510ec61 100644
--- a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
@@ -69,11 +69,19 @@ namespace Grpc.Core.Tests
[Test]
public async Task PropagateCancellation()
{
+ var readyToCancelTcs = new TaskCompletionSource<object>();
+ var successTcs = new TaskCompletionSource<string>();
+
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{
- // check that we didn't obtain the default cancellation token.
- Assert.IsTrue(context.CancellationToken.CanBeCanceled);
- return "PASS";
+ readyToCancelTcs.SetResult(null); // child call running, ready to parent call
+
+ while (!context.CancellationToken.IsCancellationRequested)
+ {
+ await Task.Delay(10);
+ }
+ successTcs.SetResult("CHILD_CALL_CANCELLED");
+ return "";
});
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
@@ -82,13 +90,23 @@ namespace Grpc.Core.Tests
Assert.IsNotNull(propagationToken.ParentCall);
var callOptions = new CallOptions(propagationToken: propagationToken);
- return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz");
+ try
+ {
+ await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz");
+ }
+ catch(RpcException)
+ {
+ // Child call will get cancelled, eat the exception.
+ }
+ return "";
});
var cts = new CancellationTokenSource();
- var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
- await call.RequestStream.CompleteAsync();
- Assert.AreEqual("PASS", await call);
+ var parentCall = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
+ await readyToCancelTcs.Task;
+ cts.Cancel();
+ Assert.Throws(typeof(RpcException), async () => await parentCall);
+ Assert.AreEqual("CHILD_CALL_CANCELLED", await successTcs.Task);
}
[Test]
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 70b83f7fb1..a171855ee0 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -64,6 +64,7 @@
<Link>Version.cs</Link>
</Compile>
<Compile Include="CallCredentialsTest.cs" />
+ <Compile Include="CallOptionsTest.cs" />
<Compile Include="UserAgentStringTest.cs" />
<Compile Include="FakeCredentials.cs" />
<Compile Include="MarshallingErrorsTest.cs" />
diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs
index c0f94c63c2..1fda80cb90 100644
--- a/src/csharp/Grpc.Core/CallOptions.cs
+++ b/src/csharp/Grpc.Core/CallOptions.cs
@@ -184,6 +184,7 @@ namespace Grpc.Core
{
Preconditions.CheckArgument(!newOptions.cancellationToken.CanBeCanceled,
"Cannot propagate cancellation token from parent call. The cancellation token has already been set to a non-default value.");
+ newOptions.cancellationToken = propagationToken.ParentCancellationToken;
}
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 953f61aa1e..92f8d77e85 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -238,20 +238,6 @@ namespace Grpc.Core.Internal
}
}
- protected Exception TrySerialize(TWrite msg, out byte[] payload)
- {
- try
- {
- payload = serializer(msg);
- return null;
- }
- catch (Exception e)
- {
- payload = null;
- return e;
- }
- }
-
protected Exception TryDeserialize(byte[] payload, out TRead msg)
{
using (Profilers.ForCurrentThread().NewScope("AsyncCallBase.TryDeserialize"))
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 012de45524..c48ac71630 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -83,6 +83,7 @@
<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" />
diff --git a/src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs b/src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs
new file mode 100644
index 0000000000..1d758b7540
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs
@@ -0,0 +1,113 @@
+#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.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Testing;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+ public class HeaderInterceptorTest
+ {
+ const string Host = "localhost";
+ Server server;
+ Channel channel;
+ TestService.TestServiceClient client;
+
+ [TestFixtureSetUp]
+ public void Init()
+ {
+ server = new Server
+ {
+ Services = { TestService.BindService(new TestServiceImpl()) },
+ Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
+ };
+ server.Start();
+
+ channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
+ client = TestService.NewClient(channel);
+ }
+
+ [TestFixtureTearDown]
+ public void Cleanup()
+ {
+ channel.ShutdownAsync().Wait();
+ server.ShutdownAsync().Wait();
+ }
+
+ [Test]
+ public async Task HeaderInterceptor_CreateMetadata()
+ {
+ var key = "x-grpc-test-echo-initial";
+ client.HeaderInterceptor = new HeaderInterceptor((method, metadata) =>
+ {
+ metadata.Add(key, "ABC");
+ });
+
+ var call = client.UnaryCallAsync(new SimpleRequest());
+ await call;
+
+ var responseHeaders = await call.ResponseHeadersAsync;
+ Assert.AreEqual("ABC", responseHeaders.First((entry) => entry.Key == key).Value);
+ }
+
+ [Test]
+ public async Task HeaderInterceptor_AppendMetadata()
+ {
+ var initialKey = "x-grpc-test-echo-initial";
+ var trailingKey = "x-grpc-test-echo-trailing-bin";
+
+ client.HeaderInterceptor = new HeaderInterceptor((method, metadata) =>
+ {
+ metadata.Add(initialKey, "ABC");
+ });
+
+ var headers = new Metadata
+ {
+ { trailingKey, new byte[] {0xaa} }
+ };
+ var call = client.UnaryCallAsync(new SimpleRequest(), headers: headers);
+ await call;
+
+ 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);
+ }
+ }
+}