Skip to content

Commit

Permalink
Add unt test for #5.
Browse files Browse the repository at this point in the history
The original TestRoutines.TestCancellationAsync failed to issue the notification to really cancel the request.
Fixed typo: ITestRpcCancallationContract -> ITestRpcCancellationContract.
  • Loading branch information
CXuesong committed May 6, 2018
1 parent d3543e9 commit 78384e2
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 22 deletions.
2 changes: 1 addition & 1 deletion UnitTestProject1/Helpers/TestJsonRpcService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public async Task<int> OnePlusTwo()

}

public interface ITestRpcCancallationContract
public interface ITestRpcCancellationContract
{

[JsonRpcMethod]
Expand Down
53 changes: 37 additions & 16 deletions UnitTestProject1/JsonRpcStreamsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ public JsonRpcStreamsTests(ITestOutputHelper output) : base(output)
private readonly RequestMessage TestMessage = new RequestMessage(1, "test");

private readonly byte[] TestMessagePartwiseStreamContent =
Encoding.UTF8.GetBytes(
"Content-Length: 40\r\nContent-Type: application/json-rpc;charset=utf-8\r\n\r\n{\"id\":1,\"method\":\"test\",\"jsonrpc\":\"2.0\"}")
;
Encoding.UTF8.GetBytes(
"Content-Length: 40\r\nContent-Type: application/json-rpc;charset=utf-8\r\n\r\n{\"id\":1,\"method\":\"test\",\"jsonrpc\":\"2.0\"}");

[Fact]
public async Task PartwiseStreamWriterTest()
Expand Down Expand Up @@ -113,6 +112,7 @@ async Task<ResponseMessage> WaitForResponse()
Output.WriteLine($"Received response in {sw.Elapsed}.");
return (ResponseMessage) Message.LoadJson(content);
}

async Task<ResponseMessage> SendRequest(MessageId messageId)
{
request.Id = messageId;
Expand All @@ -125,6 +125,7 @@ async Task<ResponseMessage> SendRequest(MessageId messageId)
Assert.Equal(55, (int) response.Result);
return response;
}

using (var server = new ServerTestHelper(this, serverReader, serverWriter,
StreamRpcServerHandlerOptions.None))
{
Expand Down Expand Up @@ -215,22 +216,40 @@ public async Task ConsistentResponseSequenceTest()
}
}

// #5 StreamRpcServerHandler.TryCancelRequest may cause server unable to respond to the subsequent requests
[Fact]
public async Task PartwiseStreamConsistentSequenceCancellationTest()
{
(var ss, var cs) = FullDuplexStream.CreateStreams();
using (var clientReader = new ByLineTextMessageReader(cs))
using (var clientWriter = new ByLineTextMessageWriter(cs))
using (var serverReader = new ByLineTextMessageReader(ss))
using (var serverWriter = new ByLineTextMessageWriter(ss))
using (var server = new ServerTestHelper(this, serverReader, serverWriter,
StreamRpcServerHandlerOptions.ConsistentResponseSequence
| StreamRpcServerHandlerOptions.SupportsRequestCancellation))
using (var client = new ClientTestHelper(clientReader, clientWriter))
{
await TestRoutines.TestCancellationAsync(client.ClientCancellationStub);
}
}

public class ServerTestHelper : IDisposable
{
{

private readonly List<IDisposable> disposables = new List<IDisposable>();

public ServerTestHelper(UnitTestBase owner, MessageReader reader, MessageWriter writer,
StreamRpcServerHandlerOptions options)
{
ServiceHost = Utility.CreateJsonRpcServiceHost(owner);
ServerHandler = new StreamRpcServerHandler(ServiceHost, options);
ServerMessageReader = reader;
ServerMessageWriter = writer;
disposables.Add(ServerHandler.Attach(ServerMessageReader, ServerMessageWriter));
}
public ServerTestHelper(UnitTestBase owner, MessageReader reader, MessageWriter writer,
StreamRpcServerHandlerOptions options)
{
ServiceHost = Utility.CreateJsonRpcServiceHost(owner);
ServerHandler = new StreamRpcServerHandler(ServiceHost, options);
ServerMessageReader = reader;
ServerMessageWriter = writer;
disposables.Add(ServerHandler.Attach(ServerMessageReader, ServerMessageWriter));
}

public IJsonRpcServiceHost ServiceHost { get; }
public IJsonRpcServiceHost ServiceHost { get; }

public MessageReader ServerMessageReader { get; }

Expand All @@ -257,12 +276,14 @@ public ClientTestHelper(MessageReader reader, MessageWriter writer)
Client = new JsonRpcClient(ClientHandler);
ClientMessageReader = reader;
ClientMessageWriter = writer;
// We use positional parameters when issuing cancelRequest request. Just for more test coverage.
Client.RequestCancelling += (_, e) => { Client.SendNotificationAsync("cancelRequest", new JArray(e.RequestId.Value), CancellationToken.None); };
disposables.Add(ClientHandler.Attach(ClientMessageReader, ClientMessageWriter));

var proxyBuilder = new JsonRpcProxyBuilder {ContractResolver = Utility.DefaultContractResolver};
ClientStub = proxyBuilder.CreateProxy<ITestRpcContract>(Client);
ClientExceptionStub = proxyBuilder.CreateProxy<ITestRpcExceptionContract>(Client);
ClientCancellationStub = proxyBuilder.CreateProxy<ITestRpcCancallationContract>(Client);
ClientCancellationStub = proxyBuilder.CreateProxy<ITestRpcCancellationContract>(Client);
}

public JsonRpcClient Client { get; }
Expand All @@ -277,7 +298,7 @@ public ClientTestHelper(MessageReader reader, MessageWriter writer)

public ITestRpcExceptionContract ClientExceptionStub { get; }

public ITestRpcCancallationContract ClientCancellationStub { get; }
public ITestRpcCancellationContract ClientCancellationStub { get; }

/// <inheritdoc />
public void Dispose()
Expand Down
25 changes: 20 additions & 5 deletions UnitTestProject1/TestRoutines.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Text;
Expand Down Expand Up @@ -54,22 +55,36 @@ public static async Task TestStubAsync(ITestRpcExceptionContract stub)
{
var ex = Assert.Throws<JsonRpcRemoteException>(() => stub.MismatchedMethod());
Assert.Null(ex.RemoteException);
Assert.Equal(JsonRpcErrorCode.MethodNotFound, (JsonRpcErrorCode)ex.Error.Code);
Assert.Equal(JsonRpcErrorCode.MethodNotFound, (JsonRpcErrorCode) ex.Error.Code);
}
{
var ex = await Assert.ThrowsAsync<JsonRpcContractException>(stub.ContractViolatingMethodAsync);
}
}

public static async Task TestCancellationAsync(ITestRpcCancallationContract stub)
public static async Task TestCancellationAsync(ITestRpcCancellationContract stub)
{
await stub.Delay(TimeSpan.FromMilliseconds(50));
Assert.True(await stub.IsLastDelayFinished());
using (var cts = new CancellationTokenSource(100))
using (var cts = new CancellationTokenSource())
{
await Assert.ThrowsAsync<TaskCanceledException>(
() => stub.Delay(TimeSpan.FromSeconds(1), cts.Token));
// Note: When the request cancellation notification is issued from client,
// a TaskCancelledException will be thrown immediately regardless of the service handler's state.
// we can check whether the request has really been cancelled by enabling ConsistentResponseSequence.
// TODO implement ability to wait for "request cancelled" response and put it into some OperationCancelledException-derived class
// in JsonRpcClient.
// 1. Issue the request
var delayTask = stub.Delay(TimeSpan.FromSeconds(3), cts.Token);
// 2. Issue the cancellation
cts.Cancel();
// 3. Ensures the client-side exception
await Assert.ThrowsAsync<TaskCanceledException>(() => delayTask);
var sw = Stopwatch.StartNew();
Assert.False(await stub.IsLastDelayFinished());
sw.Stop();
// Ensures that the stub.Delay request has really been cancelled.
// Normally the execution time of stub.IsLastDelayFinished should definitely be less than 2 sec.
Assert.InRange(sw.ElapsedMilliseconds, 1, 2000);
}
}
}
Expand Down

0 comments on commit 78384e2

Please sign in to comment.