Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RunTestsInContext Command #1782

Merged
merged 14 commits into from
May 11, 2020
Merged
2 changes: 1 addition & 1 deletion .pipelines/init.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
parameters:
# Configuration: Release
Verbosity: Normal
DotNetVersion: "3.0.100"
DotNetVersion: "3.1.201"
CakeVersion: "0.32.1"
NuGetVersion: "4.9.2"
steps:
Expand Down
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ resources:

variables:
Verbosity: Diagnostic
DotNetVersion: "3.0.100"
DotNetVersion: "3.1.201"
CakeVersion: "0.32.1"
NuGetVersion: "4.9.2"
GitVersionVersion: "5.0.1"
Expand Down
2 changes: 1 addition & 1 deletion build.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"DotNetInstallScriptURL": "https://dot.net/v1",
"DotNetChannel": "Preview",
"DotNetVersions": [
"3.0.100",
"3.1.201",
"5.0.100-preview.2.20169.1"
],
"RequiredMonoVersion": "6.6.0",
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"sdk": {
"version": "3.0.100"
"version": "3.1.201"
}
}
2 changes: 2 additions & 0 deletions src/OmniSharp.Abstractions/OmniSharpEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ public static class V2
public const string RunAllTestsInClass = "/v2/runtestsinclass";
public const string DebugTestGetStartInfo = "/v2/debugtest/getstartinfo";
public const string DebugTestLaunch = "/v2/debugtest/launch";
public const string DebugTestsInContextGetStartInfo = "/v2/debugtestsincontext/getstartinfo";
public const string DebugTestStop = "/v2/debugtest/stop";
public const string DebugTestsInClassGetStartInfo = "/v2/debugtestsinclass/getstartinfo";
public const string RunTestsInContext = "/v2/runtestsincontext";

public const string BlockStructure = "/v2/blockstructure";
public const string CodeStructure = "/v2/codestructure";
Expand Down
12 changes: 11 additions & 1 deletion src/OmniSharp.DotNetTest/DebugSessionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using OmniSharp.DotNetTest.Models;
using OmniSharp.Utilities;
Expand Down Expand Up @@ -77,9 +78,18 @@ public void EndSession()
}
}

#nullable enable
public Task<DebugTestGetStartInfoResponse> DebugGetStartInfoAsync(int line, int column, Document contextDocument, string? runSettings, string? targetFrameworkVersion, CancellationToken cancellationToken)
{
VerifySession(isStarted: true);

return _testManager.DebugGetStartInfoAsync(line, column, contextDocument, runSettings, targetFrameworkVersion, cancellationToken);
}
#nullable restore

public Task<DebugTestGetStartInfoResponse> DebugGetStartInfoAsync(string methodName, string runSettings, string testFrameworkName, string targetFrameworkVersion, CancellationToken cancellationToken)
=> DebugGetStartInfoAsync(new string[] { methodName }, runSettings, testFrameworkName, targetFrameworkVersion, cancellationToken);

public Task<DebugTestGetStartInfoResponse> DebugGetStartInfoAsync(string[] methodNames, string runSettings, string testFrameworkName, string targetFrameworkVersion, CancellationToken cancellationToken)
{
VerifySession(isStarted: true);
Expand Down
17 changes: 17 additions & 0 deletions src/OmniSharp.DotNetTest/Models/BaseTestsInContextRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

#nullable enable

using OmniSharp.Mef;
using OmniSharp.Models;

namespace OmniSharp.DotNetTest.Models
{
public abstract class BaseTestsInContextRequest : Request
{
public string? RunSettings { get; set; }
/// <summary>
/// e.g. .NETCoreApp, Version=2.0
/// </summary>
public string? TargetFrameworkVersion { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

#nullable enable

using OmniSharp.Mef;

namespace OmniSharp.DotNetTest.Models
{
[OmniSharpEndpoint(OmniSharpEndpoints.V2.DebugTestsInContextGetStartInfo, typeof(DebugTestsInContextGetStartInfoRequest), typeof(DebugTestGetStartInfoResponse))]
public class DebugTestsInContextGetStartInfoRequest : BaseTestsInContextRequest
{
}
}
11 changes: 11 additions & 0 deletions src/OmniSharp.DotNetTest/Models/RunTestsInContextRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#nullable enable

using OmniSharp.Mef;

namespace OmniSharp.DotNetTest.Models
{
[OmniSharpEndpoint(OmniSharpEndpoints.V2.RunTestsInContext, typeof(RunTestsInContextRequest), typeof(RunTestResponse))]
public class RunTestsInContextRequest : BaseTestsInContextRequest
{
}
}
11 changes: 4 additions & 7 deletions src/OmniSharp.DotNetTest/Services/BaseTestService`2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,12 @@ protected BaseTestService(OmniSharpWorkspace workspace, IDotNetCliService dotNet
{
}

protected abstract TResponse HandleRequest(TRequest request, TestManager testManager);
protected abstract Task<TResponse> HandleRequest(TRequest request, TestManager testManager);

public Task<TResponse> Handle(TRequest request)
public async Task<TResponse> Handle(TRequest request)
{
using (var testManager = CreateTestManager(request.FileName))
{
var response = HandleRequest(request, testManager);
return Task.FromResult(response);
}
using var testManager = CreateTestManager(request.FileName);
return await HandleRequest(request, testManager);
}
}
}
2 changes: 1 addition & 1 deletion src/OmniSharp.DotNetTest/Services/DebugTestService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal class DebugTestService : BaseTestService,
IRequestHandler<DebugTestLaunchRequest, DebugTestLaunchResponse>,
IRequestHandler<DebugTestStopRequest, DebugTestStopResponse>
{
private DebugSessionManager _debugSessionManager;
private readonly DebugSessionManager _debugSessionManager;

[ImportingConstructor]
public DebugTestService(DebugSessionManager debugSessionManager, OmniSharpWorkspace workspace, IDotNetCliService dotNetCli, IEventEmitter eventEmitter, ILoggerFactory loggerFactory)
Expand Down
45 changes: 45 additions & 0 deletions src/OmniSharp.DotNetTest/Services/DebugTestsInContextService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#nullable enable

using System;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using OmniSharp.DotNetTest.Models;
using OmniSharp.Eventing;
using OmniSharp.Mef;
using OmniSharp.Services;

namespace OmniSharp.DotNetTest.Services
{
[Shared]
[OmniSharpHandler(OmniSharpEndpoints.V2.DebugTestsInContextGetStartInfo, LanguageNames.CSharp)]
internal class DebugTestsInContextService : BaseTestService,
IRequestHandler<DebugTestsInContextGetStartInfoRequest, DebugTestGetStartInfoResponse>
{
private readonly DebugSessionManager _debugSessionManager;

[ImportingConstructor]
public DebugTestsInContextService(DebugSessionManager debugSessionManager, OmniSharpWorkspace workspace, IDotNetCliService dotNetCli, IEventEmitter eventEmitter, ILoggerFactory loggerFactory)
: base(workspace, dotNetCli, eventEmitter, loggerFactory)
{
_debugSessionManager = debugSessionManager;
}

public Task<DebugTestGetStartInfoResponse> Handle(DebugTestsInContextGetStartInfoRequest request)
{
var testManager = CreateTestManager(request.FileName);
if (testManager.IsConnected)
{
_debugSessionManager.StartSession(testManager);
return _debugSessionManager.DebugGetStartInfoAsync(
request.Line, request.Column, Workspace.GetDocument(request.FileName),
request.RunSettings, request.TargetFrameworkVersion,
CancellationToken.None);
}

throw new InvalidOperationException("The debugger could not be started");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These seem unfortunate, especially for the InContext version of the command, but the existing DebugTestGetStartInfoResponse doesn't have a place for a failure and failure message. I would have modified that to add a field, but I'm unsure if that will break existing clients. Is that a safe change to make, or should I add a new response that adds a failure/reason to it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sure whether this would be a problem for other clients. Maybe @filipw knows definitively.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should be fine - additive changes are generally fine since it's json based.
moreover, the debug tests protocl is - I am pretty sure - only used by VS Code extension since the debugger is proprietary

}
}
}
5 changes: 3 additions & 2 deletions src/OmniSharp.DotNetTest/Services/GetTestStartInfoService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Composition;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using OmniSharp.DotNetTest.Models;
Expand All @@ -17,9 +18,9 @@ public GetTestStartInfoService(OmniSharpWorkspace workspace, IDotNetCliService d
{
}

protected override GetTestStartInfoResponse HandleRequest(GetTestStartInfoRequest request, TestManager testManager)
protected override Task<GetTestStartInfoResponse> HandleRequest(GetTestStartInfoRequest request, TestManager testManager)
{
return testManager.GetTestStartInfo(request.MethodName, request.RunSettings, request.TestFrameworkName, request.TargetFrameworkVersion);
return testManager.GetTestStartInfoAsync(request.MethodName, request.RunSettings, request.TestFrameworkName, request.TargetFrameworkVersion, cancellationToken: default);
}
}
}
8 changes: 5 additions & 3 deletions src/OmniSharp.DotNetTest/Services/RunTestService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using OmniSharp.DotNetTest.Models;
Expand All @@ -17,11 +19,11 @@ public RunTestService(OmniSharpWorkspace workspace, IDotNetCliService dotNetCli,
{
}

protected override RunTestResponse HandleRequest(RunTestRequest request, TestManager testManager)
protected override Task<RunTestResponse> HandleRequest(RunTestRequest request, TestManager testManager)
{
if (testManager.IsConnected)
{
return testManager.RunTest(request.MethodName, request.RunSettings, request.TestFrameworkName, request.TargetFrameworkVersion);
return testManager.RunTestAsync(request.MethodName, request.RunSettings, request.TestFrameworkName, request.TargetFrameworkVersion, CancellationToken.None);
}

var response = new RunTestResponse
Expand All @@ -30,7 +32,7 @@ protected override RunTestResponse HandleRequest(RunTestRequest request, TestMan
Pass = false
};

return response;
return Task.FromResult(response);
}
}
}
6 changes: 4 additions & 2 deletions src/OmniSharp.DotNetTest/Services/RunTestsInClassService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using OmniSharp.DotNetTest.Models;
Expand All @@ -17,11 +19,11 @@ public RunTestsInClassService(OmniSharpWorkspace workspace, IDotNetCliService do
{
}

protected override RunTestResponse HandleRequest(RunTestsInClassRequest request, TestManager testManager)
protected override async Task<RunTestResponse> HandleRequest(RunTestsInClassRequest request, TestManager testManager)
{
if (testManager.IsConnected)
{
return testManager.RunTest(request.MethodNames, request.RunSettings, request.TestFrameworkName, request.TargetFrameworkVersion);
return await testManager.RunTestAsync(request.MethodNames, request.RunSettings, request.TestFrameworkName, request.TargetFrameworkVersion, CancellationToken.None);
}

var response = new RunTestResponse
Expand Down
43 changes: 43 additions & 0 deletions src/OmniSharp.DotNetTest/Services/RunTestsInContextService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#nullable enable

using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using OmniSharp.DotNetTest.Models;
using OmniSharp.Eventing;
using OmniSharp.Mef;
using OmniSharp.Services;

namespace OmniSharp.DotNetTest.Services
{
[OmniSharpHandler(OmniSharpEndpoints.V2.RunTestsInContext, LanguageNames.CSharp)]
internal class RunTestsInContextService : BaseTestService, IRequestHandler<RunTestsInContextRequest, RunTestResponse>
{
[ImportingConstructor]
public RunTestsInContextService(OmniSharpWorkspace workspace, IDotNetCliService dotNetCli, IEventEmitter eventEmitter, ILoggerFactory loggerFactory)
: base(workspace, dotNetCli, eventEmitter, loggerFactory)
{
}

public async Task<RunTestResponse> Handle(RunTestsInContextRequest request)
{
var document = Workspace.GetDocument(request.FileName);
using var testManager = TestManager.Start(document.Project, DotNetCli, EventEmitter, LoggerFactory);

if (testManager.IsConnected)
{
return await testManager.RunTestsInContextAsync(request.Line, request.Column, document, request.RunSettings, request.TargetFrameworkVersion, CancellationToken.None);
}

var response = new RunTestResponse
{
Failure = "Failed to connect to 'dotnet test' process",
Pass = false
};

return response;
}
}
}
2 changes: 1 addition & 1 deletion src/OmniSharp.DotNetTest/TestFeaturesDiscover.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public IEnumerable<SyntaxFeature> Discover(SyntaxNode node, SemanticModel semant
{
if (node is MethodDeclarationSyntax method)
{
foreach (var framework in TestFramework.GetFrameworks())
foreach (var framework in TestFramework.Frameworks)
{
if (framework.IsTestMethod(method, semanticModel))
{
Expand Down
30 changes: 14 additions & 16 deletions src/OmniSharp.DotNetTest/TestFrameworks/TestFramework.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,36 @@ namespace OmniSharp.DotNetTest.TestFrameworks
{
internal abstract class TestFramework
{
private static readonly ImmutableDictionary<string, TestFramework> s_frameworks;

static TestFramework()
{
var builder = ImmutableDictionary.CreateBuilder<string, TestFramework>();
var builder = ImmutableArray.CreateBuilder<TestFramework>();

var nunit = new NUnitTestFramework();
var xunit = new XunitTestFramework();
var mstest = new MSTestFramework();

builder.Add(nunit.Name, nunit);
builder.Add(xunit.Name, xunit);
builder.Add(mstest.Name, mstest);
builder.Add(nunit);
builder.Add(xunit);
builder.Add(mstest);

s_frameworks = builder.ToImmutable();
Frameworks = builder.ToImmutable();
}

public static TestFramework GetFramework(string name)
{
return s_frameworks.TryGetValue(name, out var result)
? result
: null;
}

public static IEnumerable<TestFramework> GetFrameworks()
{
foreach (var kvp in s_frameworks)
foreach (var framework in Frameworks)
{
yield return kvp.Value;
if (framework.Name == name)
{
return framework;
}
}

return null;
}

public static ImmutableArray<TestFramework> Frameworks { get; }

public abstract string FeatureName { get; }
public abstract string Name { get; }
public abstract string MethodArgument { get; }
Expand Down
Loading