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>