public PythonTestMethod(string path, string name, PythonFixture fixture, PythonTestCase testCase) : base(path, name) { if (fixture == null) { throw new ArgumentNullException("fixture"); } if (testCase == null) { throw new ArgumentNullException("testCase"); } _fixture = fixture; _testCase = testCase; testFramework = TestFramework.FromAssembly(GetType().Assembly); }
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) { frameworkHandle.SendMessage(TestMessageLevel.Error, "Error occurred connecting to debuggee."); try { proc.Kill(); } catch (InvalidOperationException) { // Process has already exited } killed = true; } #endif } // https://pytools.codeplex.com/workitem/2290 // Check that proc.WaitHandle was not null to avoid crashing if // a test fails to start running. We will report failure and // send the error message from stdout/stderr. var handles = new WaitHandle[] { _cancelRequested, proc.WaitHandle }; if (handles[1] == null) { killed = true; } if (!killed && WaitHandle.WaitAny(handles) == 0) { try { proc.Kill(); } catch (InvalidOperationException) { // Process has already exited } killed = true; } else { RecordEnd(frameworkHandle, test, testResult, string.Join(Environment.NewLine, proc.StandardOutputLines), string.Join(Environment.NewLine, proc.StandardErrorLines), (proc.ExitCode == 0 && !killed) ? TestOutcome.Passed : TestOutcome.Failed); } }
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); } 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) {