Skip to content

Commit

Permalink
Move ITs to use SLCoreHandle, fix bug with double StartListening call (
Browse files Browse the repository at this point in the history
…#5300)

Part of #5291
  • Loading branch information
1 parent e0344b6 commit b1c875b
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 144 deletions.
4 changes: 2 additions & 2 deletions src/SLCore.IntegrationTests/DependencyLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace SonarLint.VisualStudio.SLCore.IntegrationTests;
public class DependencyLocator // this might be reused in the product code in the future
{
public static List<string> AnalyzerPlugins { get; private set; }
public static string Sloop { get; private set; }
public static string SloopBatPath { get; private set; }

static DependencyLocator()
{
Expand Down Expand Up @@ -71,7 +71,7 @@ private static void EnsureSloopIsAvailable(string localAppData, XmlDocument depe
throw new InvalidOperationException($"Can't locate SLOOP {sloopVersion}");
}

Sloop = sloopPath;
SloopBatPath = sloopPath;
}

private static string GetAnalyzerPath(string analyzerFileName, string analyzerVersion, string[] analyzerJars)
Expand Down
2 changes: 1 addition & 1 deletion src/SLCore.IntegrationTests/InitializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public async Task Sloop_ConfigScopeSetAndUnsetWithoutErrors()
slCoreTestRunner.AddListener(analysisListener);
await slCoreTestRunner.Start();

var activeConfigScopeTracker = new ActiveConfigScopeTracker(slCoreTestRunner.SlCoreServiceProvider,
var activeConfigScopeTracker = new ActiveConfigScopeTracker(slCoreTestRunner.SLCoreServiceProvider,
new AsyncLockFactory(),
new NoOpThreadHandler());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ public async Task CheckAllEmbeddedRules()
var testLogger = new TestLogger();
using var slCoreTestRunner = new SLCoreTestRunner(testLogger, TestContext.TestName);
slCoreTestRunner.AddListener(new LoggerListener(testLogger));
await slCoreTestRunner.Start();

var ruleHelpXamlBuilder = CreateRuleHelpXamlBuilder();
var activeConfigScopeTracker = CreateActiveConfigScopeTracker(slCoreTestRunner);
var slCoreRuleMetaDataProvider = CreateSlCoreRuleMetaDataProvider(slCoreTestRunner, activeConfigScopeTracker, testLogger);
var ruleHelpXamlBuilder = CreateRuleHelpXamlBuilder();

await slCoreTestRunner.Start();
activeConfigScopeTracker.SetCurrentConfigScope(configScope);
slCoreTestRunner.SlCoreServiceProvider.TryGetTransientService(out IRulesSLCoreService rulesSlCoreService).Should().BeTrue();
slCoreTestRunner.SLCoreServiceProvider.TryGetTransientService(out IRulesSLCoreService rulesSlCoreService).Should().BeTrue();

// no hotspots are returned from ListAllStandaloneRulesDefinitionsAsync
var ruleDescriptions = await GetAllRuleDescriptions(await rulesSlCoreService.ListAllStandaloneRulesDefinitionsAsync(), slCoreRuleMetaDataProvider);
Expand Down Expand Up @@ -125,12 +125,12 @@ private static void CheckRuleDescription(FlowDocument doc)

private static SLCoreRuleMetaDataProvider CreateSlCoreRuleMetaDataProvider(SLCoreTestRunner slCoreTestRunner,
IActiveConfigScopeTracker activeConfigScopeTracker, ILogger testLogger) =>
new(slCoreTestRunner.SlCoreServiceProvider,
new(slCoreTestRunner.SLCoreServiceProvider,
activeConfigScopeTracker,
testLogger);

private static ActiveConfigScopeTracker CreateActiveConfigScopeTracker(SLCoreTestRunner slCoreTestRunner) =>
new(slCoreTestRunner.SlCoreServiceProvider,
new(slCoreTestRunner.SLCoreServiceProvider,
new AsyncLockFactory(),
new NoOpThreadHandler());

Expand Down
120 changes: 63 additions & 57 deletions src/SLCore.IntegrationTests/SLCoreTestProcessRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,88 +19,104 @@
*/

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading;
using Microsoft.VisualStudio.Threading;
using SonarLint.VisualStudio.SLCore.Configuration;
using SonarLint.VisualStudio.SLCore.Core;
using SonarLint.VisualStudio.SLCore.Core.Process;
using SonarLint.VisualStudio.SLCore.Protocol;

namespace SonarLint.VisualStudio.SLCore.IntegrationTests;

[ExcludeFromCodeCoverage]
public sealed class SLCoreTestProcessRunner : IDisposable
class SLCoreTestProcessFactory : ISLCoreProcessFactory
{
private readonly string rpcLogFilePath;
private readonly string stdErrLogFilePath;
private readonly string stdErrLogPath;
private readonly string rpcLogPath;
private readonly bool enableVerboseLogs;
private readonly bool enableAutoFlush;
private readonly ISLCoreProcessFactory slCoreProcessFactory = new SLCoreProcessFactory();
private readonly SLCoreLaunchParameters launchParameters;
private ISLCoreProcess process;
private readonly CancellationTokenSource cancellationTokenSource = new();
private JsonRpcWrapper jsonRpcWrapper;
private StreamWriter logFileStream;
private StreamWriter errorFileStream;

internal ISLCoreJsonRpc Rpc { get; private set; }

private readonly ISLCoreProcessFactory slCoreProcessFactory;

public SLCoreTestProcessRunner(string pathToBat,
string rpcLogFilePath = null,
string stdErrLogFilePath = null,
bool enableVerboseLogs = false,
bool enableAutoFlush = false)
public SLCoreTestProcessFactory(ISLCoreProcessFactory slCoreProcessFactory, string stdErrLogPath = null, string rpcLogPath = null, bool enableVerboseLogs = false)
{
launchParameters = new SLCoreLaunchParameters("cmd.exe", $"/c {pathToBat}");
this.rpcLogFilePath = rpcLogFilePath;
this.stdErrLogFilePath = stdErrLogFilePath;
this.slCoreProcessFactory = slCoreProcessFactory;
this.stdErrLogPath = stdErrLogPath;
this.rpcLogPath = rpcLogPath;
this.enableVerboseLogs = enableVerboseLogs;
this.enableAutoFlush = enableAutoFlush;

}

public void Start()
public ISLCoreProcess StartNewProcess(SLCoreLaunchParameters slCoreLaunchParameters)
{
process = slCoreProcessFactory.StartNewProcess(launchParameters);
jsonRpcWrapper = (JsonRpcWrapper)process.AttachJsonRpc();

SetUpLogging();

jsonRpcWrapper.TraceSource.Switch.Level = enableVerboseLogs ? SourceLevels.Verbose : SourceLevels.Warning;
jsonRpcWrapper.TraceSource.Listeners.Add(logFileStream == null ? new ConsoleTraceListener() : new TextWriterTraceListener(logFileStream));

Rpc = new SLCoreJsonRpc(jsonRpcWrapper, new RpcMethodNameTransformer());
var slCoreTestProcess = new SLCoreTestProcess(slCoreProcessFactory.StartNewProcess(slCoreLaunchParameters), stdErrLogPath, rpcLogPath, enableVerboseLogs);
return slCoreTestProcess;
}
}

class SLCoreTestProcess : ISLCoreProcess
{
private readonly string stdErrLogPath;
private readonly bool enableVerboseLogs;
private readonly ISLCoreProcess slCoreProcess;
private readonly StreamWriter logFileStream;
private readonly CancellationTokenSource errorLogReaderCancellation = new CancellationTokenSource();
private StreamWriter errorFileStream;

private void SetUpLogging()
public SLCoreTestProcess(ISLCoreProcess slCoreProcess,
string stdErrLogPath = null,
string rpcLogFilePath = null,
bool enableVerboseLogs = false)
{
this.slCoreProcess = slCoreProcess;
this.stdErrLogPath = stdErrLogPath;
this.enableVerboseLogs = enableVerboseLogs;


if (!string.IsNullOrEmpty(rpcLogFilePath))
{
logFileStream = new StreamWriter(File.OpenWrite(rpcLogFilePath));
logFileStream.AutoFlush = enableAutoFlush;
logFileStream.AutoFlush = true;
}

Task.Run(ReadErrorLog).Forget();
Task.Run(ReadErrorLog);
}

public void Dispose()
{
slCoreProcess.Dispose();
errorLogReaderCancellation.Cancel();
errorLogReaderCancellation.Dispose();
errorFileStream.Dispose();
}

private void ReadErrorLog()
public StreamReader ErrorStreamReader => slCoreProcess?.ErrorStreamReader;

public IJsonRpc AttachJsonRpc()
{
var token = cancellationTokenSource.Token;
var fileLoggingEnabled = stdErrLogFilePath != null;
var prefix = fileLoggingEnabled ? string.Empty : "ERR: ";
errorFileStream = fileLoggingEnabled ? new StreamWriter(File.OpenWrite(stdErrLogFilePath)){AutoFlush = enableAutoFlush} : null;
var jsonRpc = slCoreProcess.AttachJsonRpc();

var jsonRpcWrapper = jsonRpc as JsonRpcWrapper;

jsonRpcWrapper.TraceSource.Switch.Level = enableVerboseLogs ? SourceLevels.Verbose : SourceLevels.Warning;
jsonRpcWrapper.TraceSource.Listeners.Add(logFileStream == null ? new ConsoleTraceListener() : new TextWriterTraceListener(logFileStream));

return jsonRpc;
}

private void ReadErrorLog()
{
var token = errorLogReaderCancellation.Token;
var fileLoggingEnabled = stdErrLogPath != null;
var prefix = fileLoggingEnabled ? string.Empty : "ERR: ";
errorFileStream = fileLoggingEnabled ? new StreamWriter(File.OpenWrite(stdErrLogPath)){AutoFlush = true} : null;


while (!token.IsCancellationRequested)
{
var line = process.ErrorStreamReader.ReadLine();
var line = ErrorStreamReader.ReadLine();
if (string.IsNullOrEmpty(line)) // potential problem here if it returns too often?
{
continue;
}

if (fileLoggingEnabled)
{
errorFileStream.WriteLine(line);
Expand All @@ -111,14 +127,4 @@ private void ReadErrorLog()
}
}
}

public void Dispose()
{
cancellationTokenSource?.Cancel();
cancellationTokenSource?.Dispose();
jsonRpcWrapper?.Dispose();
process?.Dispose();
logFileStream?.Dispose();
errorFileStream?.Dispose();
}
}
Loading

0 comments on commit b1c875b

Please sign in to comment.