示例#1
0
            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;
                            var 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
                            {
                                var 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 {
                            var 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 {
                            var 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));
            }
示例#2
0
            public void Run()
            {
                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: (newproc, newthread) => {
                    try {
                        foreach (var bp in Breakpoints)
                        {
                            var fileName = bp.FileName ?? breakFileName ?? runFileName;

                            PythonBreakpoint breakpoint;
                            var 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
                            {
                                var 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;
                                }
                            }

                            breakpoint.Add();
                            bps.Add(breakpoint, bp);
                        }

                        if (OnProcessLoaded != null)
                        {
                            OnProcessLoaded(newproc);
                        }

                        thread = newthread;
                        processLoaded.SetResult(true);
                    } catch (Exception ex) {
                        backgroundException.SetException(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 {
                            var 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.SetException(ex);
                        }
                    };

                    process.BreakpointBindSucceeded += (sender, args) => {
                        try {
                            var 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.SetException(ex);
                        }
                    };

                    process.BreakpointHit += (sender, args) => {
                        try {
                            if (nextExpectedHit < ExpectedHits.Count)
                            {
                                var bp = Breakpoints[ExpectedHits[nextExpectedHit]];
                                Assert.AreSame(bp, bps[args.Breakpoint]);

                                if (bp.RemoveWhenHit)
                                {
                                    args.Breakpoint.Remove();
                                }

                                if (bp.ExpectHitOnMainThread ?? ExpectHitOnMainThread)
                                {
                                    Assert.AreSame(thread, args.Thread);
                                }

                                if (bp.OnHit != null)
                                {
                                    bp.OnHit(args);
                                }

                                if (++nextExpectedHit == ExpectedHits.Count)
                                {
                                    allBreakpointsHit.SetResult(true);
                                }
                            }
                            process.Continue();
                        } catch (Exception ex) {
                            backgroundException.SetException(ex);
                        }
                    };

                    process.Start();
                    WaitForAny(10000, processLoaded.Task, backgroundException.Task);

                    process.AutoResumeThread(thread.Id);
                    if (breakpointsToBeBound > 0)
                    {
                        WaitForAny(10000, allBreakpointBindResults.Task, backgroundException.Task);
                    }
                } finally {
                    if (WaitForExit)
                    {
                        _tests.WaitForExit(process);
                    }
                    else
                    {
                        WaitForAny(10000, allBreakpointsHit.Task, backgroundException.Task);
                        process.Terminate();
                    }
                }

                if (backgroundException.Task.IsFaulted)
                {
                    backgroundException.Task.GetAwaiter().GetResult();
                }

                Assert.AreEqual(ExpectedHits.Count, nextExpectedHit);
                Assert.IsTrue(unboundBps.All(bp => bp.IsBindFailureExpected ?? IsBindFailureExpected));
            }