예제 #1
0
        private static void AttachIfDebugging(Process targetVs)
        {
            if (!Debugger.IsAttached)
            {
                return;
            }

            // We are debugging tests, so attach the debugger to VS
            var selfId = Process.GetCurrentProcess().Id;

            foreach (var p in Process.GetProcessesByName("devenv"))
            {
                if (p.Id == targetVs.Id)
                {
                    continue;
                }

                using (VisualStudioApp vs = VisualStudioApp.FromProcessId(p.Id))
                {
                    EnvDTE.DTE dte;
                    try
                    {
                        dte = vs.GetDTE();
                    }
                    catch (InvalidOperationException)
                    {
                        // DTE is not available, which means VS has not been running
                        continue;
                    }

                    if (dte.Debugger.CurrentMode == EnvDTE.dbgDebugMode.dbgDesignMode)
                    {
                        // Not the correct VS
                        continue;
                    }

                    foreach (EnvDTE.Process dp in dte.Debugger.DebuggedProcesses)
                    {
                        if (dp.ProcessID == selfId)
                        {
                            // This is the correct VS, so attach and return.

                            vs.AttachToProcess(targetVs, null);
                            return;
                        }
                    }
                }
            }
        }
        public static IInterpreterOptionsService GetService(VisualStudioApp app)
        {
            var provider  = new MockExportProvider();
            var container = new CompositionContainer(
                new AssemblyCatalog(typeof(IInterpreterOptionsService).Assembly),
                provider
                );

            if (app != null)
            {
                var sp = new ServiceProvider(app.GetDTE() as IOleServiceProvider);
                provider.SetExport(typeof(SVsServiceProvider), () => sp);
            }
            return(container.GetExportedValue <IInterpreterOptionsService>());
        }
예제 #3
0
        private void RunTestCase(VisualStudioApp app, IFrameworkHandle frameworkHandle, IRunContext runContext, TestCase test, Dictionary <string, NodejsProjectSettings> sourceToSettings)
        {
            var testResult = new TestResult(test);

            frameworkHandle.RecordStart(test);
            testResult.StartTime = DateTimeOffset.Now;
            NodejsProjectSettings settings;

            if (!sourceToSettings.TryGetValue(test.Source, out settings))
            {
                sourceToSettings[test.Source] = settings = LoadProjectSettings(test.Source);
            }
            if (settings == null)
            {
                frameworkHandle.SendMessage(
                    TestMessageLevel.Error,
                    "Unable to determine interpreter to use for " + test.Source);
                RecordEnd(
                    frameworkHandle,
                    test,
                    testResult,
                    null,
                    "Unable to determine interpreter to use for " + test.Source,
                    TestOutcome.Failed);
                return;
            }

            NodejsTestInfo testInfo = new NodejsTestInfo(test.FullyQualifiedName);
            List <string>  args     = new List <string>();
            int            port     = 0;

            if (runContext.IsBeingDebugged && app != null)
            {
                app.GetDTE().Debugger.DetachAll();
                args.AddRange(GetDebugArgs(settings, out port));
            }

            var workingDir = Path.GetDirectoryName(CommonUtils.GetAbsoluteFilePath(settings.WorkingDir, testInfo.ModulePath));

            args.AddRange(GetInterpreterArgs(test, workingDir, settings.ProjectRootDir));

            //Debug.Fail("attach debugger");
            if (!File.Exists(settings.NodeExePath))
            {
                frameworkHandle.SendMessage(TestMessageLevel.Error, "Interpreter path does not exist: " + settings.NodeExePath);
                return;
            }
            lock (_syncObject) {
                _nodeProcess = ProcessOutput.Run(
                    settings.NodeExePath,
                    args,
                    workingDir,
                    null,
                    false,
                    null,
                    false);

#if DEBUG
                frameworkHandle.SendMessage(TestMessageLevel.Informational, "cd " + workingDir);
                frameworkHandle.SendMessage(TestMessageLevel.Informational, _nodeProcess.Arguments);
#endif

                _nodeProcess.Wait(TimeSpan.FromMilliseconds(500));
                if (runContext.IsBeingDebugged && app != null)
                {
                    try {
                        //the '#ping=0' is a special flag to tell VS node debugger not to connect to the port,
                        //because a connection carries the consequence of setting off --debug-brk, and breakpoints will be missed.
                        string qualifierUri = string.Format("tcp://localhost:{0}#ping=0", port);
                        while (!app.AttachToProcess(_nodeProcess, NodejsRemoteDebugPortSupplierUnsecuredId, qualifierUri))
                        {
                            if (_nodeProcess.Wait(TimeSpan.FromMilliseconds(500)))
                            {
                                break;
                            }
                        }
#if DEBUG
                    } catch (COMException ex) {
                        frameworkHandle.SendMessage(TestMessageLevel.Error, "Error occurred connecting to debuggee.");
                        frameworkHandle.SendMessage(TestMessageLevel.Error, ex.ToString());
                        KillNodeProcess();
                    }
#else
                    } catch (COMException) {
예제 #4
0
파일: TestExecutor.cs 프로젝트: tk811/PTVS
        private void RunTestCase(
            IFrameworkHandle frameworkHandle,
            IRunContext runContext,
            TestCase test,
            Dictionary <string, PythonProjectSettings> sourceToSettings
            )
        {
            var testResult = new TestResult(test);

            frameworkHandle.RecordStart(test);
            testResult.StartTime = DateTimeOffset.Now;

            PythonProjectSettings settings;

            if (!sourceToSettings.TryGetValue(test.Source, out settings))
            {
                sourceToSettings[test.Source] = settings = LoadProjectSettings(test.Source, _interpreterService);
            }
            if (settings == null)
            {
                frameworkHandle.SendMessage(
                    TestMessageLevel.Error,
                    "Unable to determine interpreter to use for " + test.Source);
                RecordEnd(
                    frameworkHandle,
                    test,
                    testResult,
                    null,
                    "Unable to determine interpreter to use for " + test.Source,
                    TestOutcome.Failed);
                return;
            }

            var debugMode = PythonDebugMode.None;

            if (runContext.IsBeingDebugged && _app != null)
            {
                debugMode = settings.EnableNativeCodeDebugging ? PythonDebugMode.PythonAndNative : PythonDebugMode.PythonOnly;
            }

            var testCase = new PythonTestCase(settings, test, debugMode);

            var dte = _app != null?_app.GetDTE() : null;

            if (dte != null && debugMode != PythonDebugMode.None)
            {
                dte.Debugger.DetachAll();
            }

            if (!File.Exists(settings.Factory.Configuration.InterpreterPath))
            {
                frameworkHandle.SendMessage(TestMessageLevel.Error, "Interpreter path does not exist: " + settings.Factory.Configuration.InterpreterPath);
                return;
            }

            var env           = new Dictionary <string, string>();
            var pythonPathVar = settings.Factory.Configuration.PathEnvironmentVariable;
            var pythonPath    = testCase.SearchPaths;

            if (!string.IsNullOrWhiteSpace(pythonPathVar))
            {
                if (_app != null)
                {
                    var settingsManager = SettingsManagerCreator.GetSettingsManager(dte);
                    if (settingsManager != null)
                    {
                        var store = settingsManager.GetReadOnlySettingsStore(SettingsScope.UserSettings);
                        if (store != null && store.CollectionExists(@"PythonTools\Options\General"))
                        {
                            var  settingStr = store.GetString(@"PythonTools\Options\General", "ClearGlobalPythonPath", "True");
                            bool settingBool;
                            if (bool.TryParse(settingStr, out settingBool) && !settingBool)
                            {
                                pythonPath += ";" + Environment.GetEnvironmentVariable(pythonPathVar);
                            }
                        }
                    }
                }
                env[pythonPathVar] = pythonPath;
            }

            foreach (var envVar in testCase.Environment)
            {
                env[envVar.Key] = envVar.Value;
            }

            using (var proc = ProcessOutput.Run(
                       !settings.IsWindowsApplication ?
                       settings.Factory.Configuration.InterpreterPath :
                       settings.Factory.Configuration.WindowsInterpreterPath,
                       testCase.Arguments,
                       testCase.WorkingDirectory,
                       env,
                       false,
                       null
                       )) {
                bool killed = false;

#if DEBUG
                frameworkHandle.SendMessage(TestMessageLevel.Informational, "cd " + testCase.WorkingDirectory);
                frameworkHandle.SendMessage(TestMessageLevel.Informational, "set " + (pythonPathVar ?? "") + "=" + (pythonPath ?? ""));
                frameworkHandle.SendMessage(TestMessageLevel.Informational, proc.Arguments);
#endif

                proc.Wait(TimeSpan.FromMilliseconds(500));
                if (debugMode != PythonDebugMode.None)
                {
                    if (proc.ExitCode.HasValue)
                    {
                        // Process has already exited
                        frameworkHandle.SendMessage(TestMessageLevel.Error, "Failed to attach debugger because the process has already exited.");
                        if (proc.StandardErrorLines.Any())
                        {
                            frameworkHandle.SendMessage(TestMessageLevel.Error, "Standard error from Python:");
                            foreach (var line in proc.StandardErrorLines)
                            {
                                frameworkHandle.SendMessage(TestMessageLevel.Error, line);
                            }
                        }
                    }

                    try {
                        if (debugMode == PythonDebugMode.PythonOnly)
                        {
                            string qualifierUri = string.Format("tcp://{0}@localhost:{1}", testCase.DebugSecret, testCase.DebugPort);
                            while (!_app.AttachToProcess(proc, PythonRemoteDebugPortSupplierUnsecuredId, qualifierUri))
                            {
                                if (proc.Wait(TimeSpan.FromMilliseconds(500)))
                                {
                                    break;
                                }
                            }
                        }
                        else
                        {
                            var engines = new[] { PythonDebugEngineGuid, VSConstants.DebugEnginesGuids.NativeOnly_guid };
                            while (!_app.AttachToProcess(proc, engines))
                            {
                                if (proc.Wait(TimeSpan.FromMilliseconds(500)))
                                {
                                    break;
                                }
                            }
                        }

#if DEBUG
                    } catch (COMException ex) {
                        frameworkHandle.SendMessage(TestMessageLevel.Error, "Error occurred connecting to debuggee.");
                        frameworkHandle.SendMessage(TestMessageLevel.Error, ex.ToString());
                        try {
                            proc.Kill();
                        } catch (InvalidOperationException) {
                            // Process has already exited
                        }
                        killed = true;
                    }
#else
                    } catch (COMException) {
예제 #5
0
        private void RunTestCase(VisualStudioApp app, IFrameworkHandle frameworkHandle, IRunContext runContext, TestCase test, Dictionary <string, NodejsProjectSettings> sourceToSettings)
        {
            var testResult = new TestResult(test);

            frameworkHandle.RecordStart(test);
            testResult.StartTime = DateTimeOffset.Now;
            NodejsProjectSettings settings;

            if (!sourceToSettings.TryGetValue(test.Source, out settings))
            {
                sourceToSettings[test.Source] = settings = LoadProjectSettings(test.Source);
            }
            if (settings == null)
            {
                frameworkHandle.SendMessage(
                    TestMessageLevel.Error,
                    "Unable to determine interpreter to use for " + test.Source);
                RecordEnd(
                    frameworkHandle,
                    test,
                    testResult,
                    null,
                    "Unable to determine interpreter to use for " + test.Source,
                    TestOutcome.Failed);
                return;
            }

#if DEV15
            // VS 2017 doesn't install some assemblies to the GAC that are needed to work with the
            // debugger, and as the tests don't execute in the devenv.exe process, those assemblies
            // fail to load - so load them manually from PublicAssemblies.

            // Use the executable name, as this is only needed for the out of proc test execution
            // that may interact with the debugger (vstest.executionengine.x86.exe).
            string currentProc = Process.GetCurrentProcess().MainModule.FileName;
            if (Path.GetFileName(currentProc).ToLowerInvariant().Equals("vstest.executionengine.x86.exe"))
            {
                string baseDir          = Path.GetDirectoryName(currentProc);
                string publicAssemblies = Path.Combine(baseDir, "..\\..\\..\\PublicAssemblies");

                Assembly.LoadFrom(Path.Combine(publicAssemblies, "Microsoft.VisualStudio.OLE.Interop.dll"));
                Assembly.LoadFrom(Path.Combine(publicAssemblies, "envdte90.dll"));
                Assembly.LoadFrom(Path.Combine(publicAssemblies, "envdte80.dll"));
                Assembly.LoadFrom(Path.Combine(publicAssemblies, "envdte.dll"));
            }
#endif

            NodejsTestInfo testInfo = new NodejsTestInfo(test.FullyQualifiedName);
            List <string>  args     = new List <string>();
            int            port     = 0;
            if (runContext.IsBeingDebugged && app != null)
            {
                app.GetDTE().Debugger.DetachAll();
                args.AddRange(GetDebugArgs(settings, out port));
            }

            var workingDir = Path.GetDirectoryName(CommonUtils.GetAbsoluteFilePath(settings.WorkingDir, testInfo.ModulePath));
            args.AddRange(GetInterpreterArgs(test, workingDir, settings.ProjectRootDir));

            //Debug.Fail("attach debugger");
            if (!File.Exists(settings.NodeExePath))
            {
                frameworkHandle.SendMessage(TestMessageLevel.Error, "Interpreter path does not exist: " + settings.NodeExePath);
                return;
            }
            lock (_syncObject) {
                _nodeProcess = ProcessOutput.Run(
                    settings.NodeExePath,
                    args,
                    workingDir,
                    null,
                    false,
                    null,
                    false);

#if DEBUG
                frameworkHandle.SendMessage(TestMessageLevel.Informational, "cd " + workingDir);
                frameworkHandle.SendMessage(TestMessageLevel.Informational, _nodeProcess.Arguments);
#endif

                _nodeProcess.Wait(TimeSpan.FromMilliseconds(500));
                if (runContext.IsBeingDebugged && app != null)
                {
                    try {
                        //the '#ping=0' is a special flag to tell VS node debugger not to connect to the port,
                        //because a connection carries the consequence of setting off --debug-brk, and breakpoints will be missed.
                        string qualifierUri = string.Format(CultureInfo.InvariantCulture, "tcp://localhost:{0}#ping=0", port);
                        while (!app.AttachToProcess(_nodeProcess, NodejsRemoteDebugPortSupplierUnsecuredId, qualifierUri))
                        {
                            if (_nodeProcess.Wait(TimeSpan.FromMilliseconds(500)))
                            {
                                break;
                            }
                        }
#if DEBUG
                    } catch (COMException ex) {
                        frameworkHandle.SendMessage(TestMessageLevel.Error, "Error occurred connecting to debuggee.");
                        frameworkHandle.SendMessage(TestMessageLevel.Error, ex.ToString());
                        KillNodeProcess();
                    }
#else
                    } catch (COMException) {
예제 #6
0
        public void StartOrRestart(
            string devenvExe,
            string devenvArguments,
            string testDataRoot,
            string tempRoot
            )
        {
            lock (_lock)
            {
                var settings = $"{devenvExe ?? ""};{devenvArguments ?? ""};{testDataRoot ?? ""};{tempRoot ?? ""}";
                if (_vs != null && _app != null)
                {
                    if (_currentSettings == settings)
                    {
                        return;
                    }
                    Console.WriteLine("Restarting VS because settings have changed");
                }
                _currentSettings = settings;
                CloseCurrentInstance();

                var psi = new ProcessStartInfo
                {
                    FileName               = devenvExe,
                    Arguments              = devenvArguments,
                    ErrorDialog            = false,
                    UseShellExecute        = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError  = true
                };
                psi.Environment["_PTVS_UI_TEST"] = "1";
                if (!string.IsNullOrEmpty(testDataRoot))
                {
                    psi.Environment["_TESTDATA_ROOT_PATH"] = testDataRoot;
                }
                if (!string.IsNullOrEmpty(tempRoot))
                {
                    psi.Environment["_TESTDATA_TEMP_PATH"] = tempRoot;
                }

                _vs = Process.Start(psi);
                if (!NativeMethods.AssignProcessToJobObject(_jobObject, _vs.Handle))
                {
                    try
                    {
                        _vs.Kill();
                    }
                    catch (Exception)
                    {
                    }
                    _vs.Dispose();
                    throw new InvalidOperationException("Failed to add VS to our job object");
                }

                // Forward console output to our own output, which will
                // be captured by the test runner.
                _vs.OutputDataReceived += (s, e) => { if (e.Data != null)
                                                      {
                                                          Console.WriteLine(e.Data);
                                                      }
                };
                _vs.ErrorDataReceived += (s, e) => { if (e.Data != null)
                                                     {
                                                         Console.Error.WriteLine(e.Data);
                                                     }
                };
                _vs.BeginOutputReadLine();
                _vs.BeginErrorReadLine();

                // Always allow at least five seconds to start
                Thread.Sleep(5000);
                if (_vs.HasExited)
                {
                    throw new InvalidOperationException("Failed to start VS");
                }
                _app = VisualStudioApp.FromProcessId(_vs.Id);

                var        stopAt = DateTime.Now.AddSeconds(60);
                EnvDTE.DTE dte    = null;
                while (DateTime.Now < stopAt && dte == null)
                {
                    try
                    {
                        dte = _app.GetDTE();
                    }
                    catch (InvalidOperationException)
                    {
                        Thread.Sleep(1000);
                    }
                }
                if (dte == null)
                {
                    throw new InvalidOperationException("Failed to start VS");
                }

                AttachIfDebugging(_vs);
            }
        }
예제 #7
0
        public bool RunTest(string container, string name, TimeSpan timeout, object[] arguments, bool allowRetry)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            var  dte      = _app.GetDTE();
            bool timedOut = false;
            CancellationTokenSource cts = null;
            var startTime = DateTime.UtcNow;

            if (!Debugger.IsAttached && timeout < TimeSpan.MaxValue)
            {
                cts = new CancellationTokenSource();
                Task.Delay(timeout, cts.Token).ContinueWith(t =>
                {
                    timedOut = true;
                    Console.WriteLine($"Terminating {container}.{name}() after {DateTime.UtcNow - startTime}");
                    // Terminate VS to unblock the Execute() call below
                    CloseCurrentInstance(hard: true);
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
            }

            try
            {
                var r = dte.GetObject(container).Execute(name, arguments);
                if (!r.IsSuccess)
                {
                    if (r.ExceptionType == "Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException")
                    {
                        throw new AssertInconclusiveException(r.ExceptionMessage);
                    }
                    throw new TestFailedException(
                              r.ExceptionType,
                              r.ExceptionMessage,
                              r.ExceptionTraceback
                              );
                }
                return(true);
            }
            catch (InvalidComObjectException ex)
            {
                Console.WriteLine(ex);
                CloseCurrentInstance();
                if (!allowRetry)
                {
                    ExceptionDispatchInfo.Capture(ex).Throw();
                }
            }
            catch (COMException ex)
            {
                Console.WriteLine(ex);
                CloseCurrentInstance();
                if (timedOut)
                {
                    throw new TimeoutException($"Terminating {container}.{name}() after {DateTime.UtcNow - startTime}", ex);
                }
                if (!allowRetry)
                {
                    ExceptionDispatchInfo.Capture(ex).Throw();
                }
            }
            catch (ThreadAbortException ex)
            {
                Console.WriteLine(ex);
                CloseCurrentInstance(hard: true);
                ExceptionDispatchInfo.Capture(ex).Throw();
            }
            catch (Exception ex)
            {
                CloseCurrentInstance();
                ExceptionDispatchInfo.Capture(ex).Throw();
            }
            finally
            {
                if (cts != null)
                {
                    cts.Cancel();
                    cts.Dispose();
                }
            }
            return(false);
        }