@joebigelow / wix / commits / 95e8b1be

Add more burn E2E tests.

Fix bug where first splash screen wasn't closed. Fix bug where billboard only started the first time. Fix bug where the restart status was lost when the exit code was an error. Fix bug where the hash byte array length was compared to the hash string length (string is twice as long). Fix bug where Burn didn't give update hash if the first byte was 0.

Sean Hall committed Sep 15, 2022 at 12:17 UTC 95e8b1be902cce3b5a394066a62e0c32d0688261
15 files changed +223 -12
src/burn/engine/apply.cpp
+21 -2
@@ -2547,6 +2547,11 @@ static HRESULT DoExecuteAction(
2547 } while (fRetry && *pRestart < BOOTSTRAPPER_APPLY_RESTART_INITIATED);
2548
2549 LExit:
2550 + if (*pRestart < restart)
2551 + {
2552 + *pRestart = restart;
2553 + }
2554 +
2555 return hr;
2556 }
2557
@@ -2561,6 +2566,7 @@ static HRESULT DoRollbackActions(
2566 DWORD iCheckpoint = 0;
2567 BOOL fRetryIgnored = FALSE;
2568 BOOL fSuspendIgnored = FALSE;
2569 + BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE;
2570
2571 pContext->fRollback = TRUE;
2572
@@ -2598,7 +2604,8 @@ static HRESULT DoRollbackActions(
2604 continue;
2605 }
2606
2601 - BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE;
2607 + restart = BOOTSTRAPPER_APPLY_RESTART_NONE;
2608 +
2609 switch (pRollbackAction->type)
2610 {
2611 case BURN_EXECUTE_ACTION_TYPE_CHECKPOINT:
@@ -2674,6 +2681,11 @@ static HRESULT DoRollbackActions(
2681 }
2682
2683 LExit:
2684 + if (*pRestart < restart)
2685 + {
2686 + *pRestart = restart;
2687 + }
2688 +
2689 return hr;
2690 }
2691
@@ -2791,6 +2803,7 @@ static HRESULT DoRestoreRelatedBundleActions(
2803 HRESULT hr = S_OK;
2804 BOOL fRetryIgnored = FALSE;
2805 BOOL fSuspendIgnored = FALSE;
2806 + BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE;
2807
2808 // execute restore related bundle actions
2809 for (DWORD i = 0; i < pEngineState->plan.cRestoreRelatedBundleActions; ++i)
@@ -2804,7 +2817,8 @@ static HRESULT DoRestoreRelatedBundleActions(
2817 pContext->wzExecutingPackageId = NULL;
2818 pContext->fAbandonedProcess = FALSE;
2819
2807 - BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE;
2820 + restart = BOOTSTRAPPER_APPLY_RESTART_NONE;
2821 +
2822 switch (pRestoreRelatedBundleAction->type)
2823 {
2824 case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE:
@@ -2824,6 +2838,11 @@ static HRESULT DoRestoreRelatedBundleActions(
2838 }
2839
2840 LExit:
2841 + if (*pRestart < restart)
2842 + {
2843 + *pRestart = restart;
2844 + }
2845 +
2846 return hr;
2847 }
2848
src/burn/engine/detect.cpp
+8 -3
@@ -399,18 +399,23 @@ static HRESULT DetectAtomFeedUpdate(
399 {
400 APPLICATION_UPDATE_ENTRY* pAppUpdateEntry = &pApupChain->rgEntries[i];
401 APPLICATION_UPDATE_ENCLOSURE* pEnclosure = pAppUpdateEntry->rgEnclosures;
402 + LPCWSTR wzHash = L"";
403 + BOOTSTRAPPER_UPDATE_HASH_TYPE hashType = BOOTSTRAPPER_UPDATE_HASH_TYPE_NONE;
404
403 - if (pEnclosure && pEnclosure->rgbDigest && *pEnclosure->rgbDigest)
405 + if (pEnclosure && pEnclosure->rgbDigest && APUP_HASH_ALGORITHM_SHA512 == pEnclosure->digestAlgorithm)
406 {
407 hr = StrAllocHexEncode(pEnclosure->rgbDigest, pEnclosure->cbDigest, &sczHash);
408 ExitOnFailure(hr, "Failed to encode hash as string.");
409 +
410 + wzHash = sczHash;
411 + hashType = BOOTSTRAPPER_UPDATE_HASH_TYPE_SHA512;
412 }
413
414 hr = UserExperienceOnDetectUpdate(pUX,
415 pEnclosure ? pEnclosure->wzUrl : NULL,
416 pEnclosure ? pEnclosure->dw64Size : 0,
412 - sczHash ? sczHash : L"",
413 - pEnclosure ? pEnclosure->digestAlgorithm == APUP_HASH_ALGORITHM_SHA512 ? BOOTSTRAPPER_UPDATE_HASH_TYPE_SHA512 : BOOTSTRAPPER_UPDATE_HASH_TYPE_NONE : BOOTSTRAPPER_UPDATE_HASH_TYPE_NONE,
417 + wzHash,
418 + hashType,
419 pAppUpdateEntry->pVersion,
420 pAppUpdateEntry->wzTitle,
421 pAppUpdateEntry->wzSummary,
src/burn/engine/engine.mc
+1 -1
@@ -1006,7 +1006,7 @@ MessageId=366
1006 Severity=Success
1007 SymbolicName=MSG_EXECUTE_PACKAGE_PROCESS_EXITED
1008 Language=English
1009 -The process for package: %1!ls! exited with code: %2!u!. The exit code has been translated to type: %3!hs! and restart: %4!hs!.
1009 +The process for package: %1!ls! exited with code: 0x%2!x!. The exit code has been translated to type: %3!hs! and restart: %4!hs!.
1010 .
1011
1012 MessageId=370
src/burn/engine/externalengine.cpp
+1 -1
@@ -296,7 +296,7 @@ HRESULT ExternalEngineSetUpdate(
296 {
297 ExitFunction1(hr = E_INVALIDARG);
298 }
299 - else if (BOOTSTRAPPER_UPDATE_HASH_TYPE_SHA512 == hashType && (!wzHash || !*wzHash || SHA512_HASH_LEN != lstrlenW(wzHash)))
299 + else if (BOOTSTRAPPER_UPDATE_HASH_TYPE_SHA512 == hashType && (!wzHash || !*wzHash || SHA512_HASH_LEN * 2 != lstrlenW(wzHash)))
300 {
301 ExitFunction1(hr = E_INVALIDARG);
302 }
src/burn/engine/splashscreen.cpp
+6
@@ -221,6 +221,11 @@ LExit:
221 ::DeleteObject(splashScreenInfo.hBitmap);
222 }
223
224 + if (splashScreenInfo.hwndPrevious)
225 + {
226 + ::PostMessageW(splashScreenInfo.hwndPrevious, WM_CLOSE, 0, 0);
227 + }
228 +
229 return hr;
230 }
231
@@ -261,6 +266,7 @@ static LRESULT CALLBACK WndProc(
266 return 1;
267
268 case WM_ENTERIDLE:
269 + case WM_MOVING:
270 lres = ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
271
272 // We had to create our own splash screen so that Windows would automatically transfer focus from the other process's splash screen.
src/libs/dutil/WixToolset.DUtil/thmutil.cpp
-2
@@ -4287,8 +4287,6 @@ static HRESULT StopBillboard(
4287
4288 if (THEME_CONTROL_TYPE_BILLBOARD == pControl->type)
4289 {
4290 - ThemeControlEnable(pControl, FALSE);
4291 -
4290 if (::KillTimer(pTheme->hwndParent, idEvent))
4291 {
4292 hr = S_OK;
src/test/burn/TestData/ExePackageTests/CustomExitCodeExePackage/CustomExitCodeExePackage.wixproj new
+17
@@ -0,0 +1,17 @@
1 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <OutputType>Bundle</OutputType>
5 + <UpgradeCode>{9BB4F6D3-4EE3-40BF-879F-90E78440EAE8}</UpgradeCode>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
12 + </ItemGroup>
13 + <ItemGroup>
14 + <PackageReference Include="WixToolset.Bal.wixext" />
15 + <PackageReference Include="WixToolset.NetFx.wixext" />
16 + </ItemGroup>
17 +</Project>
\ No newline at end of file
src/test/burn/TestData/ExePackageTests/CustomExitCodeExePackage/CustomExitCodeExePackage.wxs new
+34
@@ -0,0 +1,34 @@
1 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2 +
3 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 + <Fragment>
5 + <PackageGroup Id="BundlePackages">
6 + <ExePackage Id="TestExe" Cache="remove" PerMachine="yes"
7 + DetectCondition="" Permanent="yes" InstallArguments="/ec [EXEEXITCODE]">
8 + <PayloadGroupRef Id="TestExePayloads" />
9 +
10 + <ExitCode Value="0" Behavior="error" />
11 + <ExitCode Value="3" Behavior="scheduleReboot" />
12 + <ExitCode Value="4" Behavior="forceReboot" />
13 + <ExitCode Value="5" Behavior="errorScheduleReboot" />
14 + <ExitCode Value="-2147024891" Behavior="errorScheduleReboot" />
15 + <ExitCode Value="6" Behavior="errorForceReboot" />
16 + <ExitCode Value="-2147024890" Behavior="errorForceReboot" />
17 + <ExitCode Value="3010" Behavior="error" />
18 + <ExitCode Value="-2147021886" Behavior="error" />
19 + <ExitCode Value="3011" Behavior="error" />
20 + <ExitCode Value="-2147021885" Behavior="error" />
21 + <ExitCode Value="1641" Behavior="error" />
22 + <ExitCode Value="-2147023255" Behavior="error" />
23 + <ExitCode Value="3017" Behavior="error" />
24 + <ExitCode Value="-2147021879" Behavior="error" />
25 + <ExitCode Value="3018" Behavior="error" />
26 + <ExitCode Value="-2147021878" Behavior="error" />
27 + <ExitCode Value="-2147483647" Behavior="error" />
28 + <ExitCode Value="-2147483648" Behavior="error" />
29 + <ExitCode Behavior="success" />
30 + </ExePackage>
31 + </PackageGroup>
32 + <Variable Name="EXEEXITCODE" bal:Overridable="yes" Value="1" />
33 + </Fragment>
34 +</Wix>
src/test/burn/TestData/Manual/BafThmutilTesting/theme/BafThmUtilTestingTheme.xml
+1 -1
@@ -132,7 +132,7 @@ There are currently four states for a button: default, focus, hover, and selecte
132 </Page>
133 <Page Name="Billboard">
134 <Label X="6" Y="6" Width="-6" Height="43" FontId="Default">
135 - This page has a billboard. It loops between two panels every 1.5 seconds.
135 + This page has a billboard. It loops between two panels every 1.5 seconds. Press Back to go to another page, and then come back and make sure it still loops.
136 </Label>
137 <Billboard Name="FirstBillboard" X="11" Y="59" Width="-11" Height="-39" Interval="1500" Loop="yes">
138 <Panel>
src/test/burn/TestData/Manual/BafThmutilTesting/theme/BafThmUtilTestingThemeLoose.xml
+1 -1
@@ -132,7 +132,7 @@ There are currently four states for a button: default, focus, hover, and selecte
132 </Page>
133 <Page Name="Billboard">
134 <Label X="6" Y="6" Width="-6" Height="43" FontId="Default">
135 - This page has a billboard. It loops between two panels every 1.5 seconds.
135 + This page has a billboard. It loops between two panels every 1.5 seconds. Press Back to go to another page, and then come back and make sure it still loops.
136 </Label>
137 <Billboard Name="FirstBillboard" X="11" Y="59" Width="-11" Height="-39" Interval="1500" Loop="yes">
138 <Panel>
src/test/burn/TestData/Manual/BundleA/ManualTests.txt
+10
@@ -152,3 +152,13 @@ CanRestartFromUnelevatedPerUserBundleWithShutdownPrivilege
152 =======================================
153
154 (10. Uninstall the bundle)
155 +
156 +CanShowSplashScreenQuicklyAndCacheThousandsOfFilesInLinearTime
157 +
158 +1. Run BundleB.exe.
159 +2. The splash screen should come up immediately (less than 1 second).
160 +3. After the wixstdba UI comes up, make sure the splash screen was closed (it might be hiding underneath windows).
161 +4. Click Install (accept elevation).
162 +5. This bundle contains 10000 loose files which needs to be cached, which used to take over 30 minutes. The exact timing can be different on different machines, but it should be closer to 30 seconds.
163 +6. Click Close.
164 +(7. Uninstall the bundle)
src/test/burn/TestData/UpdateBundleTests/BundleBv1/FeedBv2.0_wronghash.xml new
+54
@@ -0,0 +1,54 @@
1 +<?xml version='1.0' ?>
2 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3 +
4 +
5 +<feed xmlns="http://www.w3.org/2005/Atom" xmlns:as="http://appsyndication.org/2006/appsyn">
6 + <title type="text">BundleB v2.0</title>
7 + <subtitle type="text">Bundle Subtitle.</subtitle>
8 + <as:application type="application/exe">1116353B-7C6E-4C29-BFA1-D4A972CD421D</as:application>
9 + <updated>2014-07-14T12:39:00.000Z</updated>
10 + <id>http://localhost:9999/e2e/BundleB/feed</id>
11 + <link rel="self" type="application/atom+xml" href="http://localhost:9999/e2e/BundleB/feed"/>
12 + <generator version="0.1">manual build</generator>
13 + <entry>
14 + <title>Bundle v2.0</title>
15 + <id>v2.0</id>
16 + <author>
17 + <name>Bundle_Author</name>
18 + <uri>http://mycompany.com/software</uri>
19 + <email>Bundle_Author@mycompany.com</email>
20 + </author>
21 + <link rel="alternate" href="http://www.mycompany.com/content/view/software"/>
22 + <link rel="enclosure" href="http://localhost:9999/e2e/BundleB/2.0/BundleB.exe" length="0" type="application/octet-stream">
23 + <as:name>this hash is supposed to be wrong but has a tiny chance of actually being right</as:name>
24 + <as:digest algorithm="sha512">00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</as:digest>
25 + </link>
26 + <content type="html">
27 + &lt;p&gt;Change list:&lt;/p&gt;&lt;ul&gt;
28 + &lt;li&gt;Updated release.&lt;/li&gt;
29 + &lt;/ul&gt;
30 + </content>
31 + <as:upgrade version="1.0" />
32 + <as:version>2.0.0.0</as:version>
33 + <updated>2014-11-10T12:39:00.000Z</updated>
34 + </entry>
35 + <entry>
36 + <title>Bundle v1.0</title>
37 + <id>v1.0</id>
38 + <author>
39 + <name>Bundle_Author</name>
40 + <uri>http://mycompany.com/software</uri>
41 + <email>Bundle_Author@mycompany.com</email>
42 + </author>
43 + <link rel="alternate" href="http://www.mycompany.com/content/view/software"/>
44 + <link rel="enclosure" href="http://localhost:9999/e2e/BundleB/1.0/BundleB.exe" length="0" type="application/octet-stream"/>
45 + <content type="html">
46 + &lt;p&gt;Change list:&lt;/p&gt;&lt;ul&gt;
47 + &lt;li&gt;Initial release.&lt;/li&gt;
48 + &lt;/ul&gt;
49 + </content>
50 + <as:upgrade version="1.0.0.0-preview" />
51 + <as:version>1.0.0.0</as:version>
52 + <updated>2014-11-09T12:39:00.000Z</updated>
53 + </entry>
54 +</feed>
src/test/burn/WixTestTools/MSIExec.cs
+7 -1
@@ -666,7 +666,13 @@ namespace WixTestTools
666 /// A restart is required to complete the install. This message is indicative of a success.
667 /// This does not include installs where the ForceReboot action is run.
668 /// </summary>
669 - ERROR_SUCCESS_REBOOT_REQUIRED = 3010
669 + ERROR_SUCCESS_REBOOT_REQUIRED = 3010,
670 +
671 + /// <summary>
672 + /// ERROR_SUCCESS_REBOOT_REQUIRED 3017
673 + /// The requested operation failed. A system reboot is required to roll back changes made.
674 + /// </summary>
675 + ERROR_FAIL_REBOOT_REQUIRED = 3017,
676 }
677
678 /// <summary>
src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs
+26
@@ -142,6 +142,32 @@ namespace WixToolsetTest.BurnE2E
142 Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}"));
143 }
144
145 + [RuntimeFact]
146 + public void CanUseLargeCustomExitCode()
147 + {
148 + var customExitCodeExePackageBundle = this.CreateBundleInstaller(@"CustomExitCodeExePackage");
149 +
150 + var installLogPath = customExitCodeExePackageBundle.Install(5, "EXEEXITCODE=-2147024891");
151 + customExitCodeExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
152 +
153 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, "TestExe.exe\" /ec -2147024891"));
154 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, "The process for package: TestExe exited with code: 0x80070005. The exit code has been translated to type: ErrorScheduleReboot and restart: Required."));
155 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, "Applied execute package: TestExe, result: 0x80070005, restart: Required"));
156 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, "Apply complete, result: 0x80070005, restart: Required, ba requested restart: No"));
157 + }
158 +
159 + [RuntimeFact]
160 + public void CanUseWildcardCustomExitCode()
161 + {
162 + var customExitCodeExePackageBundle = this.CreateBundleInstaller(@"CustomExitCodeExePackage");
163 +
164 + var installLogPath = customExitCodeExePackageBundle.Install((int)MSIExec.MSIExecReturnCode.SUCCESS, "EXEEXITCODE=1");
165 + customExitCodeExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
166 +
167 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, "TestExe.exe\" /ec 1"));
168 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, "The process for package: TestExe exited with code: 0x1. The exit code has been translated to type: Success and restart: None."));
169 + }
170 +
171 [RuntimeFact]
172 public void CanInstallAndUninstallPerUserArpEntryExePackage()
173 {
src/test/burn/WixToolsetTest.BurnE2E/UpdateBundleTests.cs
+36
@@ -242,5 +242,41 @@ namespace WixToolsetTest.BurnE2E
242 packageBv1.VerifyInstalled(false);
243 packageBv2.VerifyInstalled(false);
244 }
245 +
246 + // Installs bundle Bv1.0 then attempts an update to bundle Bv2.0 during modify (server exists, v2.0 feed with wrong hash).
247 + [RuntimeFact]
248 + public void CanBlockWrongUpdateBundleFromDownloadInsteadOfModify()
249 + {
250 + var packageBv1 = this.CreatePackageInstaller("PackageBv1");
251 + var packageBv2 = this.CreatePackageInstaller("PackageBv2");
252 + var bundleBv1 = this.CreateBundleInstaller("BundleBv1");
253 + var bundleBv2 = this.CreateBundleInstaller("BundleBv2");
254 + var webServer = this.CreateWebServer();
255 +
256 + webServer.AddFiles(new Dictionary<string, string>
257 + {
258 + { "/BundleB/feed", Path.Combine(this.TestContext.TestDataFolder, "FeedBv2.0_wronghash.xml") },
259 + { "/BundleB/2.0/BundleB.exe", bundleBv2.Bundle },
260 + });
261 + webServer.Start();
262 +
263 + packageBv1.VerifyInstalled(false);
264 + packageBv2.VerifyInstalled(false);
265 +
266 + bundleBv1.Install();
267 + bundleBv1.VerifyRegisteredAndInPackageCache();
268 +
269 + packageBv1.VerifyInstalled(true);
270 + packageBv2.VerifyInstalled(false);
271 +
272 + // Run the v1 bundle requesting an update bundle.
273 + bundleBv1.Modify(unchecked((int)0x80091007), arguments: "-checkupdate");
274 +
275 + bundleBv1.VerifyRegisteredAndInPackageCache();
276 + bundleBv2.VerifyUnregisteredAndRemovedFromPackageCache();
277 +
278 + packageBv1.VerifyInstalled(true);
279 + packageBv2.VerifyInstalled(false);
280 + }
281 }
282 }