| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 namespace UnitTests | |
| 6 { | |
| 7 using System; | |
| 8 using System.Diagnostics; | |
| 9 using System.IO; | |
| 10 using System.Reflection; | |
| 11 using System.Threading; | |
| 12 | |
| 13 using EnvDTE; | |
| 14 using EnvDTE80; | |
| 15 using Microsoft.VisualStudio.TestTools.UnitTesting; | |
| 16 | |
| 17 using NativeClientVSAddIn; | |
| 18 | |
| 19 /// <summary> | |
| 20 /// This is a test class for PluginDebuggerHelperTest and is intended | |
| 21 /// to contain all PluginDebuggerHelperTest Unit Tests. | |
| 22 /// </summary> | |
| 23 [TestClass] | |
| 24 public class PluginDebuggerHelperTest | |
| 25 { | |
| 26 /// <summary> | |
| 27 /// This holds the path to the NaCl solution used in these tests. | |
| 28 /// The NaCl solution is a valid nacl/pepper plug-in VS solution. | |
| 29 /// It is copied into the testing deployment directory and opened in some te
sts. | |
| 30 /// Because unit-tests run in any order, the solution should not be written
to | |
| 31 /// in any tests. | |
| 32 /// </summary> | |
| 33 private static string naclSolution; | |
| 34 | |
| 35 /// <summary> | |
| 36 /// The main visual studio object. | |
| 37 /// </summary> | |
| 38 private DTE2 dte_; | |
| 39 | |
| 40 /// <summary> | |
| 41 /// Gets or sets the test context which provides information about, | |
| 42 /// and functionality for the current test run. | |
| 43 /// </summary> | |
| 44 public TestContext TestContext { get; set; } | |
| 45 | |
| 46 /// <summary> | |
| 47 /// This is run one time before any test methods are called. Here we set-up
a test-copy of a | |
| 48 /// new NaCl solution for use in the tests. | |
| 49 /// </summary> | |
| 50 /// <param name="testContext">Holds information about the current test run</
param> | |
| 51 [ClassInitialize] | |
| 52 public static void ClassSetup(TestContext testContext) | |
| 53 { | |
| 54 DTE2 dte = TestUtilities.StartVisualStudioInstance(); | |
| 55 try | |
| 56 { | |
| 57 naclSolution = TestUtilities.CreateBlankValidNaClSolution( | |
| 58 dte, | |
| 59 "PluginDebuggerHelperTest", | |
| 60 NativeClientVSAddIn.Strings.PepperPlatformName, | |
| 61 NativeClientVSAddIn.Strings.NaClPlatformName, | |
| 62 testContext); | |
| 63 } | |
| 64 finally | |
| 65 { | |
| 66 TestUtilities.CleanUpVisualStudioInstance(dte); | |
| 67 } | |
| 68 } | |
| 69 | |
| 70 /// <summary> | |
| 71 /// This is run before each test to create test resources. | |
| 72 /// </summary> | |
| 73 [TestInitialize] | |
| 74 public void TestSetup() | |
| 75 { | |
| 76 dte_ = TestUtilities.StartVisualStudioInstance(); | |
| 77 try | |
| 78 { | |
| 79 TestUtilities.AssertAddinLoaded(dte_, NativeClientVSAddIn.Strings.AddInN
ame); | |
| 80 } | |
| 81 catch | |
| 82 { | |
| 83 TestUtilities.CleanUpVisualStudioInstance(dte_); | |
| 84 throw; | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 /// <summary> | |
| 89 /// This is run after each test to clean up things created in TestSetup(). | |
| 90 /// </summary> | |
| 91 [TestCleanup] | |
| 92 public void TestCleanup() | |
| 93 { | |
| 94 TestUtilities.CleanUpVisualStudioInstance(dte_); | |
| 95 } | |
| 96 | |
| 97 /// <summary> | |
| 98 /// A test for PluginDebuggerHelper Constructor. | |
| 99 /// </summary> | |
| 100 [TestMethod] | |
| 101 public void PluginDebuggerHelperConstructorTest() | |
| 102 { | |
| 103 // Check that a null dte fails. | |
| 104 try | |
| 105 { | |
| 106 PluginDebuggerHelper nullDte = new PluginDebuggerHelper(null); | |
| 107 Assert.Fail("Using null DTE instance did not throw exception"); | |
| 108 } | |
| 109 catch (ArgumentNullException) | |
| 110 { | |
| 111 // This is expected for a correct implementation. | |
| 112 } | |
| 113 catch | |
| 114 { | |
| 115 Assert.Fail("Using null DTE instance threw something other than Argument
NullException"); | |
| 116 } | |
| 117 | |
| 118 PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(d
te_); | |
| 119 Assert.AreEqual(dte_, target.dte_); | |
| 120 Assert.IsNull(target.webServerOutputPane_); | |
| 121 Assert.IsFalse(target.isProperlyInitialized_); | |
| 122 } | |
| 123 | |
| 124 /// <summary> | |
| 125 /// This unit test verifies that the gdb init file is written correctly, | |
| 126 /// and old-existing GDB processes are cleaned up. | |
| 127 /// Verification of actual attachment is the responsibility of integration | |
| 128 /// tests and NaCl-GDB itself. | |
| 129 /// </summary> | |
| 130 [TestMethod] | |
| 131 [DeploymentItem("NativeClientVSAddIn.dll")] | |
| 132 public void AttachNaClGDBTest() | |
| 133 { | |
| 134 PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(d
te_); | |
| 135 string existingGDB = "AttachNaClGDBTest_existingGDB"; | |
| 136 try | |
| 137 { | |
| 138 target.pluginProjectDirectory_ = TestContext.DeploymentDirectory; | |
| 139 target.pluginAssembly_ = "fakeAssemblyString"; | |
| 140 target.irtPath_ = "fakeIrtPath"; | |
| 141 target.gdbPath_ = "python.exe"; | |
| 142 target.gdbProcess_ = TestUtilities.StartProcessForKilling(existingGDB, 2
0); | |
| 143 string existingInitFileName = Path.GetTempFileName(); | |
| 144 target.gdbInitFileName_ = existingInitFileName; | |
| 145 target.isProperlyInitialized_ = true; | |
| 146 | |
| 147 // Visual studio won't allow adding a breakpoint unless it is associated
with | |
| 148 // an existing file and valid line number, so use DummyLoopSolution. | |
| 149 dte_.Solution.Open(naclSolution); | |
| 150 string fileName = "main.cpp"; | |
| 151 string functionName = "DummyInstance::HandleMessage"; | |
| 152 int lineNumber = 35; | |
| 153 dte_.Debugger.Breakpoints.Add(Function: functionName); | |
| 154 dte_.Debugger.Breakpoints.Add(Line: lineNumber, File: fileName); | |
| 155 | |
| 156 target.AttachNaClGDB(null, new PluginDebuggerHelper.PluginFoundEventArgs
(0)); | |
| 157 | |
| 158 Assert.IsTrue(File.Exists(target.gdbInitFileName_), "Init file not writt
en"); | |
| 159 | |
| 160 string[] gdbCommands = File.ReadAllLines(target.gdbInitFileName_); | |
| 161 bool functionBP = false; | |
| 162 bool lineBP = false; | |
| 163 | |
| 164 // Validate that the commands contain what we specified. | |
| 165 // The syntax itself is not validated since this add-in is not responsib
le for | |
| 166 // the syntax and it could change. | |
| 167 foreach (string command in gdbCommands) | |
| 168 { | |
| 169 if (command.Contains(fileName) && command.Contains(lineNumber.ToString
())) | |
| 170 { | |
| 171 lineBP = true; | |
| 172 } | |
| 173 | |
| 174 if (command.Contains(functionName)) | |
| 175 { | |
| 176 functionBP = true; | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 Assert.IsFalse( | |
| 181 TestUtilities.DoesProcessExist("python.exe", existingGDB), | |
| 182 "Failed to kill existing GDB process"); | |
| 183 Assert.IsFalse( | |
| 184 File.Exists(existingInitFileName), | |
| 185 "Failed to delete existing temp gdb init file"); | |
| 186 Assert.IsTrue(lineBP, "Line breakpoint not properly set"); | |
| 187 Assert.IsTrue(functionBP, "Function breakpoint not properly set"); | |
| 188 } | |
| 189 finally | |
| 190 { | |
| 191 if (dte_.Debugger.Breakpoints != null) | |
| 192 { | |
| 193 // Remove all breakpoints. | |
| 194 foreach (EnvDTE.Breakpoint bp in dte_.Debugger.Breakpoints) | |
| 195 { | |
| 196 bp.Delete(); | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 if (!string.IsNullOrEmpty(target.gdbInitFileName_) && File.Exists(target
.gdbInitFileName_)) | |
| 201 { | |
| 202 File.Delete(target.gdbInitFileName_); | |
| 203 } | |
| 204 | |
| 205 if (target.gdbProcess_ != null && !target.gdbProcess_.HasExited) | |
| 206 { | |
| 207 target.gdbProcess_.Kill(); | |
| 208 target.gdbProcess_.Dispose(); | |
| 209 } | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 /// <summary> | |
| 214 /// A test for FindAndAttachToPlugin. | |
| 215 /// </summary> | |
| 216 [TestMethod] | |
| 217 [DeploymentItem("NativeClientVSAddIn.dll")] | |
| 218 public void FindAndAttachToPluginTest() | |
| 219 { | |
| 220 PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(d
te_); | |
| 221 target.isProperlyInitialized_ = true; | |
| 222 | |
| 223 MockProcessSearcher processResults = new MockProcessSearcher(); | |
| 224 target.debuggedChromeMainProcess_ = System.Diagnostics.Process.GetCurrentP
rocess(); | |
| 225 uint currentProcId = (uint)target.debuggedChromeMainProcess_.Id; | |
| 226 string naclCommandLine = Strings.NaClLoaderFlag; | |
| 227 | |
| 228 target.pluginAssembly_ = "testAssemblyPath"; | |
| 229 string pluginLoadFlag = string.Format( | |
| 230 Strings.PepperProcessPluginFlagFormat, target.pluginAssembly_); | |
| 231 string pepperCommandLine = string.Concat( | |
| 232 pluginLoadFlag, " ", Strings.ChromeRendererFlag); | |
| 233 | |
| 234 // Fake the list of processes on the system. | |
| 235 processResults.ProcessList.Add( | |
| 236 new ProcessInfo( | |
| 237 currentProcId, | |
| 238 currentProcId, | |
| 239 string.Empty, | |
| 240 Strings.NaClDebugFlag, | |
| 241 Strings.ChromeProcessName)); | |
| 242 processResults.ProcessList.Add( | |
| 243 new ProcessInfo(1, currentProcId, string.Empty, string.Empty, "MyParen
tProcess")); | |
| 244 processResults.ProcessList.Add( | |
| 245 new ProcessInfo(10, 1, string.Empty, pepperCommandLine, Strings.Chrome
ProcessName)); | |
| 246 processResults.ProcessList.Add( | |
| 247 new ProcessInfo(11, 1, string.Empty, naclCommandLine, Strings.NaClProc
essName)); | |
| 248 | |
| 249 // These two are missing some relevant command line args, they should not
be attached to. | |
| 250 processResults.ProcessList.Add( | |
| 251 new ProcessInfo(12, 1, string.Empty, pluginLoadFlag, Strings.ChromePro
cessName)); | |
| 252 processResults.ProcessList.Add( | |
| 253 new ProcessInfo(13, 1, string.Empty, string.Empty, Strings.NaClProcess
Name)); | |
| 254 | |
| 255 // These two don't have this process as their parent, so they should not b
e attached to. | |
| 256 processResults.ProcessList.Add( | |
| 257 new ProcessInfo(14, 14, string.Empty, pepperCommandLine, Strings.Chrom
eProcessName)); | |
| 258 processResults.ProcessList.Add( | |
| 259 new ProcessInfo(15, 15, string.Empty, naclCommandLine, Strings.NaClPro
cessName)); | |
| 260 | |
| 261 // Set the private value to the mock object (can't use accessor since no v
alid cast). | |
| 262 typeof(PluginDebuggerHelper).GetField( | |
| 263 "processSearcher_", | |
| 264 BindingFlags.NonPublic | BindingFlags.Instance).SetValue(target.Target
, processResults); | |
| 265 | |
| 266 // Test that the correct processes are attached to. | |
| 267 bool goodNaCl = false; | |
| 268 bool goodPepper = false; | |
| 269 var handler = new EventHandler<NativeClientVSAddIn.PluginDebuggerHelper.Pl
uginFoundEventArgs>( | |
| 270 delegate(object unused, NativeClientVSAddIn.PluginDebuggerHelper.PluginF
oundEventArgs args) | |
| 271 { | |
| 272 switch (args.ProcessID) | |
| 273 { | |
| 274 case 10: | |
| 275 if (goodPepper) | |
| 276 { | |
| 277 Assert.Fail("Should not attach twice to same pepper process"); | |
| 278 } | |
| 279 | |
| 280 if (target.projectPlatformType_ == | |
| 281 PluginDebuggerHelper_Accessor.ProjectPlatformType.NaCl) | |
| 282 { | |
| 283 Assert.Fail("Attached to pepper process when NaCl was the target
"); | |
| 284 } | |
| 285 | |
| 286 goodPepper = true; | |
| 287 break; | |
| 288 case 11: | |
| 289 if (goodNaCl) | |
| 290 { | |
| 291 Assert.Fail("Should not attach twice to same nacl process"); | |
| 292 } | |
| 293 | |
| 294 if (target.projectPlatformType_ == | |
| 295 PluginDebuggerHelper_Accessor.ProjectPlatformType.Pepper) | |
| 296 { | |
| 297 Assert.Fail("Attached to nacl process when pepper was the target
"); | |
| 298 } | |
| 299 | |
| 300 goodNaCl = true; | |
| 301 break; | |
| 302 case 12: | |
| 303 Assert.Fail("Should not attach to pepper process with bad args"); | |
| 304 break; | |
| 305 case 13: | |
| 306 Assert.Fail("Should not attach to nacl process with bad args"); | |
| 307 break; | |
| 308 case 14: | |
| 309 Assert.Fail("Should not attach to pepper process that is not " | |
| 310 + "descendant of Visual Studio"); | |
| 311 break; | |
| 312 case 15: | |
| 313 Assert.Fail("Should not attach to nacl process that is not " | |
| 314 + "descendant of Visual Studio"); | |
| 315 break; | |
| 316 default: | |
| 317 Assert.Fail("Should not attach to non-pepper/non-nacl process"); | |
| 318 break; | |
| 319 } | |
| 320 }); | |
| 321 | |
| 322 target.add_PluginFoundEvent(handler); | |
| 323 target.projectPlatformType_ = PluginDebuggerHelper_Accessor.ProjectPlatfor
mType.Pepper; | |
| 324 target.FindAndAttachToPlugin(null, null); | |
| 325 target.projectPlatformType_ = PluginDebuggerHelper_Accessor.ProjectPlatfor
mType.NaCl; | |
| 326 target.FindAndAttachToPlugin(null, null); | |
| 327 target.remove_PluginFoundEvent(handler); | |
| 328 Assert.IsTrue(goodPepper, "Failed to attach to pepper process"); | |
| 329 Assert.IsTrue(goodNaCl, "Failed to attach to NaCl process"); | |
| 330 } | |
| 331 | |
| 332 /// <summary> | |
| 333 /// A test for LoadProjectSettings. | |
| 334 /// </summary> | |
| 335 [TestMethod] | |
| 336 public void LoadProjectSettingsTest() | |
| 337 { | |
| 338 string expectedSDKRootDir = | |
| 339 Environment.GetEnvironmentVariable(Strings.SDKPathEnvironmentVariable)
; | |
| 340 Assert.IsNotNull(expectedSDKRootDir, "SDK Path environment variable not se
t!"); | |
| 341 | |
| 342 PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(d
te_); | |
| 343 target.isProperlyInitialized_ = false; | |
| 344 try | |
| 345 { | |
| 346 target.LoadProjectSettings(); | |
| 347 Assert.Fail("Initializing with no loaded solution shouldn't succeed"); | |
| 348 } | |
| 349 catch (ArgumentOutOfRangeException) | |
| 350 { | |
| 351 // This is expected for a correct implementation. | |
| 352 } | |
| 353 | |
| 354 dte_.Solution.Open(naclSolution); | |
| 355 | |
| 356 // Setting the start-up project to a non-cpp project should make loading f
ail. | |
| 357 object[] badStartupProj = { TestUtilities.NotNaClProjectUniqueName }; | |
| 358 dte_.Solution.SolutionBuild.StartupProjects = badStartupProj; | |
| 359 Assert.IsFalse(target.LoadProjectSettings()); | |
| 360 Assert.IsFalse(target.isProperlyInitialized_); | |
| 361 | |
| 362 // Setting the start-up project to correct C++ project, but also setting t
he platform | |
| 363 // to non-nacl/pepper should make loading fail. | |
| 364 object[] startupProj = { TestUtilities.BlankNaClProjectUniqueName }; | |
| 365 dte_.Solution.SolutionBuild.StartupProjects = startupProj; | |
| 366 TestUtilities.SetSolutionConfiguration( | |
| 367 dte_, TestUtilities.BlankNaClProjectUniqueName, "Debug", "Win32"); | |
| 368 Assert.IsFalse(target.LoadProjectSettings()); | |
| 369 Assert.IsFalse(target.isProperlyInitialized_); | |
| 370 | |
| 371 // Setting the platform to NaCl should make loading succeed. | |
| 372 TestUtilities.SetSolutionConfiguration( | |
| 373 dte_, TestUtilities.BlankNaClProjectUniqueName, "Debug", Strings.NaClP
latformName); | |
| 374 Assert.IsTrue(target.LoadProjectSettings()); | |
| 375 Assert.IsTrue(target.isProperlyInitialized_); | |
| 376 Assert.AreEqual( | |
| 377 PluginDebuggerHelper_Accessor.ProjectPlatformType.NaCl, | |
| 378 target.projectPlatformType_); | |
| 379 | |
| 380 string projectDir = Path.Combine( | |
| 381 Path.GetDirectoryName(naclSolution), | |
| 382 Path.GetDirectoryName(TestUtilities.BlankNaClProjectUniqueName)) + @"\
"; | |
| 383 string outputDir = Path.Combine(projectDir, "newlib") + @"\"; | |
| 384 string assembly = Path.Combine(outputDir, TestUtilities.BlankNaClProjectNa
me + ".nexe"); | |
| 385 | |
| 386 Assert.AreEqual(projectDir, target.pluginProjectDirectory_); | |
| 387 Assert.AreEqual(outputDir, target.pluginOutputDirectory_); | |
| 388 Assert.AreEqual(assembly, target.pluginAssembly_); | |
| 389 | |
| 390 Assert.AreEqual(expectedSDKRootDir, target.sdkRootDirectory_); | |
| 391 Assert.AreEqual("python.exe", target.webServerExecutable_); | |
| 392 | |
| 393 // Setting platform to Pepper should make succeed. | |
| 394 TestUtilities.SetSolutionConfiguration( | |
| 395 dte_, TestUtilities.BlankNaClProjectUniqueName, "Debug", Strings.Peppe
rPlatformName); | |
| 396 Assert.IsTrue(target.LoadProjectSettings()); | |
| 397 Assert.IsTrue(target.isProperlyInitialized_); | |
| 398 Assert.AreEqual( | |
| 399 PluginDebuggerHelper_Accessor.ProjectPlatformType.Pepper, | |
| 400 target.projectPlatformType_); | |
| 401 | |
| 402 outputDir = Path.Combine(projectDir, "win") + @"\"; | |
| 403 assembly = Path.Combine(outputDir, TestUtilities.BlankNaClProjectName + ".
dll"); | |
| 404 Assert.AreEqual(projectDir, target.pluginProjectDirectory_); | |
| 405 Assert.AreEqual(outputDir, target.pluginOutputDirectory_); | |
| 406 Assert.AreEqual(assembly, target.pluginAssembly_); | |
| 407 | |
| 408 Assert.AreEqual(expectedSDKRootDir, target.sdkRootDirectory_); | |
| 409 Assert.AreEqual("python.exe", target.webServerExecutable_); | |
| 410 } | |
| 411 | |
| 412 /// <summary> | |
| 413 /// Checks that VS properly attaches debugger. | |
| 414 /// </summary> | |
| 415 [TestMethod] | |
| 416 [DeploymentItem("NativeClientVSAddIn.dll")] | |
| 417 public void AttachVSDebuggerTest() | |
| 418 { | |
| 419 using (System.Diagnostics.Process dummyProc = TestUtilities.StartProcessFo
rKilling( | |
| 420 "DummyProc", 20)) | |
| 421 { | |
| 422 try | |
| 423 { | |
| 424 PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Access
or(dte_); | |
| 425 target.projectPlatformType_ = PluginDebuggerHelper_Accessor.ProjectPla
tformType.Pepper; | |
| 426 target.isProperlyInitialized_ = true; | |
| 427 | |
| 428 var pluginFoundArgs = new NativeClientVSAddIn.PluginDebuggerHelper.Plu
ginFoundEventArgs( | |
| 429 (uint)dummyProc.Id); | |
| 430 target.AttachVSDebugger(null, pluginFoundArgs); | |
| 431 | |
| 432 bool isBeingDebugged = false; | |
| 433 foreach (EnvDTE.Process proc in dte_.Debugger.DebuggedProcesses) | |
| 434 { | |
| 435 if (proc.ProcessID == dummyProc.Id) | |
| 436 { | |
| 437 isBeingDebugged = true; | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 Assert.IsTrue(isBeingDebugged, "Visual Studio debugger did not attach"
); | |
| 442 } | |
| 443 finally | |
| 444 { | |
| 445 if (dummyProc != null && !dummyProc.HasExited) | |
| 446 { | |
| 447 dummyProc.Kill(); | |
| 448 dummyProc.Dispose(); | |
| 449 } | |
| 450 } | |
| 451 } | |
| 452 } | |
| 453 | |
| 454 /// <summary> | |
| 455 /// A test for StartDebugging. | |
| 456 /// </summary> | |
| 457 [TestMethod] | |
| 458 public void StartDebuggingTest() | |
| 459 { | |
| 460 PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(d
te_); | |
| 461 | |
| 462 // Neutralize StartWebServer by providing dummy executable settings. | |
| 463 target.webServerExecutable_ = "python.exe"; | |
| 464 target.webServerArguments_ = "-c \"print 'test'\""; | |
| 465 target.pluginProjectDirectory_ = TestContext.DeploymentDirectory; | |
| 466 | |
| 467 // Have the timer call a function to set success to true. | |
| 468 ManualResetEvent finderSuccess = new ManualResetEvent(false); | |
| 469 target.pluginFinderTimer_ = new System.Windows.Forms.Timer(); | |
| 470 target.pluginFinderTimer_.Tick += (a, b) => { finderSuccess.Set(); }; | |
| 471 | |
| 472 // Check that an exception is thrown if not initialized properly. | |
| 473 target.isProperlyInitialized_ = false; | |
| 474 try | |
| 475 { | |
| 476 target.StartDebugging(); | |
| 477 Assert.Fail("Debugging started when not initialized"); | |
| 478 } | |
| 479 catch (Exception) | |
| 480 { | |
| 481 // Expected in a proper implementation. | |
| 482 } | |
| 483 | |
| 484 // Properly start debugging and wait for event signal. | |
| 485 target.isProperlyInitialized_ = true; | |
| 486 target.StartDebugging(); | |
| 487 | |
| 488 // Pump events waiting for signal, time-out after 10 seconds. | |
| 489 bool success = false; | |
| 490 for (int i = 0; i < 20; i++) | |
| 491 { | |
| 492 System.Windows.Forms.Application.DoEvents(); | |
| 493 if (finderSuccess.WaitOne(500)) | |
| 494 { | |
| 495 success = true; | |
| 496 break; | |
| 497 } | |
| 498 } | |
| 499 | |
| 500 Assert.IsTrue(success, "Plug-in finder timer did not fire"); | |
| 501 } | |
| 502 | |
| 503 /// <summary> | |
| 504 /// This tests that StartWebServer executes webServerExecutable_ with webSer
verArguments_ | |
| 505 /// as arguments, sets the working directory to the project directory, and h
ooks | |
| 506 /// up stdout and stderr from the web server to the Web Server output panel
in VS. | |
| 507 /// This test implicitly covers WebServerMessageReceive. | |
| 508 /// </summary> | |
| 509 [TestMethod] | |
| 510 [DeploymentItem("NativeClientVSAddIn.dll")] | |
| 511 public void StartWebServerTest() | |
| 512 { | |
| 513 PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(d
te_); | |
| 514 try | |
| 515 { | |
| 516 string successMessage = "successful test!"; | |
| 517 string stderrMessage = "stderr test"; | |
| 518 target.webServerExecutable_ = "python.exe"; | |
| 519 | |
| 520 // To save pain, if modifying this in the future avoid special character
s, | |
| 521 // or make sure to double escape them. Ex: \n --> \\n. | |
| 522 string program = | |
| 523 "import os;" + | |
| 524 "import sys;" + | |
| 525 string.Format("sys.stdout.write('{0}');", successMessage) + | |
| 526 string.Format("sys.stderr.write('{0}');", stderrMessage) + | |
| 527 "sys.stdout.write(os.getcwd());" + | |
| 528 "sys.stdout.flush();" + | |
| 529 "sys.stderr.flush()"; | |
| 530 target.webServerArguments_ = string.Format("-c \"{0}\"", program); | |
| 531 target.pluginProjectDirectory_ = TestContext.DeploymentDirectory; | |
| 532 target.isProperlyInitialized_ = true; | |
| 533 target.StartWebServer(); | |
| 534 | |
| 535 // Check that the output pane exists. | |
| 536 EnvDTE.OutputWindowPane window = dte_.ToolWindows.OutputWindow.OutputWin
dowPanes.Item( | |
| 537 Strings.WebServerOutputWindowTitle); | |
| 538 Assert.IsNotNull(window, "Web server output pane failed to create"); | |
| 539 | |
| 540 // Wait for results to arrive for up to 10 seconds, checking every 0.5 s
econds. | |
| 541 string result = TestUtilities.GetPaneText(target.webServerOutputPane_); | |
| 542 for (int repeat = 0; repeat < 20; repeat++) | |
| 543 { | |
| 544 if (result != null && | |
| 545 result.Contains(successMessage) && | |
| 546 result.Contains(stderrMessage) && | |
| 547 result.Contains(TestContext.DeploymentDirectory)) | |
| 548 { | |
| 549 break; | |
| 550 } | |
| 551 | |
| 552 System.Threading.Thread.Sleep(500); | |
| 553 result = TestUtilities.GetPaneText(target.webServerOutputPane_); | |
| 554 } | |
| 555 | |
| 556 Assert.IsFalse(string.IsNullOrEmpty(result), "Nothing printed to output
pane"); | |
| 557 StringAssert.Contains( | |
| 558 result, | |
| 559 successMessage, | |
| 560 "Executable did not successfully run given arguments"); | |
| 561 StringAssert.Contains( | |
| 562 result, | |
| 563 TestContext.DeploymentDirectory, | |
| 564 "Web server working directory was not set to project directory"); | |
| 565 StringAssert.Contains(result, stderrMessage, "Standard error message was
not captured"); | |
| 566 } | |
| 567 finally | |
| 568 { | |
| 569 if (!target.webServer_.WaitForExit(1000)) | |
| 570 { | |
| 571 target.webServer_.Kill(); | |
| 572 target.webServer_.Dispose(); | |
| 573 } | |
| 574 } | |
| 575 } | |
| 576 | |
| 577 /// <summary> | |
| 578 /// Ensures that StopDebugging() kills GDB and the web server, and resets th
e state of | |
| 579 /// PluginDebuggerHelper to before debugging started. | |
| 580 /// Implicitly tests KillGDBProcess(). | |
| 581 /// </summary> | |
| 582 [TestMethod] | |
| 583 public void StopDebuggingTest() | |
| 584 { | |
| 585 PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(d
te_); | |
| 586 string webServerIdentifier = "StartVisualStudioInstance_TestWebServer"; | |
| 587 string gdbIdentifier = "StartVisualStudioInstance_TestGDB"; | |
| 588 | |
| 589 // Set up items that should exist given a successful calling of StartDebug
ging(). | |
| 590 target.gdbInitFileName_ = Path.GetTempFileName(); | |
| 591 target.pluginFinderForbiddenPids_.Add(123); | |
| 592 target.webServer_ = TestUtilities.StartProcessForKilling(webServerIdentifi
er, 20); | |
| 593 target.gdbProcess_ = TestUtilities.StartProcessForKilling(gdbIdentifier, 2
0); | |
| 594 target.isProperlyInitialized_ = true; | |
| 595 | |
| 596 target.StopDebugging(); | |
| 597 | |
| 598 Assert.IsFalse(target.isProperlyInitialized_, "Failed to set initialized s
tate to false"); | |
| 599 Assert.IsFalse(target.pluginFinderTimer_.Enabled, "Plug-in finder timer no
t stopped"); | |
| 600 Assert.IsFalse( | |
| 601 TestUtilities.DoesProcessExist("python.exe", webServerIdentifier), | |
| 602 "Failed to kill web server process"); | |
| 603 Assert.IsFalse( | |
| 604 TestUtilities.DoesProcessExist("python.exe", gdbIdentifier), | |
| 605 "Failed to kill gdb process"); | |
| 606 Assert.IsFalse( | |
| 607 File.Exists(target.gdbInitFileName_), | |
| 608 "Failed to delete temp gdb init file"); | |
| 609 Assert.IsTrue( | |
| 610 target.pluginFinderForbiddenPids_.Count == 0, | |
| 611 "Plugin finder Process IDs not cleared"); | |
| 612 } | |
| 613 | |
| 614 /// <summary> | |
| 615 /// A test for WebServerWriteLine. | |
| 616 /// </summary> | |
| 617 [TestMethod] | |
| 618 [DeploymentItem("NativeClientVSAddIn.dll")] | |
| 619 public void WebServerWriteLineTest() | |
| 620 { | |
| 621 PluginDebuggerHelper_Accessor target = new PluginDebuggerHelper_Accessor(d
te_); | |
| 622 string successMessage = "successful test!"; | |
| 623 target.webServerOutputPane_ = dte_.ToolWindows.OutputWindow.OutputWindowPa
nes.Add( | |
| 624 Strings.WebServerOutputWindowTitle); | |
| 625 target.isProperlyInitialized_ = true; | |
| 626 target.WebServerWriteLine(successMessage); | |
| 627 string result = TestUtilities.GetPaneText(target.webServerOutputPane_); | |
| 628 | |
| 629 // Wait for results to arrive for up to 10 seconds, checking every 0.5 sec
onds. | |
| 630 for (int repeat = 0; repeat < 20; repeat++) | |
| 631 { | |
| 632 if (result != null && | |
| 633 result.Contains(successMessage)) | |
| 634 { | |
| 635 break; | |
| 636 } | |
| 637 | |
| 638 System.Threading.Thread.Sleep(500); | |
| 639 result = TestUtilities.GetPaneText(target.webServerOutputPane_); | |
| 640 } | |
| 641 | |
| 642 StringAssert.Contains(result, successMessage, "Message failed to print"); | |
| 643 } | |
| 644 } | |
| 645 } | |
| OLD | NEW |