提交 20daf121 编写于 作者: D David Wengier

Test mutating state and non-mutating interact as expected

上级 a07b9036
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.TextManager.Interop;
namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.RequestOrdering
{
internal abstract class AbstractTestRequestHandler : AbstractRequestHandler<OrderedLspRequest, OrderedLspResponse>
{
private const int Delay = 100;
public AbstractTestRequestHandler(ILspSolutionProvider solutionProvider)
: base(solutionProvider)
{
}
public override async Task<OrderedLspResponse> HandleRequestAsync(OrderedLspRequest request, RequestContext context, CancellationToken cancellationToken)
{
var response = new OrderedLspResponse();
response.RequestOrder = request.RequestOrder;
response.StartTime = DateTime.UtcNow;
await Task.Delay(Delay, cancellationToken).ConfigureAwait(false);
// some busy work
response.ToString();
await Task.Delay(Delay, cancellationToken).ConfigureAwait(false);
response.EndTime = DateTime.UtcNow;
return response;
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.RequestOrdering
{
[Shared, ExportLspMethod(MethodName, mutatesSolutionState: true)]
internal class MutatingRequestHandler : AbstractTestRequestHandler
{
public const string MethodName = nameof(MutatingRequestHandler);
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public MutatingRequestHandler(ILspSolutionProvider solutionProvider)
: base(solutionProvider)
{
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.RequestOrdering
{
[Shared, ExportLspMethod(MethodName, mutatesSolutionState: false)]
internal class NonMutatingRequestHandler : AbstractTestRequestHandler
{
public const string MethodName = nameof(NonMutatingRequestHandler);
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public NonMutatingRequestHandler(ILspSolutionProvider solutionProvider)
: base(solutionProvider)
{
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.RequestOrdering
{
internal class OrderedLspRequest
{
public string MethodName { get; }
public int RequestOrder { get; set; }
public OrderedLspRequest(string methodName)
{
MethodName = methodName;
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.RequestOrdering
{
internal class OrderedLspResponse
{
public int RequestOrder { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.RequestOrdering
{
public partial class RequestOrderingTests : AbstractLanguageServerProtocolTests
{
protected override TestComposition Composition => base.Composition
.AddParts(typeof(MutatingRequestHandler))
.AddParts(typeof(NonMutatingRequestHandler));
[Fact]
public async Task SerialRequestsDontOverlap()
{
var requests = new[] {
new OrderedLspRequest(MutatingRequestHandler.MethodName),
new OrderedLspRequest(MutatingRequestHandler.MethodName),
new OrderedLspRequest(MutatingRequestHandler.MethodName),
};
var responses = await TestAsync(requests);
// Every request should have started at or after the one before it
Assert.True(responses[1].StartTime >= responses[0].EndTime);
Assert.True(responses[2].StartTime >= responses[1].EndTime);
}
[Fact]
public async Task ParallelRequestsOverlap()
{
var requests = new[] {
new OrderedLspRequest(NonMutatingRequestHandler.MethodName),
new OrderedLspRequest(NonMutatingRequestHandler.MethodName),
new OrderedLspRequest(NonMutatingRequestHandler.MethodName),
};
var responses = await TestAsync(requests);
// Every request should have started immediately, without waiting
Assert.True(responses[1].StartTime < responses[0].EndTime);
Assert.True(responses[2].StartTime < responses[1].EndTime);
}
[Fact]
public async Task ParallelWaitsForSerial()
{
var requests = new[] {
new OrderedLspRequest(MutatingRequestHandler.MethodName),
new OrderedLspRequest(NonMutatingRequestHandler.MethodName),
new OrderedLspRequest(NonMutatingRequestHandler.MethodName),
};
var responses = await TestAsync(requests);
// The parallel tasks should have waited for the first task to finish
Assert.True(responses[1].StartTime >= responses[0].EndTime);
Assert.True(responses[2].StartTime >= responses[0].EndTime);
// The parallel requests shouldn't have waited for each other
Assert.True(responses[1].StartTime < responses[2].EndTime);
Assert.True(responses[2].StartTime < responses[1].EndTime);
}
private async Task<OrderedLspResponse[]> TestAsync(OrderedLspRequest[] requests)
{
using var workspace = CreateTestWorkspace("class C { }", out _);
var solution = workspace.CurrentSolution;
var languageServer = GetLanguageServer(solution);
var clientCapabilities = new LSP.ClientCapabilities();
var waitables = new List<Task<OrderedLspResponse>>();
var order = 1;
foreach (var request in requests)
{
request.RequestOrder = order++;
waitables.Add(languageServer.ExecuteRequestAsync<OrderedLspRequest, OrderedLspResponse>(request.MethodName, request, clientCapabilities, null, CancellationToken.None));
}
var responses = await Task.WhenAll(waitables);
// Sanity checks to ensure test handlers aren't doing something wacky, making future checks invalid
Assert.Empty(responses.Where(r => r.StartTime == default));
Assert.All(responses, r => Assert.True(r.EndTime > r.StartTime));
return responses;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册