ForceDriverTests.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. using UICatalog;
  2. using Xunit.Abstractions;
  3. namespace IntegrationTests.UICatalog;
  4. /// <summary>
  5. /// Integration tests for ForceDriver persistence when opening scenarios in UICatalog.
  6. /// </summary>
  7. public class ForceDriverTests
  8. {
  9. private readonly ITestOutputHelper _output;
  10. public ForceDriverTests (ITestOutputHelper output)
  11. {
  12. _output = output;
  13. }
  14. /// <summary>
  15. /// Tests that ForceDriver persists when running UICatalogTop and then opening a scenario.
  16. ///
  17. /// This test verifies the fix for issue #4391 works correctly by calling UICatalog's actual methods.
  18. ///
  19. /// THE BUG: Without the fix, ForceDriver was set directly on Application, but
  20. /// ConfigurationManager would override it from config files when scenarios ran.
  21. ///
  22. /// THE FIX has two parts (both in UICatalog.cs):
  23. /// 1. SetupForceDriverConfig() - Sets ForceDriver in ConfigurationManager.RuntimeConfig
  24. /// 2. ReloadForceDriverConfig() - Reloads RuntimeConfig before each scenario
  25. ///
  26. /// This test calls both UICatalog methods to verify the fix works.
  27. /// If you remove the calls to these methods or modify UICatalog.cs to remove the fix,
  28. /// this test will fail.
  29. /// </summary>
  30. [Fact]
  31. public void ForceDriver_Persists_From_UICatalogTop_To_Scenario ()
  32. {
  33. // Arrange
  34. const string expectedDriver = "fake";
  35. ConfigurationManager.Disable (true);
  36. Application.ResetState (true);
  37. // Initialize UICatalog.Options (required by UICatalogTop)
  38. global::UICatalog.UICatalog.Options = new UICatalogCommandLineOptions
  39. {
  40. Driver = expectedDriver,
  41. DontEnableConfigurationManagement = false,
  42. Scenario = "none",
  43. BenchmarkTimeout = 2500,
  44. Benchmark = false,
  45. ResultsFile = string.Empty,
  46. DebugLogLevel = "Warning"
  47. };
  48. // Initialize cached scenarios (required by UICatalogTop)
  49. UICatalogTop.CachedScenarios = Scenario.GetScenarios ();
  50. // Call UICatalog's setup method (this is part 1 of the fix in UICatalog.cs)
  51. // This sets ForceDriver in RuntimeConfig
  52. global::UICatalog.UICatalog.SetupForceDriverConfig (expectedDriver);
  53. // Enable ConfigurationManager with all locations (as UICatalog does)
  54. ConfigurationManager.Enable (ConfigLocations.All);
  55. var topLevelDriverName = string.Empty;
  56. var scenarioDriverName = string.Empty;
  57. var iterationCount = 0;
  58. EventHandler<IterationEventArgs>? iterationHandler = null;
  59. try
  60. {
  61. // Phase 1: Run UICatalogTop (simulating main UI)
  62. _output.WriteLine ("=== Phase 1: Running UICatalogTop ===");
  63. Application.Init ();
  64. topLevelDriverName = Application.Driver?.GetName () ?? string.Empty;
  65. _output.WriteLine ($"UICatalogTop driver: {topLevelDriverName}");
  66. var top = new UICatalogTop ();
  67. // Set up to automatically select a scenario and stop
  68. iterationHandler = (sender, e) =>
  69. {
  70. iterationCount++;
  71. // On first iteration, select a scenario and request stop
  72. if (iterationCount == 1)
  73. {
  74. // Select the first scenario
  75. if (UICatalogTop.CachedScenarios is { Count: > 0 })
  76. {
  77. UICatalogTop.CachedSelectedScenario =
  78. (Scenario)Activator.CreateInstance (UICatalogTop.CachedScenarios[0].GetType ())!;
  79. Application.RequestStop ();
  80. }
  81. }
  82. };
  83. Application.Iteration += iterationHandler;
  84. Application.Run (top);
  85. Application.Iteration -= iterationHandler;
  86. top.Dispose ();
  87. Application.Shutdown ();
  88. _output.WriteLine ($"Selected scenario: {UICatalogTop.CachedSelectedScenario?.GetName ()}");
  89. _output.WriteLine ($"UICatalogTop completed after {iterationCount} iterations");
  90. // Phase 2: Run the selected scenario (simulating what UICatalog.cs does)
  91. if (UICatalogTop.CachedSelectedScenario is { } scenario)
  92. {
  93. _output.WriteLine ($"\n=== Phase 2: Running scenario '{scenario.GetName ()}' ===");
  94. // Call UICatalog's reload method (this is part 2 of the fix in UICatalog.cs)
  95. // This ensures ForceDriver persists across Init/Shutdown cycles
  96. global::UICatalog.UICatalog.ReloadForceDriverConfig ();
  97. _output.WriteLine ("Reloaded ForceDriver config via UICatalog.ReloadForceDriverConfig()");
  98. // Track the driver used inside the scenario
  99. string? driverInsideScenario = null;
  100. EventHandler<EventArgs<bool>>? initHandler = null;
  101. EventHandler<IterationEventArgs>? scenarioIterationHandler = null;
  102. initHandler = (s, e) =>
  103. {
  104. if (e.Value)
  105. {
  106. driverInsideScenario = Application.Driver?.GetName ();
  107. // Request stop immediately so the scenario doesn't actually run
  108. scenarioIterationHandler = (_, _) =>
  109. {
  110. Application.RequestStop ();
  111. // Remove immediately to avoid assertions in Shutdown
  112. if (scenarioIterationHandler != null)
  113. {
  114. Application.Iteration -= scenarioIterationHandler;
  115. scenarioIterationHandler = null;
  116. }
  117. };
  118. Application.Iteration += scenarioIterationHandler;
  119. }
  120. };
  121. Application.InitializedChanged += initHandler;
  122. // Run the scenario's Main() method (this is what UICatalog does)
  123. scenario.Main ();
  124. scenarioDriverName = driverInsideScenario ?? string.Empty;
  125. Application.InitializedChanged -= initHandler;
  126. scenario.Dispose ();
  127. _output.WriteLine ($"Scenario driver: {scenarioDriverName}");
  128. _output.WriteLine ("Scenario completed and disposed");
  129. }
  130. else
  131. {
  132. _output.WriteLine ("ERROR: No scenario was selected");
  133. Assert.Fail ("No scenario was selected");
  134. }
  135. // Assert
  136. _output.WriteLine ($"\n=== Results ===");
  137. _output.WriteLine ($"UICatalogTop driver: {topLevelDriverName}");
  138. _output.WriteLine ($"Scenario driver: {scenarioDriverName}");
  139. Assert.Equal (expectedDriver, topLevelDriverName);
  140. Assert.Equal (expectedDriver, scenarioDriverName);
  141. _output.WriteLine ($"SUCCESS: Driver '{expectedDriver}' persisted from UICatalogTop to scenario");
  142. }
  143. finally
  144. {
  145. if (iterationHandler != null)
  146. {
  147. Application.Iteration -= iterationHandler;
  148. }
  149. ConfigurationManager.Disable (true);
  150. Application.ResetState (true);
  151. }
  152. }
  153. /// <summary>
  154. /// Tests that ForceDriver persists when running multiple scenarios in sequence.
  155. ///
  156. /// This verifies the fix works correctly by calling UICatalog's ReloadForceDriverConfig() method.
  157. ///
  158. /// THE FIX: ReloadForceDriverConfig() in UICatalog.cs reloads RuntimeConfig before each scenario.
  159. /// Without calling this method, the driver would revert to platform default.
  160. /// </summary>
  161. [Fact]
  162. public void ForceDriver_Persists_Across_Multiple_Scenarios ()
  163. {
  164. // Arrange
  165. const string expectedDriver = "fake";
  166. ConfigurationManager.Disable (true);
  167. Application.ResetState (true);
  168. // Initialize UICatalog.Options
  169. global::UICatalog.UICatalog.Options = new UICatalogCommandLineOptions
  170. {
  171. Driver = expectedDriver,
  172. DontEnableConfigurationManagement = false,
  173. Scenario = "none",
  174. BenchmarkTimeout = 2500,
  175. Benchmark = false,
  176. ResultsFile = string.Empty,
  177. DebugLogLevel = "Warning"
  178. };
  179. // Call UICatalog's setup method (this is part 1 of the fix in UICatalog.cs)
  180. global::UICatalog.UICatalog.SetupForceDriverConfig (expectedDriver);
  181. // Enable ConfigurationManager
  182. ConfigurationManager.Enable (ConfigLocations.All);
  183. string? driver1 = null;
  184. string? driver2 = null;
  185. EventHandler<EventArgs<bool>>? initHandler1 = null;
  186. EventHandler<EventArgs<bool>>? initHandler2 = null;
  187. EventHandler<IterationEventArgs>? iterHandler1 = null;
  188. EventHandler<IterationEventArgs>? iterHandler2 = null;
  189. try
  190. {
  191. // Get two different scenarios to test
  192. var scenarios = Scenario.GetScenarios ();
  193. Assert.True (scenarios.Count >= 2, "Need at least 2 scenarios for this test");
  194. var scenario1 = scenarios[0];
  195. var scenario2 = scenarios[1];
  196. _output.WriteLine ($"Testing with scenarios: {scenario1.GetName ()} and {scenario2.GetName ()}");
  197. // Run scenario 1
  198. initHandler1 = (s, e) =>
  199. {
  200. if (e.Value)
  201. {
  202. driver1 = Application.Driver?.GetName ();
  203. iterHandler1 = (_, _) =>
  204. {
  205. Application.RequestStop ();
  206. // Remove immediately to avoid assertions in Shutdown
  207. if (iterHandler1 != null)
  208. {
  209. Application.Iteration -= iterHandler1;
  210. iterHandler1 = null;
  211. }
  212. };
  213. Application.Iteration += iterHandler1;
  214. }
  215. };
  216. Application.InitializedChanged += initHandler1;
  217. scenario1.Main ();
  218. Application.InitializedChanged -= initHandler1;
  219. scenario1.Dispose ();
  220. _output.WriteLine ($"Scenario 1 completed with driver: {driver1}");
  221. // Call UICatalog's reload method (this is part 2 of the fix in UICatalog.cs)
  222. // This ensures ForceDriver persists across Init/Shutdown cycles
  223. global::UICatalog.UICatalog.ReloadForceDriverConfig ();
  224. _output.WriteLine ("Reloaded ForceDriver config via UICatalog.ReloadForceDriverConfig()");
  225. // Run scenario 2
  226. // Run scenario 2
  227. initHandler2 = (s, e) =>
  228. {
  229. if (e.Value)
  230. {
  231. driver2 = Application.Driver?.GetName ();
  232. iterHandler2 = (_, _) =>
  233. {
  234. Application.RequestStop ();
  235. // Remove immediately to avoid assertions in Shutdown
  236. if (iterHandler2 != null)
  237. {
  238. Application.Iteration -= iterHandler2;
  239. iterHandler2 = null;
  240. }
  241. };
  242. Application.Iteration += iterHandler2;
  243. }
  244. };
  245. Application.InitializedChanged += initHandler2;
  246. scenario2.Main ();
  247. Application.InitializedChanged -= initHandler2;
  248. scenario2.Dispose ();
  249. _output.WriteLine ($"Scenario 2 completed with driver: {driver2}");
  250. // Assert
  251. Assert.Equal (expectedDriver, driver1);
  252. Assert.Equal (expectedDriver, driver2);
  253. _output.WriteLine ($"SUCCESS: Driver '{expectedDriver}' persisted across both scenarios");
  254. }
  255. finally
  256. {
  257. // Cleanup any remaining handlers
  258. if (initHandler1 != null)
  259. {
  260. Application.InitializedChanged -= initHandler1;
  261. }
  262. if (iterHandler2 != null)
  263. {
  264. Application.InitializedChanged -= initHandler2;
  265. }
  266. if (iterHandler1 != null)
  267. {
  268. Application.Iteration -= iterHandler1;
  269. }
  270. if (iterHandler2 != null)
  271. {
  272. Application.Iteration -= iterHandler2;
  273. }
  274. ConfigurationManager.Disable (true);
  275. Application.ResetState (true);
  276. }
  277. }
  278. }