@joebigelow / wix-1 / commits / af680335

Handle when related bundles have an uninstall key but aren't cached.

#4991

Sean Hall committed Mar 10, 2021 at 18:18 UTC af68033509730ffe01602f839861a47287bb709f
14 files changed +188 -34
src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
+2
@@ -491,6 +491,7 @@ struct BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_ARGS
491 LPCWSTR wzBundleTag;
492 BOOL fPerMachine;
493 LPCWSTR wzVersion;
494 + BOOL fMissingFromCache;
495 };
496
497 struct BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_RESULTS
@@ -547,6 +548,7 @@ struct BA_ONDETECTRELATEDBUNDLE_ARGS
548 BOOL fPerMachine;
549 LPCWSTR wzVersion;
550 BOOTSTRAPPER_RELATED_OPERATION operation;
551 + BOOL fMissingFromCache;
552 };
553
554 struct BA_ONDETECTRELATEDBUNDLE_RESULTS
src/engine/core.cpp
+26 -13
@@ -59,6 +59,10 @@ static void LogPackages(
59 __in const BURN_RELATED_BUNDLES* pRelatedBundles,
60 __in const BOOTSTRAPPER_ACTION action
61 );
62 +static void LogRelatedBundles(
63 + __in const BURN_RELATED_BUNDLES* pRelatedBundles,
64 + __in BOOL fReverse
65 + );
66
67
68 // function definitions
@@ -1793,15 +1797,9 @@ static void LogPackages(
1797 else
1798 {
1799 // Display related bundles first if uninstalling.
1796 - if (BOOTSTRAPPER_ACTION_UNINSTALL == action && 0 < pRelatedBundles->cRelatedBundles)
1800 + if (BOOTSTRAPPER_ACTION_UNINSTALL == action)
1801 {
1798 - for (int i = pRelatedBundles->cRelatedBundles - 1; 0 <= i; --i)
1799 - {
1800 - const BURN_RELATED_BUNDLE* pRelatedBundle = &pRelatedBundles->rgRelatedBundles[i];
1801 - const BURN_PACKAGE* pPackage = &pRelatedBundle->package;
1802 -
1803 - LogId(REPORT_STANDARD, MSG_PLANNED_RELATED_BUNDLE, pPackage->sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingDependencyActionToString(pPackage->dependencyExecute));
1804 - }
1802 + LogRelatedBundles(pRelatedBundles, TRUE);
1803 }
1804
1805 // Display all the packages in the log.
@@ -1852,13 +1850,28 @@ static void LogPackages(
1850 }
1851
1852 // Display related bundles last if caching, installing, modifying, or repairing.
1855 - if (BOOTSTRAPPER_ACTION_UNINSTALL < action && 0 < pRelatedBundles->cRelatedBundles)
1853 + if (BOOTSTRAPPER_ACTION_UNINSTALL < action)
1854 {
1857 - for (DWORD i = 0; i < pRelatedBundles->cRelatedBundles; ++i)
1858 - {
1859 - const BURN_RELATED_BUNDLE* pRelatedBundle = &pRelatedBundles->rgRelatedBundles[i];
1860 - const BURN_PACKAGE* pPackage = &pRelatedBundle->package;
1855 + LogRelatedBundles(pRelatedBundles, FALSE);
1856 + }
1857 + }
1858 +}
1859 +
1860 +static void LogRelatedBundles(
1861 + __in const BURN_RELATED_BUNDLES* pRelatedBundles,
1862 + __in BOOL fReverse
1863 + )
1864 +{
1865 + if (0 < pRelatedBundles->cRelatedBundles)
1866 + {
1867 + for (DWORD i = 0; i < pRelatedBundles->cRelatedBundles; ++i)
1868 + {
1869 + const DWORD iRelatedBundle = fReverse ? pRelatedBundles->cRelatedBundles - 1 - i : i;
1870 + const BURN_RELATED_BUNDLE* pRelatedBundle = pRelatedBundles->rgRelatedBundles + iRelatedBundle;
1871 + const BURN_PACKAGE* pPackage = &pRelatedBundle->package;
1872
1873 + if (pRelatedBundle->fPlannable)
1874 + {
1875 LogId(REPORT_STANDARD, MSG_PLANNED_RELATED_BUNDLE, pPackage->sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingDependencyActionToString(pPackage->dependencyExecute));
1876 }
1877 }
src/engine/dependency.cpp
+7 -1
@@ -260,7 +260,13 @@ extern "C" HRESULT DependencyDetect(
260
261 for (DWORD iRelatedBundle = 0; iRelatedBundle < pEngineState->registration.relatedBundles.cRelatedBundles; ++iRelatedBundle)
262 {
263 - pPackage = &pEngineState->registration.relatedBundles.rgRelatedBundles[iRelatedBundle].package;
263 + BURN_RELATED_BUNDLE* pRelatedBundle = pEngineState->registration.relatedBundles.rgRelatedBundles + iRelatedBundle;
264 + if (!pRelatedBundle->fPlannable)
265 + {
266 + continue;
267 + }
268 +
269 + pPackage = &pRelatedBundle->package;
270 hr = DetectPackageDependents(pPackage, sdIgnoredDependents, pRegistration);
271 ExitOnFailure(hr, "Failed to detect dependents for related bundle '%ls'", pPackage->sczId);
272 }
src/engine/detect.cpp
+10 -7
@@ -143,13 +143,16 @@ extern "C" HRESULT DetectForwardCompatibleBundles(
143
144 if (nCompareResult <= 0)
145 {
146 - pRelatedBundle->fForwardCompatible = TRUE;
147 - pRegistration->fForwardCompatibleBundleExists = TRUE;
146 + if (pRelatedBundle->fPlannable)
147 + {
148 + pRelatedBundle->fForwardCompatible = TRUE;
149 + pRegistration->fForwardCompatibleBundleExists = TRUE;
150 + }
151
149 - hr = UserExperienceOnDetectForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion);
152 + hr = UserExperienceOnDetectForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, BURN_CACHE_STATE_COMPLETE != pRelatedBundle->package.cache);
153 ExitOnRootFailure(hr, "BA aborted detect forward compatible bundle.");
154
152 - LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion);
155 + LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingCacheStateToString(pRelatedBundle->package.cache));
156 }
157 }
158 }
@@ -222,13 +225,13 @@ extern "C" HRESULT DetectReportRelatedBundles(
225 break;
226 }
227
225 - LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingRelatedOperationToString(operation));
228 + LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingRelatedOperationToString(operation), LoggingCacheStateToString(pRelatedBundle->package.cache));
229
227 - hr = UserExperienceOnDetectRelatedBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, operation);
230 + hr = UserExperienceOnDetectRelatedBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, operation, BURN_CACHE_STATE_COMPLETE != pRelatedBundle->package.cache);
231 ExitOnRootFailure(hr, "BA aborted detect related bundle.");
232
233 // For now, if any related bundles will be executed during uninstall by default then never automatically clean up the bundle.
231 - if (*pfEligibleForCleanup)
234 + if (*pfEligibleForCleanup && pRelatedBundle->fPlannable)
235 {
236 uninstallRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
237 hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->relationType, BOOTSTRAPPER_ACTION_UNINSTALL, pRegistration->pVersion, pRelatedBundle->pVersion, &uninstallRequestState);
src/engine/engine.mc
+9 -2
@@ -202,7 +202,7 @@ MessageId=102
202 Severity=Success
203 SymbolicName=MSG_DETECTED_RELATED_BUNDLE
204 Language=English
205 -Detected related bundle: %1!ls!, type: %2!hs!, scope: %3!hs!, version: %4!ls!, operation: %5!hs!
205 +Detected related bundle: %1!ls!, type: %2!hs!, scope: %3!hs!, version: %4!ls!, operation: %5!hs!, cached: %6!hs!
206 .
207
208 MessageId=103
@@ -237,7 +237,14 @@ MessageId=107
237 Severity=Success
238 SymbolicName=MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE
239 Language=English
240 -Detected forward compatible bundle: %1!ls!, type: %2!hs!, scope: %3!hs!, version: %4!ls!
240 +Detected forward compatible bundle: %1!ls!, type: %2!hs!, scope: %3!hs!, version: %4!ls!, cached: %5!hs!
241 +.
242 +
243 +MessageId=108
244 +Severity=Warning
245 +SymbolicName=MSG_DETECT_RELATED_BUNDLE_NOT_FULLY_CACHED
246 +Language=English
247 +Detected partially cached related bundle: %1!ls!, cache path: %2!ls!, reason: 0x%3!x!
248 .
249
250 MessageId=120
src/engine/externalengine.cpp
+1 -1
@@ -327,7 +327,7 @@ HRESULT ExternalEngineSetUpdate(
327 sczId = pEngineState->registration.sczId;
328 }
329
330 - hr = PseudoBundleInitialize(FILEMAKEVERSION(rmj, rmm, rup, rpr), &pEngineState->update.package, FALSE, sczId, BOOTSTRAPPER_RELATION_UPDATE, BOOTSTRAPPER_PACKAGE_STATE_ABSENT, pEngineState->registration.sczExecutableName, sczLocalSource ? sczLocalSource : wzLocalSource, wzDownloadSource, qwSize, TRUE, sczCommandline, NULL, NULL, NULL, rgbHash, cbHash);
330 + hr = PseudoBundleInitialize(FILEMAKEVERSION(rmj, rmm, rup, rpr), &pEngineState->update.package, FALSE, sczId, BOOTSTRAPPER_RELATION_UPDATE, BOOTSTRAPPER_PACKAGE_STATE_ABSENT, BURN_CACHE_STATE_NONE, pEngineState->registration.sczExecutableName, sczLocalSource ? sczLocalSource : wzLocalSource, wzDownloadSource, qwSize, TRUE, sczCommandline, NULL, NULL, NULL, rgbHash, cbHash);
331 ExitOnFailure(hr, "Failed to set update bundle.");
332
333 pEngineState->update.fUpdateAvailable = TRUE;
src/engine/plan.cpp
+11
@@ -1292,6 +1292,12 @@ extern "C" HRESULT PlanRelatedBundlesBegin(
1292 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
1293 {
1294 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i;
1295 +
1296 + if (!pRelatedBundle->fPlannable)
1297 + {
1298 + continue;
1299 + }
1300 +
1301 pRelatedBundle->package.defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE;
1302 pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE;
1303
@@ -1417,6 +1423,11 @@ extern "C" HRESULT PlanRelatedBundlesComplete(
1423 DWORD *pdwInsertIndex = NULL;
1424 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i;
1425
1426 + if (!pRelatedBundle->fPlannable)
1427 + {
1428 + continue;
1429 + }
1430 +
1431 // Do not execute if a major upgrade to the related bundle is an embedded bundle (Provider keys are the same)
1432 if (0 < pRelatedBundle->package.cDependencyProviders)
1433 {
src/engine/pseudobundle.cpp
+3 -2
@@ -10,6 +10,7 @@ extern "C" HRESULT PseudoBundleInitialize(
10 __in_z LPCWSTR wzId,
11 __in BOOTSTRAPPER_RELATION_TYPE relationType,
12 __in BOOTSTRAPPER_PACKAGE_STATE state,
13 + __in BURN_CACHE_STATE cacheState,
14 __in_z LPCWSTR wzFilePath,
15 __in_z LPCWSTR wzLocalSource,
16 __in_z_opt LPCWSTR wzDownloadSource,
@@ -66,14 +67,14 @@ extern "C" HRESULT PseudoBundleInitialize(
67 memcpy_s(pPackage->rgPayloads->pPayload->pbHash, pPackage->rgPayloads->pPayload->cbHash, pbHash, cbHash);
68 }
69
69 - pPackage->rgPayloads->fCached = (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state || BOOTSTRAPPER_PACKAGE_STATE_CACHED == state);
70 + pPackage->rgPayloads->fCached = BURN_CACHE_STATE_NONE < cacheState;
71
72 pPackage->Exe.fPseudoBundle = TRUE;
73
74 pPackage->type = BURN_PACKAGE_TYPE_EXE;
75 pPackage->fPerMachine = fPerMachine;
76 pPackage->currentState = state;
76 - pPackage->cache = (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state || BOOTSTRAPPER_PACKAGE_STATE_CACHED == state) ? BURN_CACHE_STATE_COMPLETE : BURN_CACHE_STATE_NONE;
77 + pPackage->cache = cacheState;
78 pPackage->qwInstallSize = qwSize;
79 pPackage->qwSize = qwSize;
80 pPackage->fVital = fVital;
src/engine/pseudobundle.h
+1
@@ -13,6 +13,7 @@ HRESULT PseudoBundleInitialize(
13 __in_z LPCWSTR wzId,
14 __in BOOTSTRAPPER_RELATION_TYPE relationType,
15 __in BOOTSTRAPPER_PACKAGE_STATE state,
16 + __in BURN_CACHE_STATE cacheState,
17 __in_z LPCWSTR wzFilePath,
18 __in_z LPCWSTR wzLocalSource,
19 __in_z_opt LPCWSTR wzDownloadSource,
src/engine/registration.h
+1
@@ -62,6 +62,7 @@ typedef struct _BURN_RELATED_BUNDLE
62
63 VERUTIL_VERSION* pVersion;
64 LPWSTR sczTag;
65 + BOOL fPlannable;
66
67 BURN_PACKAGE package;
68 } BURN_RELATED_BUNDLE;
src/engine/relatedbundle.cpp
+14 -2
@@ -398,6 +398,7 @@ static HRESULT LoadRelatedBundleFromKey(
398 DWORD64 qwEngineVersion = 0;
399 LPWSTR sczBundleVersion = NULL;
400 LPWSTR sczCachePath = NULL;
401 + BURN_CACHE_STATE cacheState = BURN_CACHE_STATE_NONE;
402 DWORD64 qwFileSize = 0;
403 BURN_DEPENDENCY_PROVIDER dependencyProvider = { };
404
@@ -423,7 +424,18 @@ static HRESULT LoadRelatedBundleFromKey(
424 ExitOnFailure(hr, "Failed to read cache path from registry for bundle: %ls", wzRelatedBundleId);
425
426 hr = FileSize(sczCachePath, reinterpret_cast<LONGLONG *>(&qwFileSize));
426 - ExitOnFailure(hr, "Failed to get size of pseudo bundle: %ls", sczCachePath);
427 + if (SUCCEEDED(hr))
428 + {
429 + cacheState = BURN_CACHE_STATE_COMPLETE;
430 + }
431 + else if (E_FILENOTFOUND != hr)
432 + {
433 + cacheState = BURN_CACHE_STATE_PARTIAL;
434 + LogId(REPORT_STANDARD, MSG_DETECT_RELATED_BUNDLE_NOT_FULLY_CACHED, wzRelatedBundleId, sczCachePath, hr);
435 + }
436 + hr = S_OK;
437 +
438 + pRelatedBundle->fPlannable = BURN_CACHE_STATE_COMPLETE == cacheState;
439
440 hr = RegReadString(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY, &dependencyProvider.sczKey);
441 if (E_FILENOTFOUND != hr)
@@ -452,7 +464,7 @@ static HRESULT LoadRelatedBundleFromKey(
464 pRelatedBundle->relationType = relationType;
465
466 hr = PseudoBundleInitialize(qwEngineVersion, &pRelatedBundle->package, fPerMachine, wzRelatedBundleId, pRelatedBundle->relationType,
455 - BOOTSTRAPPER_PACKAGE_STATE_PRESENT, sczCachePath, sczCachePath, NULL, qwFileSize, FALSE,
467 + BOOTSTRAPPER_PACKAGE_STATE_PRESENT, cacheState, sczCachePath, sczCachePath, NULL, qwFileSize, FALSE,
468 L"-quiet", L"-repair -quiet", L"-uninstall -quiet",
469 (dependencyProvider.sczKey && *dependencyProvider.sczKey) ? &dependencyProvider : NULL,
470 NULL, 0);
src/engine/userexperience.cpp
+6 -2
@@ -763,7 +763,8 @@ EXTERN_C BAAPI UserExperienceOnDetectForwardCompatibleBundle(
763 __in BOOTSTRAPPER_RELATION_TYPE relationType,
764 __in_z LPCWSTR wzBundleTag,
765 __in BOOL fPerMachine,
766 - __in VERUTIL_VERSION* pVersion
766 + __in VERUTIL_VERSION* pVersion,
767 + __in BOOL fMissingFromCache
768 )
769 {
770 HRESULT hr = S_OK;
@@ -776,6 +777,7 @@ EXTERN_C BAAPI UserExperienceOnDetectForwardCompatibleBundle(
777 args.wzBundleTag = wzBundleTag;
778 args.fPerMachine = fPerMachine;
779 args.wzVersion = pVersion->sczVersion;
780 + args.fMissingFromCache = fMissingFromCache;
781
782 results.cbSize = sizeof(results);
783
@@ -879,7 +881,8 @@ EXTERN_C BAAPI UserExperienceOnDetectRelatedBundle(
881 __in_z LPCWSTR wzBundleTag,
882 __in BOOL fPerMachine,
883 __in VERUTIL_VERSION* pVersion,
882 - __in BOOTSTRAPPER_RELATED_OPERATION operation
884 + __in BOOTSTRAPPER_RELATED_OPERATION operation,
885 + __in BOOL fMissingFromCache
886 )
887 {
888 HRESULT hr = S_OK;
@@ -893,6 +896,7 @@ EXTERN_C BAAPI UserExperienceOnDetectRelatedBundle(
896 args.fPerMachine = fPerMachine;
897 args.wzVersion = pVersion->sczVersion;
898 args.operation = operation;
899 + args.fMissingFromCache = fMissingFromCache;
900
901 results.cbSize = sizeof(results);
902
src/engine/userexperience.h
+4 -2
@@ -200,7 +200,8 @@ BAAPI UserExperienceOnDetectForwardCompatibleBundle(
200 __in BOOTSTRAPPER_RELATION_TYPE relationType,
201 __in_z LPCWSTR wzBundleTag,
202 __in BOOL fPerMachine,
203 - __in VERUTIL_VERSION* pVersion
203 + __in VERUTIL_VERSION* pVersion,
204 + __in BOOL fMissingFromCache
205 );
206 BAAPI UserExperienceOnDetectMsiFeature(
207 __in BURN_USER_EXPERIENCE* pUserExperience,
@@ -225,7 +226,8 @@ BAAPI UserExperienceOnDetectRelatedBundle(
226 __in_z LPCWSTR wzBundleTag,
227 __in BOOL fPerMachine,
228 __in VERUTIL_VERSION* pVersion,
228 - __in BOOTSTRAPPER_RELATED_OPERATION operation
229 + __in BOOTSTRAPPER_RELATED_OPERATION operation,
230 + __in BOOL fMissingFromCache
231 );
232 BAAPI UserExperienceOnDetectRelatedMsiPackage(
233 __in BURN_USER_EXPERIENCE* pUserExperience,
src/test/BurnUnitTest/PlanTest.cpp
+93 -2
@@ -292,6 +292,94 @@ namespace Bootstrapper
292 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PackageC", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
293 }
294
295 + [Fact]
296 + void RelatedBundleMissingFromCacheTest()
297 + {
298 + HRESULT hr = S_OK;
299 + BURN_ENGINE_STATE engineState = { };
300 + BURN_ENGINE_STATE* pEngineState = &engineState;
301 + BURN_PLAN* pPlan = &engineState.plan;
302 +
303 + InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
304 + DetectAttachedContainerAsAttached(pEngineState);
305 + DetectPackagesAsAbsent(pEngineState);
306 + BURN_RELATED_BUNDLE* pRelatedBundle = DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0");
307 + pRelatedBundle->fPlannable = FALSE;
308 +
309 + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL);
310 + NativeAssert::Succeeded(hr, "CorePlan failed");
311 +
312 + Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action);
313 + Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
314 + Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
315 +
316 + BOOL fRollback = FALSE;
317 + DWORD dwIndex = 0;
318 + DWORD dwPackageStart = 0;
319 + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
320 + dwPackageStart = ValidateCachePackageStart(pPlan, fRollback, dwIndex++, L"PackageA", 5, 2, 33743, FALSE);
321 + ValidateCacheExtractContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", FALSE, BURN_PLAN_INVALID_ACTION_INDEX, 2);
322 + ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageA", L"PackageA", TRUE, FALSE, dwPackageStart);
323 + ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageA", L"cab9Ins_fTP3wNwq5Gxo41ch5VUPaQ", TRUE, FALSE, dwPackageStart);
324 + ValidateCachePackageStop(pPlan, fRollback, dwIndex++, L"PackageA", FALSE);
325 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, FALSE);
326 + Assert::Equal(dwIndex, pPlan->cCacheActions);
327 +
328 + fRollback = TRUE;
329 + dwIndex = 0;
330 + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
331 + ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE);
332 + Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
333 +
334 + Assert::Equal(35694ull, pPlan->qwEstimatedSize);
335 + Assert::Equal(33743ull, pPlan->qwCacheSizeTotal);
336 +
337 + fRollback = FALSE;
338 + dwIndex = 0;
339 + DWORD dwExecuteCheckpointId = 2;
340 + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
341 + ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[6].syncpoint.hEvent);
342 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
343 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
344 + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER);
345 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
346 + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
347 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
348 + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_REGISTER);
349 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
350 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
351 + Assert::Equal(dwIndex, pPlan->cExecuteActions);
352 +
353 + fRollback = TRUE;
354 + dwIndex = 0;
355 + dwExecuteCheckpointId = 2;
356 + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
357 + ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
358 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
359 + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
360 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
361 + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
362 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
363 + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_UNREGISTER);
364 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
365 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
366 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
367 + Assert::Equal(dwIndex, pPlan->cRollbackActions);
368 +
369 + Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
370 + Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
371 +
372 + dwIndex = 0;
373 + Assert::Equal(dwIndex, pPlan->cCleanActions);
374 +
375 + UINT uIndex = 0;
376 + ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
377 + Assert::Equal(uIndex, pPlan->cPlannedProviders);
378 +
379 + Assert::Equal(1ul, pEngineState->packages.cPackages);
380 + ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
381 + }
382 +
383 [Fact]
384 void SingleMsiCacheTest()
385 {
@@ -1041,7 +1129,7 @@ namespace Bootstrapper
1129 }
1130 }
1131
1044 - void DetectUpgradeBundle(
1132 + BURN_RELATED_BUNDLE* DetectUpgradeBundle(
1133 __in BURN_ENGINE_STATE* pEngineState,
1134 __in LPCWSTR wzId,
1135 __in LPCWSTR wzVersion
@@ -1067,12 +1155,15 @@ namespace Bootstrapper
1155 hr = VerParseVersion(wzVersion, 0, FALSE, &pRelatedBundle->pVersion);
1156 NativeAssert::Succeeded(hr, "Failed to parse pseudo bundle version: %ls", wzVersion);
1157
1158 + pRelatedBundle->fPlannable = TRUE;
1159 pRelatedBundle->relationType = BOOTSTRAPPER_RELATION_UPGRADE;
1160
1072 - hr = PseudoBundleInitialize(0, &pRelatedBundle->package, TRUE, wzId, pRelatedBundle->relationType, BOOTSTRAPPER_PACKAGE_STATE_PRESENT, NULL, NULL, NULL, 0, FALSE, L"-quiet", L"-repair -quiet", L"-uninstall -quiet", &dependencyProvider, NULL, 0);
1161 + hr = PseudoBundleInitialize(0, &pRelatedBundle->package, TRUE, wzId, pRelatedBundle->relationType, BOOTSTRAPPER_PACKAGE_STATE_PRESENT, BURN_CACHE_STATE_COMPLETE, NULL, NULL, NULL, 0, FALSE, L"-quiet", L"-repair -quiet", L"-uninstall -quiet", &dependencyProvider, NULL, 0);
1162 NativeAssert::Succeeded(hr, "Failed to initialize related bundle to represent bundle: %ls", wzId);
1163
1164 ++pRelatedBundles->cRelatedBundles;
1165 +
1166 + return pRelatedBundle;
1167 }
1168
1169 void DetectAsRelatedUpgradeBundle(