private static void CopyFiles(RunStartParams rsp, string solutionGrandParentPath, string folder, SearchOption searchOpt) { if (!new DirectoryInfo(folder).Exists) { return; } foreach (var src in Directory.EnumerateFiles(folder, "*", searchOpt)) { var shouldExlclude = rsp.Config.SnapshotExcludePatterns.Any(item => src.IndexOf(item, 0, StringComparison.OrdinalIgnoreCase) >= 0); if (shouldExlclude) { continue; } var dst = src.ToUpperInvariant().Replace(solutionGrandParentPath.ToUpperInvariant(), rsp.Config.SnapShotRoot); var srcInfo = new FileInfo(src); var dstInfo = new FileInfo(dst); if (srcInfo.LastWriteTimeUtc > dstInfo.LastWriteTimeUtc) { Directory.CreateDirectory(Path.GetDirectoryName(dst)); Logger.LogInfo("Copying: {0} - {1}.", src, dst); File.Copy(src, dst, true); } } }
private static RunStepResult DiscoverUnitTests(IRunExecutorHost host, RunStartParams rsp, RunStepInfo rsi) { if (!host.CanContinue()) { throw new OperationCanceledException(); } var output = RunTestHost("discover", rsp); RunStepStatus rss = RunStepStatus.Succeeded; if (output.Item1 != 0) { rss = RunStepStatus.Failed; } var testsPerAssembly = PerDocumentLocationDTestCases.Deserialize(FilePath.NewFilePath(rsp.DataFiles.DiscoveredUnitDTestsStore.Item)); var totalTests = testsPerAssembly.Values.Aggregate(0, (acc, e) => acc + e.Count); TelemetryClient.TrackEvent(rsi.name.Item, new Dictionary <string, string>(), new Dictionary <string, double> { { "TestCount", totalTests } }); return(rss.ToRSR(RunData.NewTestCases(testsPerAssembly), "Unit Tests Discovered - which ones - TBD")); }
public void OnRunEnded(RunStartParams rsp) { DispatcherHelper.CheckBeginInvokeOnUI( () => { AddTextToConsole(sb => sb.AppendFormat("### Ended run.")); EngineLoader.EnableEngine(); }); }
private static Tuple <int, string> RunTestHost(string command, RunStartParams rsp) { string testRunnerPath = rsp.TestHostPath.Item; var output = ExecuteProcess( testRunnerPath, Core.TestHost.buildCommandLine(command, rsp) ); return(output); }
public static void Instrument(IRunExecutorHost host, RunStartParams rsp, Func <DocumentLocation, IEnumerable <DTestCase> > findTest) { try { InstrumentImpl(host, rsp, findTest); } catch (Exception e) { Logger.LogError("Failed to instrument. Exception: {0}", e); } }
public void OnRunStarting(RunStartParams rd) { DispatcherHelper.CheckBeginInvokeOnUI( () => { RaisePropertyChanged(() => IsRunInProgress); ClearTextFields(); AddTextToConsole( sb => sb.AppendFormat("### Starting new run...")); }); }
private static RunStepResult DiscoverSequencePoints(IRunExecutorHost host, RunStartParams rsp, RunStepInfo rsi) { var sequencePoint = Instrumentation.GenerateSequencePointInfo(host, rsp); if (sequencePoint != null) { sequencePoint.Serialize(rsp.DataFiles.SequencePointStore); } var totalSP = sequencePoint.Values.Aggregate(0, (acc, e) => acc + e.Count); TelemetryClient.TrackEvent(rsi.name.Item, new Dictionary <string, string>(), new Dictionary <string, double> { { "SequencePointCount", totalSP } }); return(RunStepStatus.Succeeded.ToRSR(RunData.NewSequencePoints(sequencePoint), "Binaries Instrumented - which ones - TBD")); }
private static RunStepResult DeleteBuildOutput(IRunExecutorHost host, RunStartParams rsp, RunStepInfo rsi) { if (Directory.Exists(rsp.Solution.BuildRoot.Item)) { foreach (var file in Directory.EnumerateFiles(rsp.Solution.BuildRoot.Item, "*.pdb")) { File.Delete(file); var dll = Path.ChangeExtension(file, "dll"); if (File.Exists(dll)) { File.Delete(dll); } } } return(RunStepStatus.Succeeded.ToRSR(RunData.NoData, "What was done - TBD")); }
private static RunStepResult TakeSolutionSnapshot(IRunExecutorHost host, RunStartParams rsp, RunStepInfo rsi) { var solutionGrandParentPath = Path.GetDirectoryName(Path.GetDirectoryName(rsp.Solution.Path.Item)); var projects = VsSolution.GetProjects(host.HostVersion, rsp.Solution.Path.Item).ToList(); var toCopy = new List <Tuple <string, SearchOption> > { new Tuple <string, SearchOption>(Path.GetDirectoryName(rsp.Solution.Path.Item), SearchOption.TopDirectoryOnly), }; Array.ForEach(rsp.Config.SnapshotIncludeFolders, item => { toCopy.Add(new Tuple <string, SearchOption>(Path.Combine(Path.GetDirectoryName(rsp.Solution.Path.Item), item), SearchOption.AllDirectories)); }); projects.ForEach(p => { var projectFile = Path.Combine(Path.GetDirectoryName(rsp.Solution.Path.Item), p.RelativePath); var folder = Path.GetDirectoryName(projectFile); toCopy.Add(new Tuple <string, SearchOption>(folder, SearchOption.AllDirectories)); }); toCopy.ForEach(item => { if (!host.CanContinue()) { throw new OperationCanceledException(); } CopyFiles(rsp, solutionGrandParentPath, item.Item1, item.Item2); }); SnapshotGC.mark(FilePath.NewFilePath(Path.GetDirectoryName(rsp.Solution.SnapshotPath.Item))); TelemetryClient.TrackEvent(rsi.name.Item, new Dictionary <string, string>(), new Dictionary <string, double> { { "ProjectCount", projects.Count } }); return(RunStepStatus.Succeeded.ToRSR(RunData.NoData, "What was done - TBD")); }
private static RunStepResult RunTests(IRunExecutorHost host, RunStartParams rsp, RunStepInfo rsi) { if (!host.CanContinue()) { throw new OperationCanceledException(); } var output = RunTestHost("execute", rsp); RunStepStatus rss = RunStepStatus.Succeeded; if (output.Item1 != 0) { rss = RunStepStatus.Failed; } var testResults = PerTestIdDResults.Deserialize(FilePath.NewFilePath(rsp.DataFiles.TestResultsStore.Item)); var coverageSession = PerSequencePointIdTestRunId.Deserialize(FilePath.NewFilePath(rsp.DataFiles.CoverageSessionStore.Item)); var testFailureInfo = PerDocumentLocationTestFailureInfo.Deserialize(FilePath.NewFilePath(rsp.DataFiles.TestFailureInfoStore.Item)); return(rss.ToRSR(RunData.NewTestRunOutput(testResults, testFailureInfo, coverageSession), output.Item2)); }
private static RunStepResult BuildSolutionSnapshot(IRunExecutorHost host, RunStartParams rsp, RunStepInfo rsi) { var output = ExecuteProcess( Path.Combine( Environment.GetEnvironmentVariable("ProgramFiles(x86)"), string.Format(@"MSBuild\{0}\Bin\msbuild.exe", host.HostVersion)), string.Format( @"/m /v:minimal /p:DebugSymbols=true /p:DebugType=full /p:Optimize=false /p:Configuration=Debug /p:CreateVsixContainer=false /p:DeployExtension=false /p:CopyVsixExtensionFiles=false /p:RunCodeAnalysis=false {0} /p:OutDir=""{1}\\"" ""{2}""", string.Join(" ", (rsp.Config.AdditionalMSBuildProperties ?? new string[0]).Select(it => string.Format("/p:{0}", it))), rsp.Solution.BuildRoot.Item, rsp.Solution.SnapshotPath.Item) ); RunStepStatus rss = RunStepStatus.Succeeded; if (output.Item1 != 0) { rss = RunStepStatus.Failed; } return(rss.ToRSR(RunData.NoData, output.Item2)); }
private static Tuple <bool, TestId> IsSequencePointAtStartOfAUnitTest(RunStartParams rsp, Mono.Cecil.Cil.SequencePoint sp, FilePath assemblyPath, Func <DocumentLocation, IEnumerable <DTestCase> > findTest) { if (sp == null) { return(new Tuple <bool, TestId>(false, null)); } var dl = new DocumentLocation { document = PathBuilder.rebaseCodeFilePath(rsp.Solution.Path, rsp.Solution.SnapshotPath, FilePath.NewFilePath(sp.Document.Url)), line = DocumentCoordinate.NewDocumentCoordinate(sp.StartLine) }; var test = findTest(dl).FirstOrDefault(t => t.Source.Equals(assemblyPath)); if (test == null) { return(new Tuple <bool, TestId>(false, null)); } else { return(new Tuple <bool, TestId>( true, new TestId(assemblyPath, dl))); } }
private static void FindSequencePointForType(RunStartParams rsp, PerDocumentSequencePoints perDocSP, ModuleDefinition module, TypeDefinition type) { foreach (MethodDefinition meth in type.Methods) { if (IsMethodSkipped(meth)) { continue; } var sps = from i in meth.Body.Instructions where i.SequencePoint != null where i.SequencePoint.StartLine != 0xfeefee select new { module, meth, i.SequencePoint }; int id = 0; foreach (var sp in sps) { var fp = PathBuilder.rebaseCodeFilePath(rsp.Solution.Path, rsp.Solution.SnapshotPath, FilePath.NewFilePath(sp.SequencePoint.Document.Url)); var seqPts = perDocSP.GetOrAdd(fp, _ => new ConcurrentBag <R4nd0mApps.TddStud10.Common.Domain.SequencePoint>()); seqPts.Add(new R4nd0mApps.TddStud10.Common.Domain.SequencePoint { id = new SequencePointId { methodId = new MethodId(AssemblyId.NewAssemblyId(sp.module.Mvid), MdTokenRid.NewMdTokenRid(sp.meth.MetadataToken.RID)), uid = id++ }, document = fp, startLine = DocumentCoordinate.NewDocumentCoordinate(sp.SequencePoint.StartLine), startColumn = DocumentCoordinate.NewDocumentCoordinate(sp.SequencePoint.StartColumn), endLine = DocumentCoordinate.NewDocumentCoordinate(sp.SequencePoint.EndLine), endColumn = DocumentCoordinate.NewDocumentCoordinate(sp.SequencePoint.EndColumn), }); } } }
private static PerDocumentSequencePoints GenerateSequencePointInfoImpl(IRunExecutorHost host, RunStartParams rsp) { var timeFilter = rsp.StartTime; var buildOutputRoot = rsp.Solution.BuildRoot.Item; Logger.LogInfo( "Generating sequence point info: Time filter - {0}, Build output root - {1}.", timeFilter.ToLocalTime(), buildOutputRoot); var perDocSP = new PerDocumentSequencePoints(); Engine.Engine.FindAndExecuteForEachAssembly( host, buildOutputRoot, timeFilter, (string assemblyPath) => { Logger.LogInfo("Generating sequence point info for {0}.", assemblyPath); var assembly = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters { ReadSymbols = true }); VisitAllTypes( assembly.Modules, (m, t) => { FindSequencePointForType(rsp, perDocSP, m, t); }); }); return(perDocSP); }
private static void InstrumentType(RunStartParams rsp, Func <DocumentLocation, IEnumerable <DTestCase> > findTest, string assemblyPath, Func <string, string> rebaseDocument, MethodReference enterSPMR, MethodReference exitUTMR, ModuleDefinition module, TypeDefinition type) { foreach (MethodDefinition meth in type.Methods) { if (IsMethodSkipped(meth)) { continue; } meth.Body.SimplifyMacros(); var spi = from i in meth.Body.Instructions where i.SequencePoint != null where i.SequencePoint.StartLine != 0xfeefee select i; var spId = 0; var instructions = spi.ToArray(); foreach (var sp in instructions) { if (sp.Previous != null && (sp.Previous.OpCode.Code == Code.Leave_S || sp.Previous.OpCode.Code == Code.Leave || sp.Previous.OpCode.Code == Code.Endfilter || sp.Previous.OpCode.Code == Code.Endfinally)) { continue; } /**********************************************************************************/ /* PDB Path Replace */ /**********************************************************************************/ sp.SequencePoint.Document.Url = rebaseDocument(sp.SequencePoint.Document.Url); /**********************************************************************************/ /* Inject Enter Sequence Point */ /**********************************************************************************/ Instruction instrMarker = sp; Instruction instr = null; var ilProcessor = meth.Body.GetILProcessor(); // IL_000d: call void R4nd0mApps.TddStud10.TestHost.Marker::EnterSequencePoint(string, ldstr, ldstr) instr = ilProcessor.Create(OpCodes.Call, enterSPMR); ilProcessor.InsertBefore(instrMarker, instr); instrMarker = instr; // IL_000b: ldstr <spid> instr = ilProcessor.Create(OpCodes.Ldstr, (spId++).ToString()); ilProcessor.InsertBefore(instrMarker, instr); instrMarker = instr; // IL_0006: ldstr <mdtoken> instr = ilProcessor.Create(OpCodes.Ldstr, meth.MetadataToken.RID.ToString()); ilProcessor.InsertBefore(instrMarker, instr); instrMarker = instr; // IL_0001: ldstr <assemblyId> instr = ilProcessor.Create(OpCodes.Ldstr, module.Mvid.ToString()); ilProcessor.InsertBefore(instrMarker, instr); instrMarker = instr; } /*************************************************************************************/ /* Inject Exit Unit Test */ /*************************************************************************************/ var ret = IsSequencePointAtStartOfAUnitTest(rsp, spi.Select(i => i.SequencePoint).FirstOrDefault(), FilePath.NewFilePath(assemblyPath), findTest); if (ret.Item1) { // NOTE: Reeeealy need to bring this class under test. Commenting out the void check as Property tests can return boolean. if (!meth.IsConstructor /*&& meth.ReturnType == module.TypeSystem.Void*/ && !meth.IsAsync()) { InjectExitUtCallInsideMethodWiseFinally(module, meth, ret.Item2, exitUTMR); } else { Logger.LogError("Instrumentation: Unsupported method type: IsConstructo = {0}, Return Type = {1}, IsAsync = {2}.", meth.IsConstructor, meth.ReturnType, meth.IsAsync()); } } meth.Body.InitLocals = true; meth.Body.OptimizeMacros(); } }
public static PerDocumentSequencePoints GenerateSequencePointInfo(IRunExecutorHost host, RunStartParams rsp) { try { return(GenerateSequencePointInfoImpl(host, rsp)); } catch (Exception e) { Logger.LogError("Failed to instrument. Exception: {0}", e); } return(null); }
private static void InstrumentImpl(IRunExecutorHost host, RunStartParams rsp, Func <DocumentLocation, IEnumerable <DTestCase> > findTest) { var timeFilter = rsp.StartTime; var solutionRoot = Path.GetDirectoryName(rsp.Solution.Path.Item); var buildOutputRoot = rsp.Solution.BuildRoot.Item; Logger.LogInfo( "Instrumenting: Time filter - {0}, Build output root - {1}.", timeFilter.ToLocalTime(), buildOutputRoot); System.Reflection.StrongNameKeyPair snKeyPair = null; var snKeyFile = Directory.EnumerateFiles(solutionRoot, "*.snk").FirstOrDefault(); if (snKeyFile != null) { snKeyPair = new System.Reflection.StrongNameKeyPair(File.ReadAllBytes(snKeyFile)); Logger.LogInfo("Using strong name from {0}.", snKeyFile); } var asmResolver = new DefaultAssemblyResolver(); Array.ForEach(asmResolver.GetSearchDirectories(), asmResolver.RemoveSearchDirectory); asmResolver.AddSearchDirectory(buildOutputRoot); var readerParams = new ReaderParameters { AssemblyResolver = asmResolver, ReadSymbols = true, }; string testRunnerPath = Path.GetFullPath(typeof(R4nd0mApps.TddStud10.TestRuntime.Marker).Assembly.Location); var enterSPMD = from t in ModuleDefinition.ReadModule(testRunnerPath).GetTypes() where t.Name == "Marker" from m in t.Methods where m.Name == "EnterSequencePoint" select m; var exitUTMD = from t in ModuleDefinition.ReadModule(testRunnerPath).GetTypes() where t.Name == "Marker" from m in t.Methods where m.Name == "ExitUnitTest" select m; Func <string, string> rebaseDocument = s => PathBuilder.rebaseCodeFilePath(rsp.Solution.Path, rsp.Solution.SnapshotPath, FilePath.NewFilePath(s)).Item; Engine.Engine.FindAndExecuteForEachAssembly( host, buildOutputRoot, timeFilter, (string assemblyPath) => { Logger.LogInfo("Instrumenting {0}.", assemblyPath); var assembly = AssemblyDefinition.ReadAssembly(assemblyPath, readerParams); var hasSn = assembly.Name.HasPublicKey; /* * IL_0001: ldstr <assemblyId> * IL_0006: ldstr <mdtoken> * IL_000b: ldstr <spid> * IL_000d: call void R4nd0mApps.TddStud10.TestHost.Marker::ExitUnitTest(string, ldstr, ldstr) */ MethodReference enterSPMR = assembly.MainModule.Import(enterSPMD.First()); MethodReference exitUTMR = assembly.MainModule.Import(exitUTMD.First()); VisitAllTypes( assembly.Modules, (m, t) => { InstrumentType(rsp, findTest, assemblyPath, rebaseDocument, enterSPMR, exitUTMR, m, t); }); var backupAssemblyPath = Path.ChangeExtension(assemblyPath, ".original"); File.Delete(backupAssemblyPath); File.Move(assemblyPath, backupAssemblyPath); try { assembly.Write(assemblyPath, new WriterParameters { WriteSymbols = true, StrongNameKeyPair = hasSn ? snKeyPair : null }); } catch { Logger.LogInfo("Backing up or instrumentation failed. Attempting to revert back changes to {0}.", assemblyPath); File.Delete(assemblyPath); File.Move(backupAssemblyPath, assemblyPath); throw; } }, 1); }
public void OnRunStarting(object _, RunStartParams rd) { }
private static RunStepResult RefreshTestRuntime(IRunExecutorHost host, RunStartParams rsp, RunStepInfo rsi) { var output = TestRunTimeInstaller.Install(rsp.Solution.BuildRoot.Item); return(RunStepStatus.Succeeded.ToRSR(RunData.NoData, string.Format("Copied Test Runtime: {0}", output))); }
public void OnRunEnded(object _, RunStartParams rsp) { }