aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp/Grpc.Core.Tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/csharp/Grpc.Core.Tests')
-rw-r--r--src/csharp/Grpc.Core.Tests/ClientServerTest.cs201
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj24
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs21
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs202
-rw-r--r--src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs (renamed from src/csharp/Grpc.Core.Tests/TimespecTest.cs)59
-rw-r--r--src/csharp/Grpc.Core.Tests/ServerTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/TimeoutsTest.cs207
-rw-r--r--src/csharp/Grpc.Core.Tests/packages.config1
8 files changed, 625 insertions, 92 deletions
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index e797dd82f2..e286ea519f 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -33,6 +33,7 @@
using System;
using System.Diagnostics;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
@@ -44,7 +45,7 @@ namespace Grpc.Core.Tests
{
public class ClientServerTest
{
- const string Host = "localhost";
+ const string Host = "127.0.0.1";
const string ServiceName = "/tests.Test";
static readonly Method<string, string> EchoMethod = new Method<string, string>(
@@ -78,9 +79,9 @@ namespace Grpc.Core.Tests
{
server = new Server();
server.AddServiceDefinition(ServiceDefinition);
- int port = server.AddListeningPort(Host, Server.PickUnusedPort);
+ int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure);
server.Start();
- channel = new Channel(Host, port);
+ channel = new Channel(Host, port, Credentials.Insecure);
}
[TearDown]
@@ -99,17 +100,17 @@ namespace Grpc.Core.Tests
[Test]
public void UnaryCall()
{
- var call = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
- Assert.AreEqual("ABC", Calls.BlockingUnaryCall(call, "ABC", CancellationToken.None));
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ Assert.AreEqual("ABC", Calls.BlockingUnaryCall(internalCall, "ABC", CancellationToken.None));
}
[Test]
public void UnaryCall_ServerHandlerThrows()
{
- var call = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
try
{
- Calls.BlockingUnaryCall(call, "THROW", CancellationToken.None);
+ Calls.BlockingUnaryCall(internalCall, "THROW", CancellationToken.None);
Assert.Fail();
}
catch (RpcException e)
@@ -119,67 +120,112 @@ namespace Grpc.Core.Tests
}
[Test]
+ public void UnaryCall_ServerHandlerThrowsRpcException()
+ {
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ try
+ {
+ Calls.BlockingUnaryCall(internalCall, "THROW_UNAUTHENTICATED", CancellationToken.None);
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.Unauthenticated, e.Status.StatusCode);
+ }
+ }
+
+ [Test]
+ public void UnaryCall_ServerHandlerSetsStatus()
+ {
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ try
+ {
+ Calls.BlockingUnaryCall(internalCall, "SET_UNAUTHENTICATED", CancellationToken.None);
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.Unauthenticated, e.Status.StatusCode);
+ }
+ }
+
+ [Test]
public void AsyncUnaryCall()
{
- var call = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
- var result = Calls.AsyncUnaryCall(call, "ABC", CancellationToken.None).Result;
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ var result = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None).ResponseAsync.Result;
Assert.AreEqual("ABC", result);
}
[Test]
- public void AsyncUnaryCall_ServerHandlerThrows()
+ public async Task AsyncUnaryCall_ServerHandlerThrows()
{
- Task.Run(async () =>
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ try
{
- var call = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
- try
- {
- await Calls.AsyncUnaryCall(call, "THROW", CancellationToken.None);
- Assert.Fail();
- }
- catch (RpcException e)
- {
- Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
- }
- }).Wait();
+ await Calls.AsyncUnaryCall(internalCall, "THROW", CancellationToken.None);
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
+ }
}
[Test]
- public void ClientStreamingCall()
+ public async Task ClientStreamingCall()
{
- Task.Run(async () =>
- {
- var call = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
- var callResult = Calls.AsyncClientStreamingCall(call, CancellationToken.None);
+ var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
+ var call = Calls.AsyncClientStreamingCall(internalCall, CancellationToken.None);
- await callResult.RequestStream.WriteAll(new string[] { "A", "B", "C" });
- Assert.AreEqual("ABC", await callResult.Result);
- }).Wait();
+ await call.RequestStream.WriteAll(new string[] { "A", "B", "C" });
+ Assert.AreEqual("ABC", await call.ResponseAsync);
}
[Test]
- public void ClientStreamingCall_CancelAfterBegin()
+ public async Task ClientStreamingCall_CancelAfterBegin()
{
- Task.Run(async () =>
+ var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
+
+ var cts = new CancellationTokenSource();
+ var call = Calls.AsyncClientStreamingCall(internalCall, cts.Token);
+
+ // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
+ await Task.Delay(1000);
+ cts.Cancel();
+
+ try
{
- var call = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
+ await call.ResponseAsync;
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
+ }
+ }
- var cts = new CancellationTokenSource();
- var callResult = Calls.AsyncClientStreamingCall(call, cts.Token);
+ [Test]
+ public void AsyncUnaryCall_EchoMetadata()
+ {
+ var headers = new Metadata
+ {
+ new Metadata.Entry("asciiHeader", "abcdefg"),
+ new Metadata.Entry("binaryHeader-bin", new byte[] { 1, 2, 3, 0, 0xff }),
+ };
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, headers);
+ var call = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None);
- // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
- await Task.Delay(1000);
- cts.Cancel();
+ Assert.AreEqual("ABC", call.ResponseAsync.Result);
- try
- {
- await callResult.Result;
- }
- catch (RpcException e)
- {
- Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
- }
- }).Wait();
+ Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
+
+ var trailers = call.GetTrailers();
+ Assert.AreEqual(2, trailers.Count);
+ Assert.AreEqual(headers[0].Key, trailers[0].Key);
+ Assert.AreEqual(headers[0].Value, trailers[0].Value);
+
+ Assert.AreEqual(headers[1].Key, trailers[1].Key);
+ CollectionAssert.AreEqual(headers[1].ValueBytes, trailers[1].ValueBytes);
}
[Test]
@@ -187,25 +233,25 @@ namespace Grpc.Core.Tests
{
channel.Dispose();
- var call = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
- Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(call, "ABC", CancellationToken.None));
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(internalCall, "ABC", CancellationToken.None));
}
[Test]
public void UnaryCallPerformance()
{
- var call = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
BenchmarkUtil.RunBenchmark(100, 100,
- () => { Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken)); });
+ () => { Calls.BlockingUnaryCall(internalCall, "ABC", default(CancellationToken)); });
}
[Test]
public void UnknownMethodHandler()
{
- var call = new Call<string, string>(ServiceName, NonexistentMethod, channel, Metadata.Empty);
+ var internalCall = new Call<string, string>(ServiceName, NonexistentMethod, channel, Metadata.Empty);
try
{
- Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken));
+ Calls.BlockingUnaryCall(internalCall, "ABC", default(CancellationToken));
Assert.Fail();
}
catch (RpcException e)
@@ -214,16 +260,61 @@ namespace Grpc.Core.Tests
}
}
- private static async Task<string> EchoHandler(ServerCallContext context, string request)
+ [Test]
+ public void UserAgentStringPresent()
+ {
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ string userAgent = Calls.BlockingUnaryCall(internalCall, "RETURN-USER-AGENT", CancellationToken.None);
+ Assert.IsTrue(userAgent.StartsWith("grpc-csharp/"));
+ }
+
+ [Test]
+ public void PeerInfoPresent()
+ {
+ var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ string peer = Calls.BlockingUnaryCall(internalCall, "RETURN-PEER", CancellationToken.None);
+ Assert.IsTrue(peer.Contains(Host));
+ }
+
+ private static async Task<string> EchoHandler(string request, ServerCallContext context)
{
+ foreach (Metadata.Entry metadataEntry in context.RequestHeaders)
+ {
+ if (metadataEntry.Key != "user-agent")
+ {
+ context.ResponseTrailers.Add(metadataEntry);
+ }
+ }
+
+ if (request == "RETURN-USER-AGENT")
+ {
+ return context.RequestHeaders.Where(entry => entry.Key == "user-agent").Single().Value;
+ }
+
+ if (request == "RETURN-PEER")
+ {
+ return context.Peer;
+ }
+
if (request == "THROW")
{
throw new Exception("This was thrown on purpose by a test");
}
+
+ if (request == "THROW_UNAUTHENTICATED")
+ {
+ throw new RpcException(new Status(StatusCode.Unauthenticated, ""));
+ }
+
+ if (request == "SET_UNAUTHENTICATED")
+ {
+ context.Status = new Status(StatusCode.Unauthenticated, "");
+ }
+
return request;
}
- private static async Task<string> ConcatAndEchoHandler(ServerCallContext context, IAsyncStreamReader<string> requestStream)
+ private static async Task<string> ConcatAndEchoHandler(IAsyncStreamReader<string> requestStream, ServerCallContext context)
{
string result = "";
await requestStream.ForEach(async (request) =>
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 927954c448..1c4cca8b69 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -28,9 +28,25 @@
<ConsolePause>false</ConsolePause>
</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="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
+ <Reference Include="nunit.util">
+ <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="NUnit.VisualStudio.TestAdapter">
+ <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
@@ -44,13 +60,15 @@
<Compile Include="ClientServerTest.cs" />
<Compile Include="ServerTest.cs" />
<Compile Include="GrpcEnvironmentTest.cs" />
- <Compile Include="TimespecTest.cs" />
<Compile Include="PInvokeTest.cs" />
<Compile Include="Internal\MetadataArraySafeHandleTest.cs" />
<Compile Include="Internal\CompletionQueueSafeHandleTest.cs" />
<Compile Include="Internal\CompletionQueueEventTest.cs" />
<Compile Include="Internal\ChannelArgsSafeHandleTest.cs" />
<Compile Include="ChannelOptionsTest.cs" />
+ <Compile Include="Internal\TimespecTest.cs" />
+ <Compile Include="TimeoutsTest.cs" />
+ <Compile Include="NUnitVersionTest.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -60,7 +78,9 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <None Include="packages.config" />
+ <None Include="packages.config">
+ <SubType>Designer</SubType>
+ </None>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
diff --git a/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs
index e03e20c4f7..46469113c5 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs
@@ -59,5 +59,26 @@ namespace Grpc.Core.Internal.Tests
var nativeMetadata = MetadataArraySafeHandle.Create(metadata);
nativeMetadata.Dispose();
}
+
+ [Test]
+ public void ReadMetadataFromPtrUnsafe()
+ {
+ var metadata = new Metadata
+ {
+ new Metadata.Entry("host", "somehost"),
+ new Metadata.Entry("header2", "header value"),
+ };
+ var nativeMetadata = MetadataArraySafeHandle.Create(metadata);
+
+ var copy = MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(nativeMetadata.Handle);
+ Assert.AreEqual(2, copy.Count);
+
+ Assert.AreEqual("host", copy[0].Key);
+ Assert.AreEqual("somehost", copy[0].Value);
+ Assert.AreEqual("header2", copy[1].Key);
+ Assert.AreEqual("header value", copy[1].Value);
+
+ nativeMetadata.Dispose();
+ }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
new file mode 100644
index 0000000000..874df02baa
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
@@ -0,0 +1,202 @@
+#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.Runtime.InteropServices;
+using Grpc.Core.Internal;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+ public class TimespecTest
+ {
+ [Test]
+ public void Now_IsInUtc()
+ {
+ Assert.AreEqual(DateTimeKind.Utc, Timespec.Now.ToDateTime().Kind);
+ }
+
+ [Test]
+ public void Now_AgreesWithUtcNow()
+ {
+ var timespec = Timespec.Now;
+ var utcNow = DateTime.UtcNow;
+
+ TimeSpan difference = utcNow - timespec.ToDateTime();
+
+ // This test is inherently a race - but the two timestamps
+ // should really be way less that a minute apart.
+ Assert.IsTrue(difference.TotalSeconds < 60);
+ }
+
+ [Test]
+ public void InfFuture()
+ {
+ var timespec = Timespec.InfFuture;
+ }
+
+ [Test]
+ public void InfPast()
+ {
+ var timespec = Timespec.InfPast;
+ }
+
+ [Test]
+ public void TimespecSizeIsNativeSize()
+ {
+ Assert.AreEqual(Timespec.NativeSize, Marshal.SizeOf(typeof(Timespec)));
+ }
+
+ [Test]
+ public void ToDateTime()
+ {
+ Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
+ new Timespec(IntPtr.Zero, 0).ToDateTime());
+
+ Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50),
+ new Timespec(new IntPtr(10), 5000).ToDateTime());
+
+ Assert.AreEqual(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc),
+ new Timespec(new IntPtr(1437452508), 0).ToDateTime());
+
+ // before epoch
+ Assert.AreEqual(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10),
+ new Timespec(new IntPtr(-5), 1000).ToDateTime());
+
+ // infinity
+ Assert.AreEqual(DateTime.MaxValue, Timespec.InfFuture.ToDateTime());
+ Assert.AreEqual(DateTime.MinValue, Timespec.InfPast.ToDateTime());
+
+ // nanos are rounded to ticks are rounded up
+ Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(1),
+ new Timespec(IntPtr.Zero, 99).ToDateTime());
+
+ // Illegal inputs
+ Assert.Throws(typeof(InvalidOperationException),
+ () => new Timespec(new IntPtr(0), -2).ToDateTime());
+ Assert.Throws(typeof(InvalidOperationException),
+ () => new Timespec(new IntPtr(0), 1000 * 1000 * 1000).ToDateTime());
+ Assert.Throws(typeof(InvalidOperationException),
+ () => new Timespec(new IntPtr(0), 0, GPRClockType.Monotonic).ToDateTime());
+ }
+
+ [Test]
+ public void ToDateTime_ReturnsUtc()
+ {
+ Assert.AreEqual(DateTimeKind.Utc, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind);
+ Assert.AreNotEqual(DateTimeKind.Unspecified, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind);
+ }
+
+ [Test]
+ public void ToDateTime_Overflow()
+ {
+ // we can only get overflow in ticks arithmetic on 64-bit
+ if (IntPtr.Size == 8)
+ {
+ var timespec = new Timespec(new IntPtr(long.MaxValue - 100), 0);
+ Assert.AreNotEqual(Timespec.InfFuture, timespec);
+ Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
+
+ Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(long.MinValue + 100), 0).ToDateTime());
+ }
+ else
+ {
+ Console.WriteLine("Test cannot be run on this platform, skipping the test.");
+ }
+ }
+
+ [Test]
+ public void ToDateTime_OutOfDateTimeRange()
+ {
+ // we can only get out of range on 64-bit, on 32 bit the max
+ // timestamp is ~ Jan 19 2038, which is far within range of DateTime
+ // same case for min value.
+ if (IntPtr.Size == 8)
+ {
+ // DateTime range goes up to year 9999, 20000 years from now should
+ // be out of range.
+ long seconds = 20000L * 365L * 24L * 3600L;
+
+ var timespec = new Timespec(new IntPtr(seconds), 0);
+ Assert.AreNotEqual(Timespec.InfFuture, timespec);
+ Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
+
+ Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(-seconds), 0).ToDateTime());
+ }
+ else
+ {
+ Console.WriteLine("Test cannot be run on this platform, skipping the test");
+ }
+ }
+
+ [Test]
+ public void FromDateTime()
+ {
+ Assert.AreEqual(new Timespec(IntPtr.Zero, 0),
+ Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
+
+ Assert.AreEqual(new Timespec(new IntPtr(10), 5000),
+ Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50)));
+
+ Assert.AreEqual(new Timespec(new IntPtr(1437452508), 0),
+ Timespec.FromDateTime(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc)));
+
+ // before epoch
+ Assert.AreEqual(new Timespec(new IntPtr(-5), 1000),
+ Timespec.FromDateTime(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10)));
+
+ // infinity
+ Assert.AreEqual(Timespec.InfFuture, Timespec.FromDateTime(DateTime.MaxValue));
+ Assert.AreEqual(Timespec.InfPast, Timespec.FromDateTime(DateTime.MinValue));
+
+ // illegal inputs
+ Assert.Throws(typeof(ArgumentException),
+ () => Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified)));
+ }
+
+ [Test]
+ public void FromDateTime_OutOfTimespecRange()
+ {
+ // we can only get overflow in Timespec on 32-bit
+ if (IntPtr.Size == 4)
+ {
+ Assert.AreEqual(Timespec.InfFuture, Timespec.FromDateTime(new DateTime(2040, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
+ Assert.AreEqual(Timespec.InfPast, Timespec.FromDateTime(new DateTime(1800, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
+ }
+ else
+ {
+ Console.WriteLine("Test cannot be run on this platform, skipping the test.");
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
index 5831121add..600df1a18d 100644
--- a/src/csharp/Grpc.Core.Tests/TimespecTest.cs
+++ b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
@@ -32,57 +32,48 @@
#endregion
using System;
-using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
using Grpc.Core.Internal;
+using Grpc.Core.Utils;
using NUnit.Framework;
-namespace Grpc.Core.Internal.Tests
+namespace Grpc.Core.Tests
{
- public class TimespecTest
+ /// <summary>
+ /// Tests if the version of nunit-console used is sufficient to run async tests.
+ /// </summary>
+ public class NUnitVersionTest
{
- [Test]
- public void Now()
- {
- var timespec = Timespec.Now;
- }
+ private int testRunCount = 0;
- [Test]
- public void InfFuture()
+ [TestFixtureTearDown]
+ public void Cleanup()
{
- var timespec = Timespec.InfFuture;
+ if (testRunCount != 2)
+ {
+ Console.Error.WriteLine("You are using and old version of NUnit that doesn't support async tests and skips them instead. " +
+ "This test has failed to indicate that.");
+ Console.Error.Flush();
+ Environment.Exit(1);
+ }
}
[Test]
- public void TimespecSizeIsNativeSize()
+ public void NUnitVersionTest1()
{
- Assert.AreEqual(Timespec.NativeSize, Marshal.SizeOf(typeof(Timespec)));
+ testRunCount++;
}
+ // Old version of NUnit will skip this test
[Test]
- public void Add()
+ public async Task NUnitVersionTest2()
{
- var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 123456789 };
- var result = t.Add(TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 10));
- Assert.AreEqual(result.tv_sec, new IntPtr(12355));
- Assert.AreEqual(result.tv_nsec, 123456789);
+ testRunCount ++;
+ await Task.Delay(10);
}
- [Test]
- public void Add_Nanos()
- {
- var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 123456789 };
- var result = t.Add(TimeSpan.FromTicks(10));
- Assert.AreEqual(result.tv_sec, new IntPtr(12345));
- Assert.AreEqual(result.tv_nsec, 123456789 + 1000);
- }
- [Test]
- public void Add_NanosOverflow()
- {
- var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 999999999 };
- var result = t.Add(TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 10 + 10));
- Assert.AreEqual(result.tv_sec, new IntPtr(12356));
- Assert.AreEqual(result.tv_nsec, 999);
- }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs
index 1119aa370e..ba9efae871 100644
--- a/src/csharp/Grpc.Core.Tests/ServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs
@@ -45,7 +45,7 @@ namespace Grpc.Core.Tests
public void StartAndShutdownServer()
{
Server server = new Server();
- server.AddListeningPort("localhost", Server.PickUnusedPort);
+ server.AddPort("localhost", Server.PickUnusedPort, ServerCredentials.Insecure);
server.Start();
server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
new file mode 100644
index 0000000000..010ffd898a
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
@@ -0,0 +1,207 @@
+#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.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
+{
+ /// <summary>
+ /// Tests for Deadline support.
+ /// </summary>
+ public class TimeoutsTest
+ {
+ const string Host = "localhost";
+ const string ServiceName = "/tests.Test";
+
+ static readonly Method<string, string> TestMethod = new Method<string, string>(
+ MethodType.Unary,
+ "/tests.Test/Test",
+ Marshallers.StringMarshaller,
+ Marshallers.StringMarshaller);
+
+ static readonly ServerServiceDefinition ServiceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName)
+ .AddMethod(TestMethod, TestMethodHandler)
+ .Build();
+
+ // provides a way how to retrieve an out-of-band result value from server handler
+ static TaskCompletionSource<string> stringFromServerHandlerTcs;
+
+ Server server;
+ Channel channel;
+
+ [SetUp]
+ public void Init()
+ {
+ server = new Server();
+ server.AddServiceDefinition(ServiceDefinition);
+ int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure);
+ server.Start();
+ channel = new Channel(Host, port, Credentials.Insecure);
+
+ stringFromServerHandlerTcs = new TaskCompletionSource<string>();
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ channel.Dispose();
+ server.ShutdownAsync().Wait();
+ }
+
+ [TestFixtureTearDown]
+ public void CleanupClass()
+ {
+ GrpcEnvironment.Shutdown();
+ }
+
+ [Test]
+ public void InfiniteDeadline()
+ {
+ // no deadline specified, check server sees infinite deadline
+ var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty);
+ Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(internalCall, "RETURN_DEADLINE", CancellationToken.None));
+
+ // DateTime.MaxValue deadline specified, check server sees infinite deadline
+ var internalCall2 = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, DateTime.MaxValue);
+ Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(internalCall2, "RETURN_DEADLINE", CancellationToken.None));
+ }
+
+ [Test]
+ public void DeadlineTransferredToServer()
+ {
+ var remainingTimeClient = TimeSpan.FromDays(7);
+ var deadline = DateTime.UtcNow + remainingTimeClient;
+ Thread.Sleep(1000);
+ var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline);
+
+ var serverDeadlineTicksString = Calls.BlockingUnaryCall(internalCall, "RETURN_DEADLINE", CancellationToken.None);
+ var serverDeadline = new DateTime(long.Parse(serverDeadlineTicksString), DateTimeKind.Utc);
+
+ // A fairly relaxed check that the deadline set by client and deadline seen by server
+ // are in agreement. C core takes care of the work with transferring deadline over the wire,
+ // so we don't need an exact check here.
+ Assert.IsTrue(Math.Abs((deadline - serverDeadline).TotalMilliseconds) < 5000);
+ }
+
+ [Test]
+ public void DeadlineInThePast()
+ {
+ var deadline = DateTime.MinValue;
+ var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline);
+
+ try
+ {
+ Calls.BlockingUnaryCall(internalCall, "TIMEOUT", CancellationToken.None);
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode);
+ }
+ }
+
+ [Test]
+ public void DeadlineExceededStatusOnTimeout()
+ {
+ var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));
+ var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline);
+
+ try
+ {
+ Calls.BlockingUnaryCall(internalCall, "TIMEOUT", CancellationToken.None);
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode);
+ }
+ }
+
+ [Test]
+ public void ServerReceivesCancellationOnTimeout()
+ {
+ var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));
+ var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline);
+
+ try
+ {
+ Calls.BlockingUnaryCall(internalCall, "CHECK_CANCELLATION_RECEIVED", CancellationToken.None);
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode);
+ }
+ Assert.AreEqual("CANCELLED", stringFromServerHandlerTcs.Task.Result);
+ }
+
+ private static async Task<string> TestMethodHandler(string request, ServerCallContext context)
+ {
+ if (request == "TIMEOUT")
+ {
+ await Task.Delay(60000);
+ return "";
+ }
+
+ if (request == "RETURN_DEADLINE")
+ {
+ if (context.Deadline == DateTime.MaxValue)
+ {
+ return "DATETIME_MAXVALUE";
+ }
+
+ return context.Deadline.Ticks.ToString();
+ }
+
+ if (request == "CHECK_CANCELLATION_RECEIVED")
+ {
+ // wait until cancellation token is fired.
+ var tcs = new TaskCompletionSource<object>();
+ context.CancellationToken.Register(() => { tcs.SetResult(null); });
+ await tcs.Task;
+ stringFromServerHandlerTcs.SetResult("CANCELLED");
+ return "";
+ }
+
+ return "";
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/packages.config b/src/csharp/Grpc.Core.Tests/packages.config
index 28af8d78c6..62077f41be 100644
--- a/src/csharp/Grpc.Core.Tests/packages.config
+++ b/src/csharp/Grpc.Core.Tests/packages.config
@@ -2,4 +2,5 @@
<packages>
<package id="Ix-Async" version="1.2.3" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" />
+ <package id="NUnitTestAdapter" version="2.0.0" targetFramework="net45" />
</packages> \ No newline at end of file