From e76329965a10be141f0fc4cfa814837416ab82d4 Mon Sep 17 00:00:00 2001 From: MchKosticyn Date: Fri, 3 Feb 2023 16:16:37 +0300 Subject: [PATCH] [fix] fixes and logging - fixed working directory of V# process - added logging from V# --- .../rdgen/org/utbot/rd/models/CSharpModel.kt | 1 + .../Generated/VSharpModel.Generated.cs | 13 +++++- .../dotnet/UtBot/UtBot.VSharp/VSharpMain.cs | 31 ++++++++++--- .../dotnet/UtBot/UtBot/ProcessWithRdServer.cs | 43 ++++++++++++------- .../src/dotnet/UtBot/UtBot/UnitTestBuilder.cs | 19 ++++---- 5 files changed, 75 insertions(+), 32 deletions(-) diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/CSharpModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/CSharpModel.kt index 309293be6e..3fc887812b 100644 --- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/CSharpModel.kt +++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/CSharpModel.kt @@ -30,5 +30,6 @@ object VSharpModel: Ext(CSharpRoot) { init { call("generate", generateArguments, generateResults).async signal("ping", PredefinedType.string).async + signal("log", PredefinedType.string).async } } \ No newline at end of file diff --git a/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/VSharpModel.Generated.cs b/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/VSharpModel.Generated.cs index be44a137a9..02aa214927 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/VSharpModel.Generated.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/VSharpModel.Generated.cs @@ -44,31 +44,39 @@ public class VSharpModel : RdExtBase //public fields [NotNull] public RdCall Generate => _Generate; [NotNull] public ISignal Ping => _Ping; + [NotNull] public ISignal Log => _Log; //private fields [NotNull] private readonly RdCall _Generate; [NotNull] private readonly RdSignal _Ping; + [NotNull] private readonly RdSignal _Log; //primary constructor private VSharpModel( [NotNull] RdCall generate, - [NotNull] RdSignal ping + [NotNull] RdSignal ping, + [NotNull] RdSignal log ) { if (generate == null) throw new ArgumentNullException("generate"); if (ping == null) throw new ArgumentNullException("ping"); + if (log == null) throw new ArgumentNullException("log"); _Generate = generate; _Ping = ping; + _Log = log; _Generate.Async = true; _Ping.Async = true; + _Log.Async = true; BindableChildren.Add(new KeyValuePair("generate", _Generate)); BindableChildren.Add(new KeyValuePair("ping", _Ping)); + BindableChildren.Add(new KeyValuePair("log", _Log)); } //secondary constructor private VSharpModel ( ) : this ( new RdCall(GenerateArguments.Read, GenerateArguments.Write, GenerateResults.Read, GenerateResults.Write), + new RdSignal(JetBrains.Rd.Impl.Serializers.ReadString, JetBrains.Rd.Impl.Serializers.WriteString), new RdSignal(JetBrains.Rd.Impl.Serializers.ReadString, JetBrains.Rd.Impl.Serializers.WriteString) ) {} //deconstruct trait @@ -76,7 +84,7 @@ private VSharpModel ( - protected override long SerializationHash => -2362293640438957269L; + protected override long SerializationHash => -5982678710127900748L; protected override Action Register => RegisterDeclaredTypesSerializers; public static void RegisterDeclaredTypesSerializers(ISerializers serializers) @@ -104,6 +112,7 @@ public override void Print(PrettyPrinter printer) using (printer.IndentCookie()) { printer.Print("generate = "); _Generate.PrintEx(printer); printer.Println(); printer.Print("ping = "); _Ping.PrintEx(printer); printer.Println(); + printer.Print("log = "); _Log.PrintEx(printer); printer.Println(); } printer.Print(")"); } diff --git a/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/VSharpMain.cs b/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/VSharpMain.cs index e58d1b8f86..36a8d63320 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/VSharpMain.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/VSharpMain.cs @@ -4,6 +4,7 @@ using System.IO; using System.Reflection; using System.Runtime.Loader; +using System.Text; using JetBrains.Collections.Viewable; using JetBrains.Lifetimes; using JetBrains.Rd; @@ -13,9 +14,7 @@ using UtBot.Rd; using UtBot.Rd.Generated; using VSharp; -using VSharp.System; using VSharp.TestRenderer; -using Thread = System.Threading.Thread; namespace UtBot.VSharp; @@ -23,6 +22,27 @@ public static class VSharpMain { public static readonly string VSharpProcessName = "VSharp"; + private class SignalWriter : TextWriter + { + private readonly ISignal _signal; + public SignalWriter(ISignal signal) + { + _signal = signal; + } + + public override void Write(string value) + { + _signal.Fire(value); + } + + public override void WriteLine(string value) + { + Write(value); + } + + public override Encoding Encoding => Encoding.Default; + } + private static GenerateResults GenerateImpl(GenerateArguments arguments) { var (assemblyPath, projectCsprojPath, solutionFilePath, @@ -40,7 +60,7 @@ private static GenerateResults GenerateImpl(GenerateArguments arguments) if (methodInfo?.Name != descriptor.MethodName) throw new InvalidDataException( $"cannot find method - ${descriptor.MethodName} for type - ${descriptor.TypeName}"); - var stat = TestGenerator.Cover(methodInfo, generationTimeout); + var stat = TestGenerator.Cover(methodInfo, generationTimeout, verbosity:Verbosity.Info); var targetProject = new FileInfo(projectCsprojPath); var solution = new FileInfo(solutionFilePath); var declaringType = methodInfo.DeclaringType; @@ -48,7 +68,6 @@ private static GenerateResults GenerateImpl(GenerateArguments arguments) var (generatedProject, renderedFiles) = Renderer.Render(stat.Results(), targetProject, declaringType, assemblyLoadContext, solution, targetFramework); return new GenerateResults(true, generatedProject.FullName, renderedFiles.ToArray(), null); - ; } public static void Main(string[] args) @@ -65,6 +84,8 @@ public static void Main(string[] args) scheduler.Queue(() => { var vSharpModel = new VSharpModel(ldef.Lifetime, protocol); + // Configuring V# logger: messages will be send via RD to UTBot plugin process + Logger.ConfigureWriter(new SignalWriter(vSharpModel.Log)); vSharpModel.Generate.Set((_, arguments) => { try @@ -94,4 +115,4 @@ public static void Main(string[] args) // Thread.Sleep(1000); ldef.Terminate(); } -} \ No newline at end of file +} diff --git a/utbot-rider/src/dotnet/UtBot/UtBot/ProcessWithRdServer.cs b/utbot-rider/src/dotnet/UtBot/UtBot/ProcessWithRdServer.cs index 24d054c577..31ff5bea3f 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot/ProcessWithRdServer.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot/ProcessWithRdServer.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Net; +using JetBrains.Annotations; using JetBrains.Application.Threading; using JetBrains.Collections.Viewable; using JetBrains.Lifetimes; @@ -11,6 +12,7 @@ using JetBrains.Threading; using JetBrains.Util; using JetBrains.Util.Logging; +using UtBot.Rd; using UtBot.Rd.Generated; namespace UtBot; @@ -20,14 +22,14 @@ public class ProcessWithRdServer { public Lifetime Lifetime => _ldef.Lifetime; public Protocol Protocol; - public VSharpModel VSharpModel { get; private set; } - + [CanBeNull] public VSharpModel VSharpModel { get; private set; } + private readonly LifetimeDefinition _ldef; - private Process _process; - private ILogger _logger = Logger.GetLogger(); + [CanBeNull] private Process _process; - public ProcessWithRdServer(string name, string workingDir, int port, string exePath, IShellLocks shellLocks, Lifetime? parent = null) + public ProcessWithRdServer(string name, string workingDir, int port, string exePath, IShellLocks shellLocks, Lifetime? parent = null, [CanBeNull] ILogger logger = null) { + logger ??= Logger.GetLogger(); using var blockingCollection = new BlockingCollection(2); shellLocks.AssertNonMainThread(); _ldef = (parent ?? Lifetime.Eternal).CreateNested(); @@ -41,9 +43,11 @@ public ProcessWithRdServer(string name, string workingDir, int port, string exeP var wire = new SocketWire.Server(Lifetime, scheduler, socket); var serializers = new Serializers(); var identities = new Identities(IdKind.Server); - var startInfo = new ProcessStartInfo("dotnet", $"\"{exePath}\" {port}"); - - startInfo.WorkingDirectory = workingDir; + var startInfo = new ProcessStartInfo("dotnet", $"\"{exePath}\" {port}") + { + WorkingDirectory = workingDir + }; + Protocol = new Protocol(name, serializers, identities, scheduler, wire, Lifetime); scheduler.Queue(() => { @@ -55,6 +59,7 @@ public ProcessWithRdServer(string name, string workingDir, int port, string exeP blockingCollection.TryAdd(s); } }); + VSharpModel.Log.Advise(Lifetime, s => logger.Info($"V#: {s}")); }); _process = new Process(); _process.StartInfo = startInfo; @@ -64,15 +69,21 @@ public ProcessWithRdServer(string name, string workingDir, int port, string exeP else _ldef.Terminate(); }); - if (_process?.HasExited == false) + + if (_process?.HasExited == true) return; + + SpinWaitEx.SpinUntil(pingLdef.Lifetime, () => { - SpinWaitEx.SpinUntil(pingLdef.Lifetime, () => + if (_process?.HasExited == true) { - VSharpModel?.Ping.Fire("UtBot"); - return blockingCollection.TryTake(out _); - }); - pingLdef.Terminate(); - } + VSharpModel = null; + _ldef.Terminate(); + } + + VSharpModel?.Ping.Fire(RdUtil.MainProcessName); + return blockingCollection.TryTake(out _); + }); + pingLdef.Terminate(); } catch (Exception) { @@ -80,4 +91,4 @@ public ProcessWithRdServer(string name, string workingDir, int port, string exeP throw; } } -} \ No newline at end of file +} diff --git a/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestBuilder.cs b/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestBuilder.cs index 2c57d745ab..fd5e06c873 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestBuilder.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestBuilder.cs @@ -118,17 +118,18 @@ private void Generate(IBackgroundProgressIndicator progressIndicator, IProject p _logger.Catch(() => { + var name = VSharpMain.VSharpProcessName; + var workingDir = project.ProjectFileLocation.Directory.FullPath; var port = NetworkUtil.GetFreePort(); - var proc = new ProcessWithRdServer(VSharpMain.VSharpProcessName, project.ProjectFileLocation.FullPath, port, vsharpRunner.FullPath, - project.Locks, - _lifetime); + var runnerPath = vsharpRunner.FullPath; + var proc = new ProcessWithRdServer(name, workingDir, port, runnerPath, project.Locks, _lifetime, _logger); var projectCsprojPath = project.ProjectFileLocation.FullPath; - var vsharpProjectTarget = calculateTestProjectTarget(tfm); + var vSharpProjectTarget = calculateTestProjectTarget(tfm); var args = new GenerateArguments(assemblyPath.FullPath, projectCsprojPath, solutionFilePath, descriptor, - GenerationTimeout, vsharpProjectTarget); - var result = proc.VSharpModel.Generate.Sync(args, RpcTimeouts.Maximal); + GenerationTimeout, vSharpProjectTarget); + var result = proc.VSharpModel?.Generate.Sync(args, RpcTimeouts.Maximal); _logger.Info("Result acquired"); - if (result.IsGenerated) + if (result is { IsGenerated: true }) { _shellLocks.ExecuteOrQueue(_lifetime, "UnitTestBuilder::Generate", () => { @@ -142,8 +143,8 @@ private void Generate(IBackgroundProgressIndicator progressIndicator, IProject p } else { - _logger.Info( - $"Could not generate tests for ${currentGeneratedItem}, exception - ${result.ExceptionMessage}"); + var ex = result == null ? "Could not start V#" : result.ExceptionMessage; + _logger.Info($"Could not generate tests for ${currentGeneratedItem}, exception - {ex}"); } });