@joebigelow / wix-1 / commits / c8b602e5

Add test that cancels an MSI package in the OnProgress for the package.

This makes it cancel after the MSI install completed but before Burn considers the package complete, which needs to cause Burn to roll it back (#3089). Also add more logging in TestBA when it does non-standard stuff.

Sean Hall committed Jan 22, 2021 at 15:59 UTC c8b602e595bced83dad206ce40189634432f1f07
3 files changed +107 -2
src/Utilities/TestBA/TestBA.cs
+69 -2
@@ -29,6 +29,8 @@ namespace WixToolset.Test.BA
29 private int cancelCacheAtProgress;
30 private int sleepDuringExecute;
31 private int cancelExecuteAtProgress;
32 + private string cancelExecuteActionName;
33 + private int cancelOnProgressAtProgress;
34 private int retryExecuteFilesInUse;
35
36 private IBootstrapperCommand Command { get; }
@@ -227,24 +229,34 @@ namespace WixToolset.Test.BA
229 {
230 this.sleepDuringCache = 0;
231 }
232 + else
233 + {
234 + this.Log(" SlowCache: {0}", this.sleepDuringCache);
235 + }
236
237 string cancelCache = this.ReadPackageAction(args.PackageId, "CancelCacheAtProgress");
238 if (String.IsNullOrEmpty(cancelCache) || !Int32.TryParse(cancelCache, out this.cancelCacheAtProgress))
239 {
240 this.cancelCacheAtProgress = -1;
241 }
242 + else
243 + {
244 + this.Log(" CancelCacheAtProgress: {0}", this.cancelCacheAtProgress);
245 + }
246 }
247
248 protected override void OnCacheAcquireProgress(CacheAcquireProgressEventArgs args)
249 {
250 this.Log("OnCacheAcquireProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage);
251
242 - if (this.cancelCacheAtProgress > 0 && this.cancelCacheAtProgress <= args.Progress)
252 + if (this.cancelCacheAtProgress >= 0 && this.cancelCacheAtProgress <= args.Progress)
253 {
254 args.Cancel = true;
255 + this.Log("OnCacheAcquireProgress(cancel)");
256 }
257 else if (this.sleepDuringCache > 0)
258 {
259 + this.Log("OnCacheAcquireProgress(sleep {0})", this.sleepDuringCache);
260 Thread.Sleep(this.sleepDuringCache);
261 }
262 }
@@ -258,18 +270,46 @@ namespace WixToolset.Test.BA
270 {
271 this.sleepDuringExecute = 0;
272 }
273 + else
274 + {
275 + this.Log(" SlowExecute: {0}", this.sleepDuringExecute);
276 + }
277
278 string cancelExecute = this.ReadPackageAction(args.PackageId, "CancelExecuteAtProgress");
279 if (String.IsNullOrEmpty(cancelExecute) || !Int32.TryParse(cancelExecute, out this.cancelExecuteAtProgress))
280 {
281 this.cancelExecuteAtProgress = -1;
282 }
283 + else
284 + {
285 + this.Log(" CancelExecuteAtProgress: {0}", this.cancelExecuteAtProgress);
286 + }
287 +
288 + this.cancelExecuteActionName = this.ReadPackageAction(args.PackageId, "CancelExecuteAtActionStart");
289 + if (!String.IsNullOrEmpty(this.cancelExecuteActionName))
290 + {
291 + this.Log(" CancelExecuteAtActionState: {0}", this.cancelExecuteActionName);
292 + }
293 +
294 + string cancelOnProgressAtProgress = this.ReadPackageAction(args.PackageId, "CancelOnProgressAtProgress");
295 + if (String.IsNullOrEmpty(cancelOnProgressAtProgress) || !Int32.TryParse(cancelOnProgressAtProgress, out this.cancelOnProgressAtProgress))
296 + {
297 + this.cancelOnProgressAtProgress = -1;
298 + }
299 + else
300 + {
301 + this.Log(" CancelOnProgressAtProgress: {0}", this.cancelOnProgressAtProgress);
302 + }
303
304 string retryBeforeCancel = this.ReadPackageAction(args.PackageId, "RetryExecuteFilesInUse");
305 if (String.IsNullOrEmpty(retryBeforeCancel) || !Int32.TryParse(retryBeforeCancel, out this.retryExecuteFilesInUse))
306 {
307 this.retryExecuteFilesInUse = 0;
308 }
309 + else
310 + {
311 + this.Log(" RetryExecuteFilesInUse: {0}", this.retryExecuteFilesInUse);
312 + }
313 }
314
315 protected override void OnExecuteFilesInUse(ExecuteFilesInUseEventArgs args)
@@ -287,16 +327,30 @@ namespace WixToolset.Test.BA
327 }
328 }
329
330 + protected override void OnExecuteMsiMessage(ExecuteMsiMessageEventArgs args)
331 + {
332 + this.Log("OnExecuteMsiMessage() - MessageType: {0}, Message: {1}, Data: '{2}'", args.MessageType, args.Message, String.Join("','", args.Data.ToArray()));
333 +
334 + if (!String.IsNullOrEmpty(this.cancelExecuteActionName) && args.MessageType == InstallMessage.ActionStart &&
335 + args.Data.Count > 0 && args.Data[0] == this.cancelExecuteActionName)
336 + {
337 + this.Log("OnExecuteMsiMessage(cancelNextProgress)");
338 + this.cancelExecuteAtProgress = 0;
339 + }
340 + }
341 +
342 protected override void OnExecuteProgress(ExecuteProgressEventArgs args)
343 {
344 this.Log("OnExecuteProgress() - package: {0}, progress: {1}%, overall progress: {2}%", args.PackageId, args.ProgressPercentage, args.OverallPercentage);
345
294 - if (this.cancelExecuteAtProgress > 0 && this.cancelExecuteAtProgress <= args.ProgressPercentage)
346 + if (this.cancelExecuteAtProgress >= 0 && this.cancelExecuteAtProgress <= args.ProgressPercentage)
347 {
348 args.Cancel = true;
349 + this.Log("OnExecuteProgress(cancel)");
350 }
351 else if (this.sleepDuringExecute > 0)
352 {
353 + this.Log("OnExecuteProgress(sleep {0})", this.sleepDuringExecute);
354 Thread.Sleep(this.sleepDuringExecute);
355 }
356 }
@@ -313,6 +367,12 @@ namespace WixToolset.Test.BA
367 {
368 this.Engine.SendEmbeddedProgress(args.ProgressPercentage, args.OverallPercentage);
369 }
370 +
371 + if (this.cancelOnProgressAtProgress >= 0 && this.cancelOnProgressAtProgress <= args.OverallPercentage)
372 + {
373 + args.Cancel = true;
374 + this.Log("OnProgress(cancel)");
375 + }
376 }
377
378 protected override void OnResolveSource(ResolveSourceEventArgs args)
@@ -323,6 +383,13 @@ namespace WixToolset.Test.BA
383 }
384 }
385
386 + protected override void OnApplyBegin(ApplyBeginEventArgs args)
387 + {
388 + this.cancelOnProgressAtProgress = -1;
389 + this.cancelExecuteAtProgress = -1;
390 + this.cancelCacheAtProgress = -1;
391 + }
392 +
393 protected override void OnApplyComplete(ApplyCompleteEventArgs args)
394 {
395 // Output what the privileges are now.
src/WixToolsetTest.BurnE2E/FailureTests.cs
+18
@@ -44,5 +44,23 @@ namespace WixToolsetTest.BurnE2E
44 packageA.VerifyInstalled(false);
45 packageB.VerifyInstalled(false);
46 }
47 +
48 + [Fact]
49 + public void CanCancelMsiPackageInOnProgress()
50 + {
51 + var packageA = this.CreatePackageInstaller("PackageA");
52 + var packageB = this.CreatePackageInstaller("PackageB");
53 + var bundleA = this.CreateBundleInstaller("BundleA");
54 + var testBAController = this.CreateTestBAController();
55 +
56 + // Cancel package B during its OnProgress message.
57 + testBAController.SetPackageCancelOnProgressAtProgress("PackageB", 100);
58 +
59 + bundleA.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
60 + bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
61 +
62 + packageA.VerifyInstalled(false);
63 + packageB.VerifyInstalled(false);
64 + }
65 }
66 }
src/WixToolsetTest.BurnE2E/TestBAController.cs
+20
@@ -80,6 +80,26 @@ namespace WixToolsetTest.BurnE2E
80 this.SetPackageState(packageId, "CancelExecuteAtProgress", cancelPoint.HasValue ? cancelPoint.ToString() : null);
81 }
82
83 + /// <summary>
84 + /// Cancels the execute of a package at the next progess after the specified MSI action start.
85 + /// </summary>
86 + /// <param name="packageId">Package identity.</param>
87 + /// <param name="actionName">Sets or removes the cancel progress on a package being executed.</param>
88 + public void SetPackageCancelExecuteAtActionStart(string packageId, string actionName)
89 + {
90 + this.SetPackageState(packageId, "CancelExecuteAtActionStart", actionName);
91 + }
92 +
93 + /// <summary>
94 + /// Cancels the execute of a package at a particular OnProgress point.
95 + /// </summary>
96 + /// <param name="packageId">Package identity.</param>
97 + /// <param name="cancelPoint">Sets or removes the cancel OnProgress point on a package being executed.</param>
98 + public void SetPackageCancelOnProgressAtProgress(string packageId, int? cancelPoint)
99 + {
100 + this.SetPackageState(packageId, "CancelOnProgressAtProgress", cancelPoint.HasValue ? cancelPoint.ToString() : null);
101 + }
102 +
103 /// <summary>
104 /// Sets the requested state for a package that the TestBA will return to the engine during plan.
105 /// </summary>