From 8f5020684b378d2f39456f53730cb7c601f8b3a0 Mon Sep 17 00:00:00 2001 From: David Driscoll Date: Sun, 2 Aug 2020 22:28:04 -0400 Subject: [PATCH] Updated router and added jsonrpc integration tests (#274) * Updated router and added jsonrpc integration tests * disabled new tests --- src/Shared/LspRequestRouter.cs | 14 +- test/Dap.Tests/JsonRpcIntegrationTests.cs | 247 ++++++++++++++++++ .../Integration/DynamicRegistrationTests.cs | 4 +- test/Lsp.Tests/JsonRpcIntegrationTests.cs | 247 ++++++++++++++++++ 4 files changed, 509 insertions(+), 3 deletions(-) create mode 100644 test/Dap.Tests/JsonRpcIntegrationTests.cs create mode 100644 test/Lsp.Tests/JsonRpcIntegrationTests.cs diff --git a/src/Shared/LspRequestRouter.cs b/src/Shared/LspRequestRouter.cs index 5956399f8..895029279 100644 --- a/src/Shared/LspRequestRouter.cs +++ b/src/Shared/LspRequestRouter.cs @@ -58,11 +58,21 @@ private IRequestDescriptor FindDescriptor(string method, return new RequestDescriptor(); } - if (@params == null || descriptor.Params == null) return new RequestDescriptor(new [] { descriptor }); + if (@params == null || descriptor.Params == null) return new RequestDescriptor(new[] { descriptor }); + + object paramsValue = null; + if (descriptor.IsDelegatingHandler) + { + var o = @params?.ToObject(descriptor.Params.GetGenericArguments()[0], _serializer.JsonSerializer); + paramsValue = Activator.CreateInstance(descriptor.Params, new object[] { o }); + } + else + { + paramsValue = @params?.ToObject(descriptor.Params, _serializer.JsonSerializer); + } var lspHandlerDescriptors = _collection.Where(handler => handler.Method == method).ToList(); - var paramsValue = @params.ToObject(descriptor.Params, _serializer.JsonSerializer); var matchDescriptor = _handlerMatchers.SelectMany(strat => strat.FindHandler(paramsValue, lspHandlerDescriptors)).ToArray(); if (matchDescriptor.Length > 0) return new RequestDescriptor(matchDescriptor); // execute command is a special case diff --git a/test/Dap.Tests/JsonRpcIntegrationTests.cs b/test/Dap.Tests/JsonRpcIntegrationTests.cs new file mode 100644 index 000000000..94df979eb --- /dev/null +++ b/test/Dap.Tests/JsonRpcIntegrationTests.cs @@ -0,0 +1,247 @@ +// using System; +// using System.Linq; +// using System.Reactive.Subjects; +// using System.Threading; +// using System.Threading.Tasks; +// using FluentAssertions; +// using MediatR; +// using NSubstitute; +// using OmniSharp.Extensions.DebugAdapter.Testing; +// using OmniSharp.Extensions.JsonRpc; +// using OmniSharp.Extensions.JsonRpc.Server; +// using OmniSharp.Extensions.JsonRpc.Testing; +// using Xunit; +// using Xunit.Abstractions; + +// namespace Dap.Tests +// { +// public class JsonRpcIntegrationTests : DebugAdapterProtocolTestBase +// { +// public JsonRpcIntegrationTests(ITestOutputHelper outputHelper) : base(new JsonRpcTestOptions().ConfigureForXUnit(outputHelper)) +// { +// } + +// class Request : IRequest +// { + +// } + +// class Data +// { +// public string Value { get; set; } +// } + +// [Fact] +// public async Task Should_Send_and_receive_requests() +// { +// var (client, server) = await Initialize( +// client => { client.OnRequest("myrequest", async () => new Data() {Value = "myresponse"}); }, +// server => { server.OnRequest("myrequest", async () => new Data() {Value = string.Join("", "myresponse".Reverse())}); } +// ); + +// var serverResponse = await client.SendRequest("myrequest").Returning(CancellationToken); +// serverResponse.Value.Should().Be("esnopserym"); + +// var clientResponse = await server.SendRequest("myrequest").Returning(CancellationToken); +// clientResponse.Value.Should().Be("myresponse"); +// } + +// [Fact(Skip = "DAP does not define invalid parameters semantics")] +// public async Task Should_throw_when_sending_requests() +// { +// var (client, server) = await Initialize( +// client => { client.OnRequest("myrequest", async (Request request) => new Data() {Value = "myresponse"}); }, +// server => { server.OnRequest("myrequest", async (Request request) => new Data() {Value = string.Join("", "myresponse".Reverse())}); } +// ); + +// Func clientRequest = () => client.SendRequest("myrequest", (Request)null).Returning(CancellationToken); +// clientRequest.Should().Throw(); + +// Func serverRequest = () => server.SendRequest("myrequest", (Request)null).Returning(CancellationToken); +// serverRequest.Should().Throw(); +// } + +// [Fact] +// public async Task Should_throw_when_receiving_requests() +// { +// var (client, server) = await Initialize( +// client => { client.OnRequest("myrequest", async (Request request) => (Data)null); }, +// server => { server.OnRequest("myrequest", async (Request request) => (Data)null); } +// ); + +// Func clientRequest = () => client.SendRequest("myrequest", new Request()).Returning(CancellationToken); +// clientRequest.Should().Throw(); + +// Func serverRequest = () => server.SendRequest("myrequest", new Request()).Returning(CancellationToken); +// serverRequest.Should().Throw(); +// } + +// [Fact] +// public async Task Should_Send_and_receive_notifications() +// { +// var clientNotification = new AsyncSubject(); +// var serverNotification = new AsyncSubject(); +// var (client, server) = await Initialize( +// client => { +// client.OnNotification("mynotification", (Data data) => { +// clientNotification.OnNext(data); +// clientNotification.OnCompleted(); +// }); +// }, +// server => { +// server.OnNotification("mynotification", (Data data) => { +// serverNotification.OnNext(data); +// serverNotification.OnCompleted(); +// }); +// } +// ); + +// client.SendNotification("mynotification", new Data() {Value = "myresponse"}); +// var serverResponse = await serverNotification; +// serverResponse.Value.Should().Be("myresponse"); + +// server.SendNotification("mynotification", new Data() {Value = string.Join("", "myresponse".Reverse())}); +// var clientResponse = await clientNotification; +// clientResponse.Value.Should().Be("esnopserym"); +// } + +// [Fact] +// public async Task Should_Send_and_cancel_requests_immediate() +// { +// var (client, server) = await Initialize( +// client => { +// client.OnRequest("myrequest", async (ct) => { +// await Task.Delay(TimeSpan.FromMinutes(1), ct); +// return new Data() {Value = "myresponse"}; +// }); +// }, +// server => { +// server.OnRequest("myrequest", async (ct) => { +// await Task.Delay(TimeSpan.FromMinutes(1), ct); +// return new Data() {Value = string.Join("", "myresponse".Reverse())}; +// }); +// } +// ); + +// var cts = new CancellationTokenSource(); +// cts.Cancel(); + +// { +// Func action = () => client.SendRequest("myrequest").Returning(cts.Token); +// await action.Should().ThrowAsync(); +// } + +// { +// Func action = () => server.SendRequest("myrequest").Returning(cts.Token); +// await action.Should().ThrowAsync(); +// } +// } + +// [Fact] +// public async Task Should_Send_and_cancel_requests_from_otherside() +// { +// var (client, server) = await Initialize( +// client => { +// client.OnRequest("myrequest", async (ct) => { +// await Task.Delay(TimeSpan.FromMinutes(1), ct); +// return new Data() {Value = "myresponse"}; +// }); +// }, +// server => { +// server.OnRequest("myrequest", async (ct) => { +// await Task.Delay(TimeSpan.FromMinutes(1), ct); +// return new Data() {Value = string.Join("", "myresponse".Reverse())}; +// }); +// } +// ); + +// { +// var cts = new CancellationTokenSource(); +// Func action = () => client.SendRequest("myrequest").Returning(cts.Token); +// cts.CancelAfter(10); +// await action.Should().ThrowAsync(); +// } + +// { +// var cts = new CancellationTokenSource(); +// Func action = () => server.SendRequest("myrequest").Returning(cts.Token); +// cts.CancelAfter(10); +// await action.Should().ThrowAsync(); +// } +// } + +// [Fact(Skip = "Not supported by the DAP")] +// public async Task Should_Cancel_Parallel_Requests_When_Options_Are_Given() +// { +// var (client, server) = await Initialize( +// client => { +// client.OnRequest( +// "parallelrequest", +// async (ct) => { +// await Task.Delay(TimeSpan.FromSeconds(10), ct); +// return new Data() {Value = "myresponse"}; +// }, +// new JsonRpcHandlerOptions() {RequestProcessType = RequestProcessType.Parallel}); +// client.OnRequest( +// "serialrequest", +// async (ct) => new Data() {Value = "myresponse"}, +// new JsonRpcHandlerOptions() {RequestProcessType = RequestProcessType.Serial} +// ); +// }, +// server => { +// server.OnRequest( +// "parallelrequest", +// async (ct) => { +// await Task.Delay(TimeSpan.FromSeconds(10), ct); +// return new Data() {Value = "myresponse"}; +// }, +// new JsonRpcHandlerOptions() {RequestProcessType = RequestProcessType.Parallel}); +// server.OnRequest( +// "serialrequest", +// async (ct) => new Data() {Value = "myresponse"}, +// new JsonRpcHandlerOptions() {RequestProcessType = RequestProcessType.Serial} +// ); +// } +// ); + +// { +// var task = client.SendRequest("parallelrequest").Returning(CancellationToken); +// await client.SendRequest("serialrequest").Returning(CancellationToken); +// Func action = () => task; +// await action.Should().ThrowAsync(); +// } + +// { +// var task = server.SendRequest("parallelrequest").Returning(CancellationToken); +// await server.SendRequest("serialrequest").Returning(CancellationToken); +// Func action = () => task; +// await action.Should().ThrowAsync(); +// } +// } + +// [Fact] +// public async Task Should_Link_Request_A_to_Request_B() +// { +// var (client, server) = await Initialize( +// client => { +// client +// .OnRequest("myrequest", async () => new Data() {Value = "myresponse"}) +// .WithLink("myrequest", "myrequest2") +// ; +// }, +// server => { +// server +// .OnRequest("myrequest", async () => new Data() {Value = string.Join("", "myresponse".Reverse())}) +// .WithLink("myrequest", "myrequest2") +// ; +// } +// ); + +// var serverResponse = await client.SendRequest("myrequest2").Returning(CancellationToken); +// serverResponse.Value.Should().Be("esnopserym"); + +// var clientResponse = await server.SendRequest("myrequest2").Returning(CancellationToken); +// clientResponse.Value.Should().Be("myresponse"); +// } +// } +// } diff --git a/test/Lsp.Tests/Integration/DynamicRegistrationTests.cs b/test/Lsp.Tests/Integration/DynamicRegistrationTests.cs index 1d478c3a1..076167699 100644 --- a/test/Lsp.Tests/Integration/DynamicRegistrationTests.cs +++ b/test/Lsp.Tests/Integration/DynamicRegistrationTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Reactive.Linq; using System.Reactive.Threading.Tasks; @@ -61,6 +61,8 @@ public async Task Should_Register_Dynamically_While_Server_Is_Running() await SettleNext(); + await SettleNext(); + client.RegistrationManager.CurrentRegistrations.Should().Contain(x => x.Method == TextDocumentNames.Completion && SelectorMatches(x, z=> z.HasLanguage && z.Language == "vb") ); diff --git a/test/Lsp.Tests/JsonRpcIntegrationTests.cs b/test/Lsp.Tests/JsonRpcIntegrationTests.cs new file mode 100644 index 000000000..31d3880f0 --- /dev/null +++ b/test/Lsp.Tests/JsonRpcIntegrationTests.cs @@ -0,0 +1,247 @@ +// using System; +// using System.Linq; +// using System.Reactive.Subjects; +// using System.Threading; +// using System.Threading.Tasks; +// using FluentAssertions; +// using MediatR; +// using NSubstitute; +// using OmniSharp.Extensions.JsonRpc; +// using OmniSharp.Extensions.JsonRpc.Server; +// using OmniSharp.Extensions.JsonRpc.Testing; +// using OmniSharp.Extensions.LanguageProtocol.Testing; +// using Xunit; +// using Xunit.Abstractions; + +// namespace Lsp.Tests +// { +// public class JsonRpcIntegrationTests : LanguageProtocolTestBase +// { +// public JsonRpcIntegrationTests(ITestOutputHelper outputHelper) : base(new JsonRpcTestOptions().ConfigureForXUnit(outputHelper)) +// { +// } + +// class Request : IRequest +// { + +// } + +// class Data +// { +// public string Value { get; set; } +// } + +// [Fact] +// public async Task Should_Send_and_receive_requests() +// { +// var (client, server) = await Initialize( +// client => { client.OnRequest("myrequest", async () => new Data() {Value = "myresponse"}); }, +// server => { server.OnRequest("myrequest", async () => new Data() {Value = string.Join("", "myresponse".Reverse())}); } +// ); + +// var serverResponse = await client.SendRequest("myrequest").Returning(CancellationToken); +// serverResponse.Value.Should().Be("esnopserym"); + +// var clientResponse = await server.SendRequest("myrequest").Returning(CancellationToken); +// clientResponse.Value.Should().Be("myresponse"); +// } + +// [Fact] +// public async Task Should_throw_when_sending_requests() +// { +// var (client, server) = await Initialize( +// client => { client.OnRequest("myrequest", async (Request request) => new Data() {Value = "myresponse"}); }, +// server => { server.OnRequest("myrequest", async (Request request) => new Data() {Value = string.Join("", "myresponse".Reverse())}); } +// ); + +// Func clientRequest = () => client.SendRequest("myrequest", (Request)null).Returning(CancellationToken); +// clientRequest.Should().Throw(); + +// Func serverRequest = () => server.SendRequest("myrequest", (Request)null).Returning(CancellationToken); +// serverRequest.Should().Throw(); +// } + +// [Fact] +// public async Task Should_throw_when_receiving_requests() +// { +// var (client, server) = await Initialize( +// client => { client.OnRequest("myrequest", async (Request request) => (Data)null); }, +// server => { server.OnRequest("myrequest", async (Request request) => (Data)null); } +// ); + +// Func clientRequest = () => client.SendRequest("myrequest", new Request()).Returning(CancellationToken); +// clientRequest.Should().Throw(); + +// Func serverRequest = () => server.SendRequest("myrequest", new Request()).Returning(CancellationToken); +// serverRequest.Should().Throw(); +// } + +// [Fact] +// public async Task Should_Send_and_receive_notifications() +// { +// var clientNotification = new AsyncSubject(); +// var serverNotification = new AsyncSubject(); +// var (client, server) = await Initialize( +// client => { +// client.OnNotification("mynotification", (Data data) => { +// clientNotification.OnNext(data); +// clientNotification.OnCompleted(); +// }); +// }, +// server => { +// server.OnNotification("mynotification", (Data data) => { +// serverNotification.OnNext(data); +// serverNotification.OnCompleted(); +// }); +// } +// ); + +// client.SendNotification("mynotification", new Data() {Value = "myresponse"}); +// var serverResponse = await serverNotification; +// serverResponse.Value.Should().Be("myresponse"); + +// server.SendNotification("mynotification", new Data() {Value = string.Join("", "myresponse".Reverse())}); +// var clientResponse = await clientNotification; +// clientResponse.Value.Should().Be("esnopserym"); +// } + +// [Fact] +// public async Task Should_Send_and_cancel_requests_immediate() +// { +// var (client, server) = await Initialize( +// client => { +// client.OnRequest("myrequest", async (ct) => { +// await Task.Delay(TimeSpan.FromMinutes(1), ct); +// return new Data() {Value = "myresponse"}; +// }); +// }, +// server => { +// server.OnRequest("myrequest", async (ct) => { +// await Task.Delay(TimeSpan.FromMinutes(1), ct); +// return new Data() {Value = string.Join("", "myresponse".Reverse())}; +// }); +// } +// ); + +// var cts = new CancellationTokenSource(); +// cts.Cancel(); + +// { +// Func action = () => client.SendRequest("myrequest").Returning(cts.Token); +// await action.Should().ThrowAsync(); +// } + +// { +// Func action = () => server.SendRequest("myrequest").Returning(cts.Token); +// await action.Should().ThrowAsync(); +// } +// } + +// [Fact] +// public async Task Should_Send_and_cancel_requests_from_otherside() +// { +// var (client, server) = await Initialize( +// client => { +// client.OnRequest("myrequest", async (ct) => { +// await Task.Delay(TimeSpan.FromMinutes(1), ct); +// return new Data() {Value = "myresponse"}; +// }); +// }, +// server => { +// server.OnRequest("myrequest", async (ct) => { +// await Task.Delay(TimeSpan.FromMinutes(1), ct); +// return new Data() {Value = string.Join("", "myresponse".Reverse())}; +// }); +// } +// ); + +// { +// var cts = new CancellationTokenSource(); +// Func action = () => client.SendRequest("myrequest").Returning(cts.Token); +// cts.CancelAfter(10); +// await action.Should().ThrowAsync(); +// } + +// { +// var cts = new CancellationTokenSource(); +// Func action = () => server.SendRequest("myrequest").Returning(cts.Token); +// cts.CancelAfter(10); +// await action.Should().ThrowAsync(); +// } +// } + +// [Fact] +// public async Task Should_Cancel_Parallel_Requests_When_Options_Are_Given() +// { +// var (client, server) = await Initialize( +// client => { +// client.OnRequest( +// "parallelrequest", +// async (ct) => { +// await Task.Delay(TimeSpan.FromSeconds(10), ct); +// return new Data() {Value = "myresponse"}; +// }, +// new JsonRpcHandlerOptions() {RequestProcessType = RequestProcessType.Parallel}); +// client.OnRequest( +// "serialrequest", +// async (ct) => new Data() {Value = "myresponse"}, +// new JsonRpcHandlerOptions() {RequestProcessType = RequestProcessType.Serial} +// ); +// }, +// server => { +// server.OnRequest( +// "parallelrequest", +// async (ct) => { +// await Task.Delay(TimeSpan.FromSeconds(10), ct); +// return new Data() {Value = "myresponse"}; +// }, +// new JsonRpcHandlerOptions() {RequestProcessType = RequestProcessType.Parallel}); +// server.OnRequest( +// "serialrequest", +// async (ct) => new Data() {Value = "myresponse"}, +// new JsonRpcHandlerOptions() {RequestProcessType = RequestProcessType.Serial} +// ); +// } +// ); + +// { +// var task = client.SendRequest("parallelrequest").Returning(CancellationToken); +// await client.SendRequest("serialrequest").Returning(CancellationToken); +// Func action = () => task; +// await action.Should().ThrowAsync(); +// } + +// { +// var task = server.SendRequest("parallelrequest").Returning(CancellationToken); +// await server.SendRequest("serialrequest").Returning(CancellationToken); +// Func action = () => task; +// await action.Should().ThrowAsync(); +// } +// } + +// [Fact] +// public async Task Should_Link_Request_A_to_Request_B() +// { +// var (client, server) = await Initialize( +// client => { +// client +// .OnRequest("myrequest", async () => new Data() {Value = "myresponse"}) +// .WithLink("myrequest", "myrequest2") +// ; +// }, +// server => { +// server +// .OnRequest("myrequest", async () => new Data() {Value = string.Join("", "myresponse".Reverse())}) +// .WithLink("myrequest", "myrequest2") +// ; +// } +// ); + +// var serverResponse = await client.SendRequest("myrequest2").Returning(CancellationToken); +// serverResponse.Value.Should().Be("esnopserym"); + +// var clientResponse = await server.SendRequest("myrequest2").Returning(CancellationToken); +// clientResponse.Value.Should().Be("myresponse"); +// } +// } +// }