private void CopySource() { try { this.WriteLine("Creating instance of debuggee by copying source."); FileUtilities.DirectoryCopy(this.DebuggeeRoot, this.DebuggeeInstance, true); } catch (IOException ex) { this.WriteLine("Error copying debuggee folder. Copying from '{0}' to '{1}'.", this.DebuggeeRoot, this.DebuggeeInstance); this.WriteLine(UDebug.ExceptionToString(ex)); throw; } }
/// <summary> /// Check for abandoned files or processes /// </summary> /// <param name="throwOnFailure">Fail the test if abandoned artifacts found</param> private void CheckDebuggerArtifacts(bool throwOnFailure) { try { if (string.IsNullOrEmpty(this.engineLogPath) || !File.Exists(this.engineLogPath)) { return; } string engineLogContent = File.ReadAllText(this.engineLogPath); // Add the MIEngine log to the test log (if it is enabled) if (!throwOnFailure && DiagnosticsSettings.LogMIEngine) { this.Comment("Engine Log"); this.WriteLine(engineLogContent); } // Parse the mi engine's log to find associated temp files and debugger pids // This only checks for any process ids or files logged by the mi engine // and may not be a complete list. List <string> tempFiles = new List <string>(3); List <int> associatedPids = new List <int>(2); foreach (Match match in EngineLogRegEx.Matches(engineLogContent)) { string tempFile = match.Groups?["tempFile"]?.Value; string shellPid = match.Groups?["shellPid"]?.Value; string debuggerPid = match.Groups?["debuggerPid"]?.Value; if (!string.IsNullOrEmpty(tempFile)) { tempFiles.Add(tempFile); } else if (!string.IsNullOrEmpty(shellPid)) { associatedPids.Add(int.Parse(shellPid, CultureInfo.InvariantCulture)); } else if (!string.IsNullOrEmpty(debuggerPid)) { associatedPids.Add(int.Parse(debuggerPid, CultureInfo.InvariantCulture)); } } // Check for abandoned temp files foreach (string tempFile in tempFiles) { if (File.Exists(tempFile)) { this.WriteLine("ERROR: Debug Adapter abandoned temp file: " + tempFile); TryDeleteFile(tempFile); Assert.False(throwOnFailure, "ERROR: Debug Adapter abandoned temp file: " + tempFile); } } // Check for abandoned processes foreach (int associatedPid in associatedPids) { if (ProcessHelper.IsProcessRunning(associatedPid)) { this.WriteLine("ERROR: Debug Adapter abandoned process: " + associatedPid.ToString(CultureInfo.InvariantCulture)); ProcessHelper.KillProcess(associatedPid, recurse: true); Assert.False(throwOnFailure, "ERROR: Debug Adapter abandoned process: " + associatedPid.ToString(CultureInfo.InvariantCulture)); } } } catch (Exception ex) { this.WriteLine("Error checking engine log. {0}", UDebug.ExceptionToString(ex)); } }
/// <summary> /// Runs a command against the debugger. /// </summary> /// <param name="command">The command to run.</param> /// <param name="expectedEvents">[OPTIONAL] If the command causes an event to occur, pass the expected event(s)</param> private void Run(DarRunner darRunner, ILoggingComponent log, params IEvent[] expectedEvents) { Parameter.ThrowIfNull(darRunner, nameof(darRunner)); log?.WriteLine("Running command {0}", this.ToString()); log?.WriteLine("Command '{0}' expecting response: {1}", this.Name, this.ExpectedResponse.ToString()); DebugAdapterResponse darCommandResponse = GetDarResponse(this.ExpectedResponse); DebugAdapterCommand darCommand = new DebugAdapterCommand( this.Name, this.Args, new[] { darCommandResponse }); List <Tuple <DebugAdapterResponse, IEvent> > darEventMap = new List <Tuple <DebugAdapterResponse, IEvent> >(expectedEvents.Length); // Add additional expected events to match if requested if (expectedEvents != null && expectedEvents.Length > 0) { if (expectedEvents.Length > 1) { log?.WriteLine("Command '{0}' expecting {1} events:", this.Name, expectedEvents.Length); } foreach (var expectedEvent in expectedEvents) { DebugAdapterResponse darEventResponse = GetDarResponse(expectedEvent); darCommand.ExpectedResponses.Add(darEventResponse); darEventMap.Add(Tuple.Create(darEventResponse, expectedEvent)); // Debug info for expected response string eventMessage = expectedEvents.Length > 1 ? " - {1}" : "Command '{0}' expecting event: {1}"; log?.WriteLine(eventMessage, this.Name, expectedEvent.ToString()); } } // Allow the command to override the timeout int overrideTimeout = Convert.ToInt32(this.Timeout.TotalMilliseconds); int savedTimeout = darRunner.ResponseTimeout; try { if (overrideTimeout > 0) { darRunner.ResponseTimeout = overrideTimeout; log?.WriteLine("Command '{0}' timeout set to {1:n0} seconds.", this.Name, this.Timeout.TotalSeconds); } darCommand.Run(darRunner); // Allow the command to retrieve properties from the actual matched response. string responseJson = JsonConvert.SerializeObject(darCommandResponse.Match); if (!string.IsNullOrWhiteSpace(responseJson)) { this.ProcessActualResponse(new ActualResponse(responseJson)); } // Allow the events to retrieve properties from the actual event. foreach (var darEvent in darEventMap) { string eventJson = JsonConvert.SerializeObject(darEvent.Item1.Match); darEvent.Item2.ProcessActualResponse(new ActualResponse(eventJson)); } } catch (Exception ex) { // Add information to the log when the exception occurs log?.WriteLine("ERROR: Running command '{0}'. Exception thrown.", this.Name); log?.WriteLine(UDebug.ExceptionToString(ex)); // The DARException is not serializable, create a new exception if (ex is DARException) { throw new RunnerException(ex.Message); } else { throw; } } finally { if (overrideTimeout > 0) { darRunner.ResponseTimeout = savedTimeout; } } }