public async Task RunAsync() { PythonThread thread = await _tests.RunAndBreakAsync(FileName, LineNo, breakFilename : BreakFileName, arguments : Arguments, processLoaded : ProcessLoaded, debugOptions : DebugOptions); PythonProcess process = thread.Process; try { var frames = thread.Frames; var localNamesExpected = Locals.Select(v => v.Expression).ToSet(); var paramNamesExpected = Params.Select(v => v.Expression).ToSet(); string fileNameExpected; if (BreakFileName == null) { fileNameExpected = Path.GetFullPath(_tests.DebuggerTestPath + FileName); } else if (Path.IsPathRooted(BreakFileName)) { fileNameExpected = BreakFileName; } else { fileNameExpected = Path.GetFullPath(_tests.DebuggerTestPath + BreakFileName); } Assert.AreEqual(frames[0].FileName, fileNameExpected, true); if (!IgnoreExtra) { AssertUtil.ContainsExactly(frames[0].Locals.Select(x => x.Expression), localNamesExpected); AssertUtil.ContainsExactly(frames[0].Parameters.Select(x => x.Expression), paramNamesExpected); } foreach (var expectedLocal in Locals) { var actualLocal = frames[0].Locals.First(v => v.Expression == expectedLocal.Expression); expectedLocal.Validate(actualLocal); } foreach (var expectedParam in Params) { var actualParam = frames[0].Parameters.First(v => v.Expression == expectedParam.Expression); expectedParam.Validate(actualParam); } await process.ResumeAsync(TimeoutToken()); if (WaitForExit) { _tests.WaitForExit(process); } } finally { if (!process.HasExited) { process.Terminate(); } } }
public async Task RunAsync() { string runFileName = RunFileName; if (!Path.IsPathRooted(runFileName)) { runFileName = _tests.DebuggerTestPath + runFileName; } string breakFileName = BreakFileName; if (breakFileName != null && !Path.IsPathRooted(breakFileName)) { breakFileName = _tests.DebuggerTestPath + breakFileName; } foreach (var bp in Breakpoints) { var fileName = bp.FileName ?? breakFileName ?? runFileName; if (fileName.EndsWith(".py")) { Assert.IsTrue(bp is Breakpoint); } else { Assert.IsTrue(bp is DjangoBreakpoint); } } var bps = new Dictionary <PythonBreakpoint, BreakpointBase>(); var unboundBps = new HashSet <Breakpoint>(); var breakpointsToBeBound = Breakpoints.Count; var debugger = new PythonDebugger(); PythonThread thread = null; // Used to signal exceptions from debugger event handlers that run on a background thread. var backgroundException = new TaskCompletionSource <bool>(); var processLoaded = new TaskCompletionSource <bool>(); var process = _tests.DebugProcess( debugger, runFileName, cwd: WorkingDirectory, arguments: Arguments, resumeOnProcessLoaded: false, onLoaded: async(newproc, newthread) => { try { foreach (var bp in Breakpoints) { var fileName = bp.FileName ?? breakFileName ?? runFileName; PythonBreakpoint breakpoint; Breakpoint pyBP = bp as Breakpoint; if (pyBP != null) { breakpoint = newproc.AddBreakpoint(fileName, pyBP.LineNumber, pyBP.ConditionKind, pyBP.Condition, pyBP.PassCountKind, pyBP.PassCount); unboundBps.Add(pyBP); } else { DjangoBreakpoint djangoBP = bp as DjangoBreakpoint; if (djangoBP != null) { breakpoint = newproc.AddDjangoBreakpoint(fileName, djangoBP.LineNumber); // Django breakpoints are never bound. --breakpointsToBeBound; } else { Assert.Fail("Unknown breakpoint type."); return; } } // Bind failed and succeeded events expect to find the breakpoint // in the dictionary, so update it before sending the add request. bps.Add(breakpoint, bp); await breakpoint.AddAsync(TimeoutToken()); } OnProcessLoaded?.Invoke(newproc); thread = newthread; processLoaded.SetResult(true); } catch (Exception ex) { backgroundException.TrySetException(ex); } }, interpreterOptions: InterpreterOptions ); int breakpointsBound = 0; int breakpointsNotBound = 0; int nextExpectedHit = 0; var allBreakpointsHit = new TaskCompletionSource <bool>(); var allBreakpointBindResults = new TaskCompletionSource <bool>(); if (breakpointsToBeBound == 0) { allBreakpointBindResults.SetResult(true); } try { process.BreakpointBindFailed += (sender, args) => { try { global::DebuggerTests.BaseDebuggerTests.Breakpoint bp = (Breakpoint)bps[args.Breakpoint]; if (bp != null && !(bp.IsBindFailureExpected ?? IsBindFailureExpected)) { Assert.Fail("Breakpoint at {0}:{1} failed to bind.", bp.FileName ?? breakFileName ?? runFileName, bp.LineNumber); } ++breakpointsNotBound; if (breakpointsBound + breakpointsNotBound == breakpointsToBeBound) { allBreakpointBindResults.SetResult(true); } } catch (Exception ex) { backgroundException.TrySetException(ex); } }; process.BreakpointBindSucceeded += (sender, args) => { try { global::DebuggerTests.BaseDebuggerTests.Breakpoint bp = (Breakpoint)bps[args.Breakpoint]; Assert.AreEqual(bp.FileName ?? breakFileName ?? runFileName, args.Breakpoint.Filename); Assert.IsTrue(unboundBps.Remove(bp)); ++breakpointsBound; if (breakpointsBound + breakpointsNotBound == breakpointsToBeBound) { allBreakpointBindResults.SetResult(true); } } catch (Exception ex) { backgroundException.TrySetException(ex); } }; process.BreakpointHit += async(sender, args) => { try { if (nextExpectedHit < ExpectedHits.Count) { var bp = Breakpoints[ExpectedHits[nextExpectedHit]]; Trace.TraceInformation("Hit {0}:{1}", args.Breakpoint.Filename, args.Breakpoint.LineNo); Assert.AreSame(bp, bps[args.Breakpoint]); if (bp.RemoveWhenHit) { await args.Breakpoint.RemoveAsync(TimeoutToken()); } if (bp.ExpectHitOnMainThread ?? ExpectHitOnMainThread) { Assert.AreSame(thread, args.Thread); } bp.OnHit?.Invoke(args); if (++nextExpectedHit == ExpectedHits.Count) { allBreakpointsHit.SetResult(true); } } try { await process.ResumeAsync(TimeoutToken()); } catch (TaskCanceledException) { // If we don't wait for exit, the Terminate() call // will cause ResumeAsync to be canceled. if (WaitForExit) { throw; } } } catch (Exception ex) { backgroundException.TrySetException(ex); } }; await process.StartAsync(); Assert.IsTrue(WaitForAny(10000, processLoaded.Task, backgroundException.Task), "Timed out waiting for process load"); await process.AutoResumeThread(thread.Id, TimeoutToken()); if (breakpointsToBeBound > 0) { Assert.IsTrue(WaitForAny(10000, allBreakpointBindResults.Task, backgroundException.Task), "Timed out waiting for breakpoints to bind"); } } finally { if (WaitForExit) { _tests.WaitForExit(process); } else { Assert.IsTrue(WaitForAny(20000, allBreakpointsHit.Task, backgroundException.Task), "Timed out waiting for breakpoints to hit"); process.Terminate(); } } if (backgroundException.Task.IsFaulted) { backgroundException.Task.GetAwaiter().GetResult(); } Assert.AreEqual(ExpectedHits.Count, nextExpectedHit); Assert.IsTrue(unboundBps.All(bp => bp.IsBindFailureExpected ?? IsBindFailureExpected)); }