From dea657295df261bb0e3e4d620eeae321531e3a11 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Tue, 14 Jun 2022 15:09:49 -0500 Subject: Add ability for non-vital cache package action. --- .../inc/BootstrapperApplication.h | 25 +++ .../WixToolset.Mba.Core/BootstrapperApplication.cs | 29 +++- src/api/burn/WixToolset.Mba.Core/EventArgs.cs | 27 +++- .../IBootstrapperApplication.cs | 40 +++-- .../IDefaultBootstrapperApplication.cs | 5 + src/api/burn/balutil/inc/BAFunctions.h | 1 + src/api/burn/balutil/inc/BalBaseBAFunctions.h | 11 ++ src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h | 1 + .../balutil/inc/BalBaseBootstrapperApplication.h | 11 ++ .../inc/BalBaseBootstrapperApplicationProc.h | 14 +- .../burn/balutil/inc/IBootstrapperApplication.h | 9 ++ src/burn/engine/apply.cpp | 51 ++++-- src/burn/engine/core.cpp | 2 +- src/burn/engine/engine.mc | 4 +- src/burn/engine/logging.cpp | 29 ++++ src/burn/engine/logging.h | 8 + src/burn/engine/package.h | 12 +- src/burn/engine/plan.cpp | 111 +++++++------ src/burn/engine/plan.h | 5 +- src/burn/engine/userexperience.cpp | 40 ++++- src/burn/engine/userexperience.h | 9 +- src/burn/test/BurnUnitTest/PlanTest.cpp | 179 +++++++++++++-------- .../WixStandardBootstrapperApplication.cpp | 14 +- src/test/burn/TestBA/TestBA.cs | 32 +++- .../PackageTestExe/PackageTestExe.wixproj | 16 ++ .../PackageTestExe/ProductComponents.wxs | 12 ++ ...chineArpEntryExePackageUninstallFailure.wixproj | 18 +++ ...erMachineArpEntryExePackageUninstallFailure.wxs | 24 +++ .../burn/TestData/TestBA/TestBAWixlib/TestExe.wxs | 7 + .../burn/WixToolsetTest.BurnE2E/ExePackageTests.cs | 117 ++++++++++++-- .../Utilities/TestBAController.cs | 15 ++ 31 files changed, 723 insertions(+), 155 deletions(-) create mode 100644 src/test/burn/TestData/ExePackageTests/PackageTestExe/PackageTestExe.wixproj create mode 100644 src/test/burn/TestData/ExePackageTests/PackageTestExe/ProductComponents.wxs create mode 100644 src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageUninstallFailure/PerMachineArpEntryExePackageUninstallFailure.wixproj create mode 100644 src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageUninstallFailure/PerMachineArpEntryExePackageUninstallFailure.wxs (limited to 'src') diff --git a/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h b/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h index ea3be214..ad3ef8a3 100644 --- a/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h +++ b/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h @@ -226,6 +226,7 @@ enum BOOTSTRAPPER_APPLICATION_MESSAGE BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE, BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL, BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE, + BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE, }; enum BOOTSTRAPPER_APPLYCOMPLETE_ACTION @@ -257,6 +258,14 @@ enum BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_RETRY, }; +enum BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION +{ + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_NONE, + // Instructs the engine to try to acquire the package so execution can use it. + // Most of the time this is used for installing the package during rollback. + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_ACQUIRE, +}; + enum BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION { BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION_NONE, @@ -546,6 +555,8 @@ struct BA_ONCACHEPACKAGEBEGIN_ARGS LPCWSTR wzPackageId; DWORD cCachePayloads; DWORD64 dw64PackageCacheSize; + // If caching a package is not vital, then acquisition will be skipped unless the BA opts in through OnCachePackageNonVitalValidationFailure. + BOOL fVital; }; struct BA_ONCACHEPACKAGEBEGIN_RESULTS @@ -568,6 +579,20 @@ struct BA_ONCACHEPACKAGECOMPLETE_RESULTS BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION action; }; +struct BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_ARGS +{ + DWORD cbSize; + LPCWSTR wzPackageId; + HRESULT hrStatus; + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION recommendation; +}; + +struct BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_RESULTS +{ + DWORD cbSize; + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION action; +}; + struct BA_ONCACHEPAYLOADEXTRACTBEGIN_ARGS { DWORD cbSize; diff --git a/src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs b/src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs index bb34a33e..fe9322ce 100644 --- a/src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs +++ b/src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs @@ -280,6 +280,9 @@ namespace WixToolset.Mba.Core /// public event EventHandler DetectRelatedBundlePackage; + /// + public event EventHandler CachePackageNonVitalValidationFailure; + /// /// Entry point that is called when the bootstrapper application is ready to run. /// @@ -1376,6 +1379,18 @@ namespace WixToolset.Mba.Core } } + /// + /// Called by the engine, raises the event. + /// + protected virtual void OnCachePackageNonVitalValidationFailure(CachePackageNonVitalValidationFailureEventArgs args) + { + EventHandler handler = this.CachePackageNonVitalValidationFailure; + if (null != handler) + { + handler(this, args); + } + } + #region IBootstrapperApplication Members int IBootstrapperApplication.BAProc(int message, IntPtr pvArgs, IntPtr pvResults, IntPtr pvContext) @@ -1570,6 +1585,7 @@ namespace WixToolset.Mba.Core this.OnPlanPackageBegin(args); pRequestedState = args.State; + pRequestedCacheType = args.CacheType; fCancel = args.Cancel; return args.HResult; } @@ -1728,9 +1744,9 @@ namespace WixToolset.Mba.Core return args.HResult; } - int IBootstrapperApplication.OnCachePackageBegin(string wzPackageId, int cCachePayloads, long dw64PackageCacheSize, ref bool fCancel) + int IBootstrapperApplication.OnCachePackageBegin(string wzPackageId, int cCachePayloads, long dw64PackageCacheSize, bool fVital, ref bool fCancel) { - CachePackageBeginEventArgs args = new CachePackageBeginEventArgs(wzPackageId, cCachePayloads, dw64PackageCacheSize, fCancel); + CachePackageBeginEventArgs args = new CachePackageBeginEventArgs(wzPackageId, cCachePayloads, dw64PackageCacheSize, fVital, fCancel); this.OnCachePackageBegin(args); fCancel = args.Cancel; @@ -2131,6 +2147,15 @@ namespace WixToolset.Mba.Core return args.HResult; } + int IBootstrapperApplication.OnCachePackageNonVitalValidationFailure(string wzPackageId, int hrStatus, BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION recommendation, ref BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION action) + { + CachePackageNonVitalValidationFailureEventArgs args = new CachePackageNonVitalValidationFailureEventArgs(wzPackageId, hrStatus, recommendation, action); + this.OnCachePackageNonVitalValidationFailure(args); + + action = args.Action; + return args.HResult; + } + #endregion } } diff --git a/src/api/burn/WixToolset.Mba.Core/EventArgs.cs b/src/api/burn/WixToolset.Mba.Core/EventArgs.cs index be113700..2b414d91 100644 --- a/src/api/burn/WixToolset.Mba.Core/EventArgs.cs +++ b/src/api/burn/WixToolset.Mba.Core/EventArgs.cs @@ -1930,12 +1930,13 @@ namespace WixToolset.Mba.Core public class CachePackageBeginEventArgs : CancellableHResultEventArgs { /// - public CachePackageBeginEventArgs(string packageId, int cachePayloads, long packageCacheSize, bool cancelRecommendation) + public CachePackageBeginEventArgs(string packageId, int cachePayloads, long packageCacheSize, bool vital, bool cancelRecommendation) : base(cancelRecommendation) { this.PackageId = packageId; this.CachePayloads = cachePayloads; this.PackageCacheSize = packageCacheSize; + this.Vital = vital; } /// @@ -1952,6 +1953,11 @@ namespace WixToolset.Mba.Core /// Gets the size on disk required by the specific package. /// public long PackageCacheSize { get; private set; } + + /// + /// If caching a package is not vital, then acquisition will be skipped unless the BA opts in through . + /// + public bool Vital { get; private set; } } /// @@ -2482,4 +2488,23 @@ namespace WixToolset.Mba.Core /// public string Version { get; private set; } } + + /// + /// Event arguments for + /// + [Serializable] + public class CachePackageNonVitalValidationFailureEventArgs : ActionEventArgs + { + /// + public CachePackageNonVitalValidationFailureEventArgs(string packageId, int hrStatus, BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION recommendation, BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION action) + : base(hrStatus, recommendation, action) + { + this.PackageId = packageId; + } + + /// + /// Gets the identity of the package that was being validated. + /// + public string PackageId { get; private set; } + } } diff --git a/src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs b/src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs index 8ce99808..87da2191 100644 --- a/src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs +++ b/src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs @@ -553,17 +553,13 @@ namespace WixToolset.Mba.Core /// /// See . /// - /// - /// - /// - /// - /// [PreserveSig] [return: MarshalAs(UnmanagedType.I4)] int OnCachePackageBegin( [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId, [MarshalAs(UnmanagedType.U4)] int cCachePayloads, [MarshalAs(UnmanagedType.U8)] long dw64PackageCacheSize, + [MarshalAs(UnmanagedType.Bool)] bool fVital, [MarshalAs(UnmanagedType.Bool)] ref bool fCancel ); @@ -672,11 +668,6 @@ namespace WixToolset.Mba.Core /// /// See . /// - /// - /// - /// - /// - /// [PreserveSig] [return: MarshalAs(UnmanagedType.I4)] int OnCachePackageComplete( @@ -1184,6 +1175,18 @@ namespace WixToolset.Mba.Core [MarshalAs(UnmanagedType.LPWStr)] string wzVersion, [MarshalAs(UnmanagedType.Bool)] ref bool fCancel ); + + /// + /// See . + /// + [PreserveSig] + [return: MarshalAs(UnmanagedType.I4)] + int OnCachePackageNonVitalValidationFailure( + [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId, + int hrStatus, + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION recommendation, + ref BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION action + ); } /// @@ -1870,6 +1873,23 @@ namespace WixToolset.Mba.Core Retry, } + /// + /// The available actions for + /// + public enum BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION + { + /// + /// + /// + None, + + /// + /// Instructs the engine to try to acquire the package so execution can use it. + /// Most of the time this is used for installing the package during rollback. + /// + Acquire, + } + /// /// The available actions for . /// diff --git a/src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs b/src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs index 2535f756..2fa88bdb 100644 --- a/src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs +++ b/src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs @@ -93,6 +93,11 @@ namespace WixToolset.Mba.Core /// event EventHandler CachePackageComplete; + /// + /// Fired when the engine failed validating a package in the package cache that is non-vital to execution. + /// + event EventHandler CachePackageNonVitalValidationFailure; + /// /// Fired when the engine begins the extraction of the payload from the container. /// diff --git a/src/api/burn/balutil/inc/BAFunctions.h b/src/api/burn/balutil/inc/BAFunctions.h index b23dd02e..8ecc04ff 100644 --- a/src/api/burn/balutil/inc/BAFunctions.h +++ b/src/api/burn/balutil/inc/BAFunctions.h @@ -92,6 +92,7 @@ enum BA_FUNCTIONS_MESSAGE BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE, BA_FUNCTIONS_MESSAGE_ONEXECUTEPROCESSCANCEL = BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL, BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE, + BA_FUNCTIONS_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE, BA_FUNCTIONS_MESSAGE_ONTHEMELOADED = 1024, BA_FUNCTIONS_MESSAGE_WNDPROC, diff --git a/src/api/burn/balutil/inc/BalBaseBAFunctions.h b/src/api/burn/balutil/inc/BalBaseBAFunctions.h index ca070553..49e97815 100644 --- a/src/api/burn/balutil/inc/BalBaseBAFunctions.h +++ b/src/api/burn/balutil/inc/BalBaseBAFunctions.h @@ -447,6 +447,7 @@ public: // IBootstrapperApplication __in_z LPCWSTR /*wzPackageId*/, __in DWORD /*cCachePayloads*/, __in DWORD64 /*dw64PackageCacheSize*/, + __in BOOL /*fVital*/, __inout BOOL* /*pfCancel*/ ) { @@ -892,6 +893,16 @@ public: // IBootstrapperApplication return S_OK; } + virtual STDMETHODIMP OnCachePackageNonVitalValidationFailure( + __in_z LPCWSTR /*wzPackageId*/, + __in HRESULT /*hrStatus*/, + __in BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION /*recommendation*/, + __inout BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION* /*pAction*/ + ) + { + return S_OK; + } + public: // IBAFunctions virtual STDMETHODIMP OnPlan( ) diff --git a/src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h b/src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h index ff92717d..e10decfc 100644 --- a/src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h +++ b/src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h @@ -163,6 +163,7 @@ static HRESULT WINAPI BalBaseBAFunctionsProc( case BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE: case BA_FUNCTIONS_MESSAGE_ONEXECUTEPROCESSCANCEL: case BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE: + case BA_FUNCTIONS_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE: hr = BalBaseBootstrapperApplicationProc((BOOTSTRAPPER_APPLICATION_MESSAGE)message, pvArgs, pvResults, pvContext); break; case BA_FUNCTIONS_MESSAGE_ONTHEMELOADED: diff --git a/src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h b/src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h index fc9c4dd7..aa1ca56f 100644 --- a/src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h +++ b/src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h @@ -505,6 +505,7 @@ public: // IBootstrapperApplication __in_z LPCWSTR /*wzPackageId*/, __in DWORD /*cCachePayloads*/, __in DWORD64 /*dw64PackageCacheSize*/, + __in BOOL /*fVital*/, __inout BOOL* pfCancel ) { @@ -1084,6 +1085,16 @@ public: // IBootstrapperApplication return S_OK; } + virtual STDMETHODIMP OnCachePackageNonVitalValidationFailure( + __in_z LPCWSTR /*wzPackageId*/, + __in HRESULT /*hrStatus*/, + __in BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION /*recommendation*/, + __inout BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION* /*pAction*/ + ) + { + return S_OK; + } + public: //CBalBaseBootstrapperApplication virtual STDMETHODIMP Initialize( __in const BOOTSTRAPPER_CREATE_ARGS* pCreateArgs diff --git a/src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h b/src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h index 92243540..3054731f 100644 --- a/src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h +++ b/src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h @@ -330,7 +330,7 @@ static HRESULT BalBaseBAProcOnCachePackageBegin( __inout BA_ONCACHEPACKAGEBEGIN_RESULTS* pResults ) { - return pBA->OnCachePackageBegin(pArgs->wzPackageId, pArgs->cCachePayloads, pArgs->dw64PackageCacheSize, &pResults->fCancel); + return pBA->OnCachePackageBegin(pArgs->wzPackageId, pArgs->cCachePayloads, pArgs->dw64PackageCacheSize, pArgs->fVital, &pResults->fCancel); } static HRESULT BalBaseBAProcOnCacheAcquireBegin( @@ -756,6 +756,15 @@ static HRESULT BalBaseBAProcOnDetectRelatedBundlePackage( return pBA->OnDetectRelatedBundlePackage(pArgs->wzPackageId, pArgs->wzBundleId, pArgs->relationType, pArgs->fPerMachine, pArgs->wzVersion, &pResults->fCancel); } +static HRESULT BalBaseBAProcOnCachePackageNonVitalValidationFailure( + __in IBootstrapperApplication* pBA, + __in BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_ARGS* pArgs, + __inout BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_RESULTS* pResults + ) +{ + return pBA->OnCachePackageNonVitalValidationFailure(pArgs->wzPackageId, pArgs->hrStatus, pArgs->recommendation, &pResults->action); +} + /******************************************************************* BalBaseBootstrapperApplicationProc - requires pvContext to be of type IBootstrapperApplication. Provides a default mapping between the new message based BA interface and @@ -1024,6 +1033,9 @@ static HRESULT WINAPI BalBaseBootstrapperApplicationProc( case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE: hr = BalBaseBAProcOnDetectRelatedBundlePackage(pBA, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); break; + case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE: + hr = BalBaseBAProcOnCachePackageNonVitalValidationFailure(pBA, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; } } diff --git a/src/api/burn/balutil/inc/IBootstrapperApplication.h b/src/api/burn/balutil/inc/IBootstrapperApplication.h index 382d5aad..0362e171 100644 --- a/src/api/burn/balutil/inc/IBootstrapperApplication.h +++ b/src/api/burn/balutil/inc/IBootstrapperApplication.h @@ -343,6 +343,7 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A __in_z LPCWSTR wzPackageId, __in DWORD cCachePayloads, __in DWORD64 dw64PackageCacheSize, + __in BOOL fVital, __inout BOOL* pfCancel ) = 0; @@ -728,4 +729,12 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A __in_z LPCWSTR wzVersion, __inout BOOL* pfCancel ) = 0; + + // OnCachePackageNonVitalValidationFailure - called when the engine failed validating a package in the package cache that is non-vital to execution. + STDMETHOD(OnCachePackageNonVitalValidationFailure)( + __in_z LPCWSTR wzPackageId, + __in HRESULT hrStatus, + __in BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION recommendation, + __inout BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION* pAction + ) = 0; }; diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index 048cd98b..d215cfe5 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp @@ -110,7 +110,8 @@ static HRESULT ApplyLayoutContainer( static HRESULT ApplyProcessPayload( __in BURN_CACHE_CONTEXT* pContext, __in_opt BURN_PACKAGE* pPackage, - __in BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem + __in BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem, + __in BOOL fVital ); static HRESULT ApplyCacheVerifyContainerOrPayload( __in BURN_CACHE_CONTEXT* pContext, @@ -203,6 +204,10 @@ static HRESULT DoRollbackActions( __in DWORD dwCheckpoint, __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); +static BOOL ShouldSkipPackage( + __in BURN_PACKAGE* pPackage, + __in BOOL fRollback + ); static HRESULT ExecuteRelatedBundle( __in BURN_ENGINE_STATE* pEngineState, __in BURN_EXECUTE_ACTION* pExecuteAction, @@ -379,6 +384,7 @@ extern "C" void ApplyReset( { BURN_PACKAGE* pPackage = pPackages->rgPackages + i; pPackage->hrCacheResult = S_OK; + pPackage->fAcquireOptionalSource = FALSE; pPackage->fReachedExecution = FALSE; pPackage->fAbandonedProcess = FALSE; pPackage->transactionRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN; @@ -633,7 +639,7 @@ extern "C" HRESULT ApplyCache( break; case BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT: - if (!::SetEvent(pCacheAction->syncpoint.hEvent)) + if (!::SetEvent(pCacheAction->syncpoint.pPackage->hCacheEvent)) { ExitWithLastError(hr, "Failed to set syncpoint event."); } @@ -959,12 +965,13 @@ static HRESULT ApplyCachePackage( HRESULT hr = S_OK; BOOL fCanceledBegin = FALSE; BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION cachePackageCompleteAction = BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_NONE; + BOOL fVital = pPackage->fCacheVital; for (;;) { fCanceledBegin = FALSE; - hr = UserExperienceOnCachePackageBegin(pContext->pUX, pPackage->sczId, pPackage->payloads.cItems, pPackage->payloads.qwTotalSize); + hr = UserExperienceOnCachePackageBegin(pContext->pUX, pPackage->sczId, pPackage->payloads.cItems, pPackage->payloads.qwTotalSize, fVital); if (FAILED(hr)) { fCanceledBegin = TRUE; @@ -975,7 +982,7 @@ static HRESULT ApplyCachePackage( { BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem = pPackage->payloads.rgItems + i; - hr = ApplyProcessPayload(pContext, pPackage, pPayloadGroupItem); + hr = ApplyProcessPayload(pContext, pPackage, pPayloadGroupItem, fVital); if (FAILED(hr)) { break; @@ -984,7 +991,7 @@ static HRESULT ApplyCachePackage( } pPackage->hrCacheResult = hr; - cachePackageCompleteAction = SUCCEEDED(hr) || pPackage->fVital || fCanceledBegin ? BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_NONE : BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_IGNORE; + cachePackageCompleteAction = SUCCEEDED(hr) || (pPackage->fVital && fVital) || fCanceledBegin ? BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_NONE : BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_IGNORE; UserExperienceOnCachePackageComplete(pContext->pUX, pPackage->sczId, hr, &cachePackageCompleteAction); if (SUCCEEDED(hr)) @@ -1014,7 +1021,7 @@ static HRESULT ApplyCachePackage( continue; } - else if (BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_IGNORE == cachePackageCompleteAction && !pPackage->fVital) // ignore non-vital download failures. + else if (BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_IGNORE == cachePackageCompleteAction && (!pPackage->fVital || !fVital)) // ignore non-vital download failures. { LogId(REPORT_STANDARD, MSG_CACHE_CONTINUING_NONVITAL_PACKAGE, pPackage->sczId, hr); hr = S_OK; @@ -1101,7 +1108,7 @@ static HRESULT ApplyLayoutBundle( { BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem = pPayloads->rgItems + i; - hr = ApplyProcessPayload(pContext, NULL, pPayloadGroupItem); + hr = ApplyProcessPayload(pContext, NULL, pPayloadGroupItem, TRUE); ExitOnFailure(hr, "Failed to layout bundle payload: %ls", pPayloadGroupItem->pPayload->sczKey); } @@ -1164,12 +1171,14 @@ LExit: static HRESULT ApplyProcessPayload( __in BURN_CACHE_CONTEXT* pContext, __in_opt BURN_PACKAGE* pPackage, - __in BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem + __in BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem, + __in BOOL fVital ) { HRESULT hr = S_OK; DWORD cTryAgainAttempts = 0; BOOL fRetry = FALSE; + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION action = BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_NONE; BURN_PAYLOAD* pPayload = pPayloadGroupItem->pPayload; Assert(pContext->pPayloads && pPackage || pContext->wzLayoutDirectory); @@ -1184,6 +1193,18 @@ static HRESULT ApplyProcessPayload( { ExitFunction(); } + else if (pPackage && !pPackage->fAcquireOptionalSource && !fVital) + { + HRESULT hrResponse = UserExperienceOnCachePackageNonVitalValidationFailure(pContext->pUX, pPackage->sczId, hr, &action); + ExitOnRootFailure(hrResponse, "BA aborted cache package non-vital failure."); + + if (BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_ACQUIRE != action) + { + ExitFunction(); + } + + pPackage->fAcquireOptionalSource = TRUE; + } for (;;) { @@ -2567,10 +2588,20 @@ static BOOL ShouldSkipPackage( ) { BOOL fSkip = FALSE; + BURN_CACHE_PACKAGE_TYPE cachePackageType = fRollback ? pPackage->rollbackCacheType : pPackage->executeCacheType; + BOOL fCacheVital = BURN_CACHE_PACKAGE_TYPE_REQUIRED == cachePackageType; - if (FAILED(pPackage->hrCacheResult)) + if (fCacheVital && FAILED(pPackage->hrCacheResult)) { - LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_FAILED_CACHED_PACKAGE, pPackage->sczId, pPackage->hrCacheResult); + if (fRollback) + { + LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_ROLLBACK_NO_CACHE, pPackage->sczId, pPackage->hrCacheResult, LoggingActionStateToString(pPackage->rollback)); + } + else + { + LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_FAILED_CACHED_PACKAGE, pPackage->sczId, pPackage->hrCacheResult); + } + ExitFunction1(fSkip = TRUE); } else if (fRollback && pPackage->fAbandonedProcess) diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index 8dfa0010..c1e3a12c 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -2329,7 +2329,7 @@ static void LogPackages( LogRollbackBoundary(pPackage->pRollbackBoundaryBackward); } - LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingCacheTypeToString(pPackage->authoredCacheType), LoggingCacheTypeToString(pPackage->cacheType), LoggingBoolToString(pPackage->fPlannedCache), LoggingBoolToString(pPackage->fPlannedUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState)); + LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingCacheTypeToString(pPackage->authoredCacheType), LoggingCacheTypeToString(pPackage->cacheType), LoggingPlannedCacheToString(pPackage), LoggingBoolToString(pPackage->fPlannedUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState)); if (BURN_PACKAGE_TYPE_MSI == pPackage->type) { diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc index 52524edb..f5e3ca27 100644 --- a/src/burn/engine/engine.mc +++ b/src/burn/engine/engine.mc @@ -417,9 +417,9 @@ Planned related bundle: %1!ls!, detect type: %2!hs!, default plan type: %3!hs!, MessageId=208 Severity=Warning -SymbolicName=MSG_PLAN_DISABLING_ROLLBACK_NO_CACHE +SymbolicName=MSG_APPLY_SKIPPED_ROLLBACK_NO_CACHE Language=English -Plan disabled rollback due to incomplete cache for package: %1!ls!, original rollback action: %2!hs! +Skipping apply rollback of package: %1!ls! due to cache error: 0x%2!x!, original rollback action: %3!hs!. Continuing... . MessageId=209 diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 77f5079c..1020d01f 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp @@ -445,6 +445,23 @@ extern "C" LPCSTR LoggingCacheTypeToString( } } +extern "C" LPCSTR LoggingCachePackageTypeToString( + BURN_CACHE_PACKAGE_TYPE cachePackageType + ) +{ + switch (cachePackageType) + { + case BURN_CACHE_PACKAGE_TYPE_NONE: + return "None"; + case BURN_CACHE_PACKAGE_TYPE_OPTIONAL: + return "Optional"; + case BURN_CACHE_PACKAGE_TYPE_REQUIRED: + return "Required"; + default: + return "Invalid"; + } +} + extern "C" LPCSTR LoggingDependencyActionToString( BURN_DEPENDENCY_ACTION action ) @@ -669,6 +686,18 @@ extern "C" LPCSTR LoggingPerMachineToString( return "PerUser"; } +extern "C" LPCSTR LoggingPlannedCacheToString( + __in const BURN_PACKAGE* pPackage + ) +{ + if (!pPackage->hCacheEvent) + { + return "No"; + } + + return pPackage->fCacheVital ? "Vital" : "NonVital"; +} + extern "C" LPCSTR LoggingRegistrationTypeToString( __in BOOTSTRAPPER_REGISTRATION_TYPE registrationType ) diff --git a/src/burn/engine/logging.h b/src/burn/engine/logging.h index 857394b9..000b04f8 100644 --- a/src/burn/engine/logging.h +++ b/src/burn/engine/logging.h @@ -92,6 +92,10 @@ LPCSTR LoggingCacheTypeToString( BOOTSTRAPPER_CACHE_TYPE cacheType ); +LPCSTR LoggingCachePackageTypeToString( + BURN_CACHE_PACKAGE_TYPE cachePackageType + ); + LPCSTR LoggingDependencyActionToString( BURN_DEPENDENCY_ACTION action ); @@ -142,6 +146,10 @@ LPCSTR LoggingPerMachineToString( __in BOOL fPerMachine ); +LPCSTR LoggingPlannedCacheToString( + __in const BURN_PACKAGE* pPackage + ); + LPCSTR LoggingRegistrationTypeToString( __in BOOTSTRAPPER_REGISTRATION_TYPE registrationType ); diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h index 85f34de5..5fccf50a 100644 --- a/src/burn/engine/package.h +++ b/src/burn/engine/package.h @@ -16,6 +16,13 @@ typedef _BURN_PACKAGE BURN_PACKAGE; const DWORD BURN_PACKAGE_INVALID_PATCH_INDEX = 0x80000000; +enum BURN_CACHE_PACKAGE_TYPE +{ + BURN_CACHE_PACKAGE_TYPE_NONE, + BURN_CACHE_PACKAGE_TYPE_OPTIONAL, + BURN_CACHE_PACKAGE_TYPE_REQUIRED, +}; + enum BURN_EXE_DETECTION_TYPE { BURN_EXE_DETECTION_TYPE_NONE, @@ -277,7 +284,7 @@ typedef struct _BURN_PACKAGE BOOTSTRAPPER_CACHE_TYPE cacheType; // only valid during Plan. BOOTSTRAPPER_REQUEST_STATE defaultRequested;// only valid during Plan. BOOTSTRAPPER_REQUEST_STATE requested; // only valid during Plan. - BOOL fPlannedCache; // only valid during Plan. + BOOL fCacheVital; // only valid during Plan. BOOL fPlannedUncache; // only valid during Plan. BOOTSTRAPPER_ACTION_STATE execute; // only valid during Plan. BOOTSTRAPPER_ACTION_STATE rollback; // only valid during Plan. @@ -286,9 +293,12 @@ typedef struct _BURN_PACKAGE BURN_DEPENDENCY_ACTION dependencyExecute; // only valid during Plan. BURN_DEPENDENCY_ACTION dependencyRollback; // only valid during Plan. BOOL fDependencyManagerWasHere; // only valid during Plan. + BURN_CACHE_PACKAGE_TYPE executeCacheType; // only valid during Plan. + BURN_CACHE_PACKAGE_TYPE rollbackCacheType; // only valid during Plan. HANDLE hCacheEvent; // only valid during Plan. LPWSTR sczCacheFolder; // only valid during Apply. HRESULT hrCacheResult; // only valid during Apply. + BOOL fAcquireOptionalSource; // only valid during Apply. BOOL fReachedExecution; // only valid during Apply. BOOL fAbandonedProcess; // only valid during Apply. diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index 419d3272..18f9b274 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp @@ -78,11 +78,13 @@ static HRESULT AddRegistrationAction( ); static HRESULT AddCachePackage( __in BURN_PLAN* pPlan, - __in BURN_PACKAGE* pPackage + __in BURN_PACKAGE* pPackage, + __in BOOL fVital ); static HRESULT AddCachePackageHelper( __in BURN_PLAN* pPlan, - __in BURN_PACKAGE* pPackage + __in BURN_PACKAGE* pPackage, + __in BOOL fVital ); static HRESULT AddCacheSlipstreamMsps( __in BURN_PLAN* pPlan, @@ -134,7 +136,7 @@ static HRESULT CalculateExecuteActions( __in BURN_PACKAGE* pPackage, __in_opt BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary ); -static BOOL NeedsCache( +static BURN_CACHE_PACKAGE_TYPE GetCachePackageType( __in BURN_PACKAGE* pPackage, __in BOOL fExecute ); @@ -894,7 +896,7 @@ static HRESULT PlanPackagesHelper( DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i; BURN_PACKAGE* pPackage = rgPackages + iPackage; - UserExperienceOnPlannedPackage(pUX, pPackage->sczId, pPackage->execute, pPackage->rollback, pPackage->fPlannedCache, pPackage->fPlannedUncache); + UserExperienceOnPlannedPackage(pUX, pPackage->sczId, pPackage->execute, pPackage->rollback, NULL != pPackage->hCacheEvent, pPackage->fPlannedUncache); if (pPackage->compatiblePackage.fPlannable) { @@ -999,7 +1001,7 @@ static HRESULT ProcessPackage( { if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested) { - hr = PlanLayoutPackage(pPlan, pPackage); + hr = PlanLayoutPackage(pPlan, pPackage, TRUE); ExitOnFailure(hr, "Failed to plan layout package."); } } @@ -1015,7 +1017,7 @@ static HRESULT ProcessPackage( { if (ForceCache(pPlan, pPackage)) { - hr = AddCachePackage(pPlan, pPackage); + hr = AddCachePackage(pPlan, pPackage, TRUE); ExitOnFailure(hr, "Failed to plan cache package."); if (pPackage->fPerMachine) @@ -1127,7 +1129,8 @@ LExit: extern "C" HRESULT PlanLayoutPackage( __in BURN_PLAN* pPlan, - __in BURN_PACKAGE* pPackage + __in BURN_PACKAGE* pPackage, + __in BOOL fVital ) { HRESULT hr = S_OK; @@ -1143,6 +1146,7 @@ extern "C" HRESULT PlanLayoutPackage( pCacheAction->type = BURN_CACHE_ACTION_TYPE_PACKAGE; pCacheAction->package.pPackage = pPackage; + pPackage->fCacheVital = fVital; ++pPlan->cOverallProgressTicksTotal; @@ -1170,18 +1174,14 @@ extern "C" HRESULT PlanExecutePackage( hr = DependencyPlanPackageBegin(fPerMachine, pPackage, pPlan); ExitOnFailure(hr, "Failed to begin plan dependency actions for package: %ls", pPackage->sczId); - if (fRequestedCache || NeedsCache(pPackage, TRUE)) + pPackage->executeCacheType = fRequestedCache ? BURN_CACHE_PACKAGE_TYPE_REQUIRED : GetCachePackageType(pPackage, TRUE); + pPackage->rollbackCacheType = GetCachePackageType(pPackage, FALSE); + + if (BURN_CACHE_PACKAGE_TYPE_NONE != pPackage->executeCacheType || BURN_CACHE_PACKAGE_TYPE_NONE != pPackage->rollbackCacheType) { - hr = AddCachePackage(pPlan, pPackage); + hr = AddCachePackage(pPlan, pPackage, BURN_CACHE_PACKAGE_TYPE_REQUIRED == pPackage->executeCacheType); ExitOnFailure(hr, "Failed to plan cache package."); } - else if (!pPackage->fCached && NeedsCache(pPackage, FALSE)) - { - // TODO: this decision should be made during apply instead of plan based on whether the package is actually cached. - // If the package is not in the cache, disable any rollback that would require the package from the cache. - LogId(REPORT_STANDARD, MSG_PLAN_DISABLING_ROLLBACK_NO_CACHE, pPackage->sczId, LoggingActionStateToString(pPackage->rollback)); - pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE; - } // Add execute actions. switch (pPackage->type) @@ -1364,6 +1364,8 @@ extern "C" HRESULT PlanRelatedBundlesInitialize( pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE; pRelatedBundle->defaultPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE; pRelatedBundle->planRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE; + pRelatedBundle->package.executeCacheType = BURN_CACHE_PACKAGE_TYPE_NONE; + pRelatedBundle->package.rollbackCacheType = BURN_CACHE_PACKAGE_TYPE_NONE; // Determine the plan relation type even if later it is ignored due to the planned action, the command relation type, or the related bundle not being plannable. // This gives more information to the BA in case it wants to override default behavior. @@ -2088,10 +2090,6 @@ static void UninitializeCacheAction( { switch (pCacheAction->type) { - case BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT: - ReleaseHandle(pCacheAction->syncpoint.hEvent); - break; - case BURN_CACHE_ACTION_TYPE_LAYOUT_BUNDLE: ReleaseStr(pCacheAction->bundleLayout.sczExecutableName); ReleaseStr(pCacheAction->bundleLayout.sczUnverifiedPath); @@ -2145,7 +2143,7 @@ static void ResetPlannedPackageState( pPackage->cacheType = pPackage->authoredCacheType; pPackage->defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE; pPackage->requested = BOOTSTRAPPER_REQUEST_STATE_NONE; - pPackage->fPlannedCache = FALSE; + pPackage->fCacheVital = FALSE; pPackage->fPlannedUncache = FALSE; pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE; pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE; @@ -2156,7 +2154,9 @@ static void ResetPlannedPackageState( pPackage->fDependencyManagerWasHere = FALSE; pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN; pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN; - pPackage->hCacheEvent = NULL; + pPackage->executeCacheType = BURN_CACHE_PACKAGE_TYPE_NONE; + pPackage->rollbackCacheType = BURN_CACHE_PACKAGE_TYPE_NONE; + ReleaseHandle(pPackage->hCacheEvent); ReleaseNullStr(pPackage->sczCacheFolder); @@ -2314,19 +2314,21 @@ LExit: static HRESULT AddCachePackage( __in BURN_PLAN* pPlan, - __in BURN_PACKAGE* pPackage + __in BURN_PACKAGE* pPackage, + __in BOOL fVital ) { HRESULT hr = S_OK; // If this is an MSI package with slipstream MSPs, ensure the MSPs are cached first. - if (BURN_PACKAGE_TYPE_MSI == pPackage->type && 0 < pPackage->Msi.cSlipstreamMspPackages) + // TODO: Slipstream packages are not accounted for when caching the MSI package is optional. + if (BURN_PACKAGE_TYPE_MSI == pPackage->type && 0 < pPackage->Msi.cSlipstreamMspPackages && fVital) { hr = AddCacheSlipstreamMsps(pPlan, pPackage); ExitOnFailure(hr, "Failed to plan slipstream patches for package."); } - hr = AddCachePackageHelper(pPlan, pPackage); + hr = AddCachePackageHelper(pPlan, pPackage, fVital); ExitOnFailure(hr, "Failed to plan cache package."); LExit: @@ -2335,7 +2337,8 @@ LExit: static HRESULT AddCachePackageHelper( __in BURN_PLAN* pPlan, - __in BURN_PACKAGE* pPackage + __in BURN_PACKAGE* pPackage, + __in BOOL fVital ) { AssertSz(pPackage->sczCacheId && *pPackage->sczCacheId, "AddCachePackageHelper() expects the package to have a cache id."); @@ -2354,6 +2357,9 @@ static HRESULT AddCachePackageHelper( ExitFunction(); } + pPackage->hCacheEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL); + ExitOnNullWithLastError(pPackage->hCacheEvent, hr, "Failed to create syncpoint event."); + // Cache checkpoints happen before the package is cached because downloading packages' // payloads will not roll themselves back the way installation packages rollback on // failure automatically. @@ -2381,7 +2387,7 @@ static HRESULT AddCachePackageHelper( pCacheAction->checkpoint.dwId = dwCheckpoint; } - hr = PlanLayoutPackage(pPlan, pPackage); + hr = PlanLayoutPackage(pPlan, pPackage, fVital); ExitOnFailure(hr, "Failed to plan cache for package."); // Create syncpoint action. @@ -2389,15 +2395,11 @@ static HRESULT AddCachePackageHelper( ExitOnFailure(hr, "Failed to append cache action."); pCacheAction->type = BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT; - pCacheAction->syncpoint.hEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL); - ExitOnNullWithLastError(pCacheAction->syncpoint.hEvent, hr, "Failed to create syncpoint event."); - - pPackage->hCacheEvent = pCacheAction->syncpoint.hEvent; + pCacheAction->syncpoint.pPackage = pPackage; hr = PlanExecuteCacheSyncAndRollback(pPlan, pPackage); ExitOnFailure(hr, "Failed to plan package cache syncpoint"); - pPackage->fPlannedCache = TRUE; if (pPackage->fCanAffectRegistration) { pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT; @@ -2421,7 +2423,7 @@ static HRESULT AddCacheSlipstreamMsps( BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[i].pMspPackage; AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches."); - hr = AddCachePackageHelper(pPlan, pMspPackage); + hr = AddCachePackageHelper(pPlan, pMspPackage, TRUE); ExitOnFailure(hr, "Failed to plan slipstream MSP: %ls", pMspPackage->sczId); } @@ -2791,22 +2793,41 @@ LExit: return hr; } -static BOOL NeedsCache( +static BURN_CACHE_PACKAGE_TYPE GetCachePackageType( __in BURN_PACKAGE* pPackage, __in BOOL fExecute ) { - BOOTSTRAPPER_ACTION_STATE action = fExecute ? pPackage->execute : pPackage->rollback; - // TODO: bundles could theoretically use package cache - if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || // Bundle and Exe packages require the package for all operations (even uninstall). - BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_DETECTION_TYPE_ARP != pPackage->Exe.detectionType) - { - return BOOTSTRAPPER_ACTION_STATE_NONE != action; - } - else // The other package types can uninstall without the original package. + BURN_CACHE_PACKAGE_TYPE cachePackageType = BURN_CACHE_PACKAGE_TYPE_NONE; + + switch (fExecute ? pPackage->execute : pPackage->rollback) { - return BOOTSTRAPPER_ACTION_STATE_UNINSTALL < action; + case BOOTSTRAPPER_ACTION_STATE_NONE: + break; + case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: + if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || + BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_DETECTION_TYPE_ARP != pPackage->Exe.detectionType) + { + // Bundle and non-ArpEntry Exe packages require the package for all operations (even uninstall). + // TODO: bundles could theoretically use package cache. + cachePackageType = BURN_CACHE_PACKAGE_TYPE_REQUIRED; + } + else + { + // The other package types can uninstall without the original package. + cachePackageType = BURN_CACHE_PACKAGE_TYPE_NONE; + } + break; + case BOOTSTRAPPER_ACTION_STATE_INSTALL: __fallthrough; + case BOOTSTRAPPER_ACTION_STATE_MODIFY: __fallthrough; + case BOOTSTRAPPER_ACTION_STATE_REPAIR: __fallthrough; + case BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE: __fallthrough; + default: + cachePackageType = BURN_CACHE_PACKAGE_TYPE_REQUIRED; + break; } + + return cachePackageType; } static BOOL ForceCache( @@ -2881,7 +2902,7 @@ static void CacheActionLog( break; case BURN_CACHE_ACTION_TYPE_PACKAGE: - LogStringLine(PlanDumpLevel, "%ls action[%u]: PACKAGE id: %ls", wzBase, iAction, pAction->package.pPackage->sczId); + LogStringLine(PlanDumpLevel, "%ls action[%u]: PACKAGE id: %ls, vital: %hs, execute cache type: %hs, rollback cache type: %hs", wzBase, iAction, pAction->package.pPackage->sczId, LoggingBoolToString(pAction->package.pPackage->fCacheVital), LoggingCachePackageTypeToString(pAction->package.pPackage->executeCacheType), LoggingCachePackageTypeToString(pAction->package.pPackage->rollbackCacheType)); break; case BURN_CACHE_ACTION_TYPE_ROLLBACK_PACKAGE: @@ -2889,7 +2910,7 @@ static void CacheActionLog( break; case BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT: - LogStringLine(PlanDumpLevel, "%ls action[%u]: SIGNAL_SYNCPOINT event handle: 0x%p", wzBase, iAction, pAction->syncpoint.hEvent); + LogStringLine(PlanDumpLevel, "%ls action[%u]: SIGNAL_SYNCPOINT package id: %ls, event handle: 0x%p", wzBase, iAction, pAction->syncpoint.pPackage->sczId, pAction->syncpoint.pPackage->hCacheEvent); break; default: diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h index 46a9a363..386de2c6 100644 --- a/src/burn/engine/plan.h +++ b/src/burn/engine/plan.h @@ -117,7 +117,7 @@ typedef struct _BURN_CACHE_ACTION } rollbackPackage; struct { - HANDLE hEvent; + BURN_PACKAGE* pPackage; } syncpoint; struct { @@ -392,7 +392,8 @@ HRESULT PlanLayoutContainer( ); HRESULT PlanLayoutPackage( __in BURN_PLAN* pPlan, - __in BURN_PACKAGE* pPackage + __in BURN_PACKAGE* pPackage, + __in BOOL fVital ); HRESULT PlanExecutePackage( __in BOOL fPerMachine, diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp index 87ef4de1..a97234ef 100644 --- a/src/burn/engine/userexperience.cpp +++ b/src/burn/engine/userexperience.cpp @@ -104,7 +104,7 @@ extern "C" HRESULT UserExperienceLoad( args.pCommand = pCommand; args.pfnBootstrapperEngineProc = EngineForApplicationProc; args.pvBootstrapperEngineProcContext = pEngineContext; - args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 31, 0); + args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 6, 10, 0); results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); @@ -726,7 +726,8 @@ EXTERN_C BAAPI UserExperienceOnCachePackageBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in_z LPCWSTR wzPackageId, __in DWORD cCachePayloads, - __in DWORD64 dw64PackageCacheSize + __in DWORD64 dw64PackageCacheSize, + __in BOOL fVital ) { HRESULT hr = S_OK; @@ -737,6 +738,7 @@ EXTERN_C BAAPI UserExperienceOnCachePackageBegin( args.wzPackageId = wzPackageId; args.cCachePayloads = cCachePayloads; args.dw64PackageCacheSize = dw64PackageCacheSize; + args.fVital = fVital; results.cbSize = sizeof(results); @@ -783,6 +785,40 @@ LExit: return hr; } +EXTERN_C BAAPI UserExperienceOnCachePackageNonVitalValidationFailure( + __in BURN_USER_EXPERIENCE* pUserExperience, + __in_z LPCWSTR wzPackageId, + __in HRESULT hrStatus, + __inout BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION* pAction + ) +{ + HRESULT hr = S_OK; + BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_ARGS args = { }; + BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_RESULTS results = { }; + + args.cbSize = sizeof(args); + args.wzPackageId = wzPackageId; + args.hrStatus = hrStatus; + args.recommendation = *pAction; + + results.cbSize = sizeof(results); + results.action = *pAction; + + hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE, &args, &results); + ExitOnFailure(hr, "BA OnCachePackageNonVitalValidationFailure failed."); + + switch (results.action) + { + case BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_NONE: __fallthrough; + case BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_ACQUIRE: + *pAction = results.action; + break; + } + +LExit: + return hr; +} + EXTERN_C BAAPI UserExperienceOnCachePayloadExtractBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in_z_opt LPCWSTR wzContainerId, diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h index 94b73f7d..9f183208 100644 --- a/src/burn/engine/userexperience.h +++ b/src/burn/engine/userexperience.h @@ -189,7 +189,14 @@ BAAPI UserExperienceOnCachePackageBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in_z LPCWSTR wzPackageId, __in DWORD cCachePayloads, - __in DWORD64 dw64PackageCacheSize + __in DWORD64 dw64PackageCacheSize, + __in BOOL fVital + ); +BAAPI UserExperienceOnCachePackageNonVitalValidationFailure( + __in BURN_USER_EXPERIENCE* pUserExperience, + __in_z LPCWSTR wzPackageId, + __in HRESULT hrStatus, + __inout BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION* pAction ); BAAPI UserExperienceOnCachePackageComplete( __in BURN_USER_EXPERIENCE* pUserExperience, diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 2135d9f5..37027ada 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp @@ -87,8 +87,8 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"TestExe"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"TestExe", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"TestExe"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -259,19 +259,24 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"TestExe", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"TestExe"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); - Assert::Equal(0ull, pPlan->qwCacheSizeTotal); + Assert::Equal(143724ull, pPlan->qwCacheSizeTotal); fRollback = FALSE; dwIndex = 0; - DWORD dwExecuteCheckpointId = 1; + DWORD dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"TestExe"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"TestExe", BOOTSTRAPPER_ACTION_STATE_UNINSTALL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -280,8 +285,9 @@ namespace Bootstrapper fRollback = TRUE; dwIndex = 0; - dwExecuteCheckpointId = 1; + dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"TestExe", BOOTSTRAPPER_ACTION_STATE_INSTALL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -290,7 +296,7 @@ namespace Bootstrapper Assert::Equal(dwIndex, pPlan->cRollbackActions); Assert::Equal(1ul, pPlan->cExecutePackagesTotal); - Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal); + Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); @@ -347,14 +353,14 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 9); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageB"); ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 14); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageC"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageC", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageC"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -506,13 +512,16 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 9); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); - Assert::Equal(0ull, pPlan->qwCacheSizeTotal); + Assert::Equal(185118ull, pPlan->qwCacheSizeTotal); fRollback = FALSE; dwIndex = 0; @@ -536,6 +545,9 @@ namespace Bootstrapper ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + dwExecuteCheckpointId += 1; // cache checkpoints + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", unregisterActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -565,6 +577,8 @@ namespace Bootstrapper ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + dwExecuteCheckpointId += 1; // cache checkpoints + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", registerActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1); @@ -577,7 +591,7 @@ namespace Bootstrapper Assert::Equal(dwIndex, pPlan->cRollbackActions); Assert::Equal(3ul, pPlan->cExecutePackagesTotal); - Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal); + Assert::Equal(4ul, pPlan->cOverallProgressTicksTotal); dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); @@ -640,11 +654,11 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_REQUIRED); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 6); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_REQUIRED); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageB"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -753,8 +767,8 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 2); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageB"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -949,8 +963,8 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -1068,8 +1082,8 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -1170,8 +1184,8 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"ExeA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"ExeA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_REQUIRED); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"ExeA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -1264,8 +1278,8 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -1515,8 +1529,8 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -1610,8 +1624,8 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -1794,19 +1808,24 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); - Assert::Equal(0ull, pPlan->qwCacheSizeTotal); + Assert::Equal(175674ull, pPlan->qwCacheSizeTotal); fRollback = FALSE; dwIndex = 0; - DWORD dwExecuteCheckpointId = 1; + DWORD dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", unregisterActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", unregisterActions1, 1); @@ -1819,8 +1838,9 @@ namespace Bootstrapper fRollback = TRUE; dwIndex = 0; - dwExecuteCheckpointId = 1; + dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", registerActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1); @@ -1833,7 +1853,7 @@ namespace Bootstrapper Assert::Equal(dwIndex, pPlan->cRollbackActions); Assert::Equal(1ul, pPlan->cExecutePackagesTotal); - Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal); + Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); @@ -2043,19 +2063,24 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); - Assert::Equal(0ull, pPlan->qwCacheSizeTotal); + Assert::Equal(175674ull, pPlan->qwCacheSizeTotal); fRollback = FALSE; dwIndex = 0; - DWORD dwExecuteCheckpointId = 1; + DWORD dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", unregisterActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", unregisterActions1, 1); @@ -2068,8 +2093,9 @@ namespace Bootstrapper fRollback = TRUE; dwIndex = 0; - dwExecuteCheckpointId = 1; + dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", registerActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1); @@ -2082,7 +2108,7 @@ namespace Bootstrapper Assert::Equal(dwIndex, pPlan->cRollbackActions); Assert::Equal(1ul, pPlan->cExecutePackagesTotal); - Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal); + Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); @@ -2139,8 +2165,8 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"test.msu"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"test.msu", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"test.msu"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -2233,14 +2259,14 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"NetFx48Web"); ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 3); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PatchA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PatchA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PatchA"); ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 5); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -2363,26 +2389,37 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PatchA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PatchA"); + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 6); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); - Assert::Equal(0ull, pPlan->qwCacheSizeTotal); + Assert::Equal(212992ull, pPlan->qwCacheSizeTotal); fRollback = FALSE; dwIndex = 0; - DWORD dwExecuteCheckpointId = 1; + DWORD dwExecuteCheckpointId = 2; BURN_EXECUTE_ACTION* pExecuteAction = NULL; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PatchA"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", unregisterActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", unregisterActions1, 1); pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, TRUE); ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA"); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + dwExecuteCheckpointId += 1; // cache checkpoints + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", unregisterActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -2396,8 +2433,9 @@ namespace Bootstrapper fRollback = TRUE; dwIndex = 0; - dwExecuteCheckpointId = 1; + dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", registerActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", registerActions1, 1); @@ -2405,6 +2443,8 @@ namespace Bootstrapper pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_INSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, TRUE); ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA"); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + dwExecuteCheckpointId += 1; // cache checkpoints + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", registerActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1); @@ -2417,7 +2457,7 @@ namespace Bootstrapper Assert::Equal(dwIndex, pPlan->cRollbackActions); Assert::Equal(2ul, pPlan->cExecutePackagesTotal); - Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); + Assert::Equal(4ul, pPlan->cOverallProgressTicksTotal); dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); @@ -2479,19 +2519,24 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); - Assert::Equal(0ull, pPlan->qwCacheSizeTotal); + Assert::Equal(131072ull, pPlan->qwCacheSizeTotal); fRollback = FALSE; dwIndex = 0; - DWORD dwExecuteCheckpointId = 1; + DWORD dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", unregisterActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", unregisterActions1, 1); @@ -2504,8 +2549,9 @@ namespace Bootstrapper fRollback = TRUE; dwIndex = 0; - dwExecuteCheckpointId = 1; + dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", registerActions1, 1); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1); @@ -2518,7 +2564,7 @@ namespace Bootstrapper Assert::Equal(dwIndex, pPlan->cRollbackActions); Assert::Equal(1ul, pPlan->cExecutePackagesTotal); - Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal); + Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); dwIndex = 0; Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); @@ -2575,11 +2621,11 @@ namespace Bootstrapper fRollback = FALSE; dwIndex = 0; ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"NetFx48Web"); ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 4); - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA"); Assert::Equal(dwIndex, pPlan->cCacheActions); fRollback = TRUE; @@ -3008,12 +3054,18 @@ namespace Bootstrapper __in BURN_PLAN* pPlan, __in BOOL fRollback, __in DWORD dwIndex, - __in LPCWSTR wzPackageId + __in LPCWSTR wzPackageId, + __in BOOL fVital, + __in BURN_CACHE_PACKAGE_TYPE executeCacheType, + __in BURN_CACHE_PACKAGE_TYPE rollbackCacheType ) { BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); Assert::Equal(BURN_CACHE_ACTION_TYPE_PACKAGE, pAction->type); NativeAssert::StringEqual(wzPackageId, pAction->package.pPackage->sczId); + Assert::Equal(fVital, pAction->package.pPackage->fCacheVital); + Assert::Equal(executeCacheType, pAction->package.pPackage->executeCacheType); + Assert::Equal(rollbackCacheType, pAction->package.pPackage->rollbackCacheType); return dwIndex + 1; } @@ -3032,12 +3084,13 @@ namespace Bootstrapper void ValidateCacheSignalSyncpoint( __in BURN_PLAN* pPlan, __in BOOL fRollback, - __in DWORD dwIndex + __in DWORD dwIndex, + __in LPCWSTR wzPackageId ) { BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); Assert::Equal(BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT, pAction->type); - Assert::NotEqual((DWORD_PTR)NULL, (DWORD_PTR)pAction->syncpoint.hEvent); + NativeAssert::StringEqual(wzPackageId, pAction->syncpoint.pPackage->sczId); } void ValidateCleanAction( diff --git a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp index 9c0f9576..9aa58a28 100644 --- a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp +++ b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp @@ -655,6 +655,7 @@ public: // IBootstrapperApplication __in_z LPCWSTR wzPackageId, __in DWORD cCachePayloads, __in DWORD64 dw64PackageCacheSize, + __in BOOL fVital, __inout BOOL* pfCancel ) { @@ -673,7 +674,7 @@ public: // IBootstrapperApplication } } - return __super::OnCachePackageBegin(wzPackageId, cCachePayloads, dw64PackageCacheSize, pfCancel); + return __super::OnCachePackageBegin(wzPackageId, cCachePayloads, dw64PackageCacheSize, fVital, pfCancel); } @@ -1488,6 +1489,9 @@ public: // IBootstrapperApplication case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE: OnDetectRelatedBundlePackageFallback(reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); break; + case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE: + OnCachePackageNonVitalValidationFailureFallback(reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; default: #ifdef DEBUG BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: Forwarding unknown BA message: %d", message); @@ -2177,6 +2181,14 @@ private: // privates m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE, pArgs, pResults, m_pvBAFunctionsProcContext); } + void OnCachePackageNonVitalValidationFailureFallback( + __in BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_ARGS* pArgs, + __inout BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_RESULTS* pResults + ) + { + m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE, pArgs, pResults, m_pvBAFunctionsProcContext); + } + public: //CBalBaseBootstrapperApplication virtual STDMETHODIMP Initialize( diff --git a/src/test/burn/TestBA/TestBA.cs b/src/test/burn/TestBA/TestBA.cs index 9ca82377..7e3d2623 100644 --- a/src/test/burn/TestBA/TestBA.cs +++ b/src/test/burn/TestBA/TestBA.cs @@ -27,6 +27,7 @@ namespace WixToolset.Test.BA private string updateBundlePath; + private bool allowAcquireAfterValidationFailure; private bool forceKeepRegistration; private bool immediatelyQuit; private bool quitAfterDetect; @@ -85,7 +86,11 @@ namespace WixToolset.Test.BA List verifyArguments = this.ReadVerifyArguments(); - foreach (string arg in BootstrapperCommand.ParseCommandLineToArgs(this.Command.CommandLine)) + IBootstrapperApplicationData baManifest = new BootstrapperApplicationData(); + IMbaCommand mbaCommand = this.Command.ParseCommandLine(); + mbaCommand.SetOverridableVariables(baManifest.Bundle.OverridableVariables, this.engine); + + foreach (string arg in mbaCommand.UnknownCommandLineArgs) { // If we're not in the update already, process the updatebundle. if (this.Command.Relation != RelationType.Update && arg.StartsWith("-updatebundle:", StringComparison.OrdinalIgnoreCase)) @@ -126,6 +131,12 @@ namespace WixToolset.Test.BA redetectCount = 0; } + string allowAcquireAfterValidationFailure = this.ReadPackageAction(null, "AllowAcquireAfterValidationFailure"); + if (String.IsNullOrEmpty(allowAcquireAfterValidationFailure) || !Boolean.TryParse(allowAcquireAfterValidationFailure, out this.allowAcquireAfterValidationFailure)) + { + this.allowAcquireAfterValidationFailure = false; + } + string explicitlyElevateAndPlanFromOnElevateBegin = this.ReadPackageAction(null, "ExplicitlyElevateAndPlanFromOnElevateBegin"); if (String.IsNullOrEmpty(explicitlyElevateAndPlanFromOnElevateBegin) || !Boolean.TryParse(explicitlyElevateAndPlanFromOnElevateBegin, out this.explicitlyElevateAndPlanFromOnElevateBegin)) { @@ -277,6 +288,15 @@ namespace WixToolset.Test.BA { args.State = state; } + + BOOTSTRAPPER_CACHE_TYPE cacheType; + string cacheAction = this.ReadPackageAction(args.PackageId, "CacheRequested"); + if (TryParseEnum(cacheAction, out cacheType)) + { + args.CacheType = cacheType; + } + + this.Log("OnPlanPackageBegin() - id: {0}, defaultState: {1}, requestedState: {2}, defaultCache: {3}, requestedCache: {4}", args.PackageId, args.RecommendedState, args.State, args.RecommendedCacheType, args.CacheType); } protected override void OnPlanPatchTarget(PlanPatchTargetEventArgs args) @@ -337,6 +357,16 @@ namespace WixToolset.Test.BA } } + protected override void OnCachePackageNonVitalValidationFailure(CachePackageNonVitalValidationFailureEventArgs args) + { + if (this.allowAcquireAfterValidationFailure) + { + args.Action = BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION.Acquire; + } + + this.Log("OnCachePackageNonVitalValidationFailure() - id: {0}, default: {1}, requested: {2}", args.PackageId, args.Recommendation, args.Action); + } + protected override void OnCacheAcquireProgress(CacheAcquireProgressEventArgs args) { 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); diff --git a/src/test/burn/TestData/ExePackageTests/PackageTestExe/PackageTestExe.wixproj b/src/test/burn/TestData/ExePackageTests/PackageTestExe/PackageTestExe.wixproj new file mode 100644 index 00000000..57e99a1b --- /dev/null +++ b/src/test/burn/TestData/ExePackageTests/PackageTestExe/PackageTestExe.wixproj @@ -0,0 +1,16 @@ + + + + true + {9281948B-9C8D-4914-A00E-3EF0F98D17EB} + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ExePackageTests/PackageTestExe/ProductComponents.wxs b/src/test/burn/TestData/ExePackageTests/PackageTestExe/ProductComponents.wxs new file mode 100644 index 00000000..b42c5c5a --- /dev/null +++ b/src/test/burn/TestData/ExePackageTests/PackageTestExe/ProductComponents.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageUninstallFailure/PerMachineArpEntryExePackageUninstallFailure.wixproj b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageUninstallFailure/PerMachineArpEntryExePackageUninstallFailure.wixproj new file mode 100644 index 00000000..bbab2b75 --- /dev/null +++ b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageUninstallFailure/PerMachineArpEntryExePackageUninstallFailure.wixproj @@ -0,0 +1,18 @@ + + + + Bundle + {799DF604-49CB-4B2C-9FD9-A1C4F93A2FDE} + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageUninstallFailure/PerMachineArpEntryExePackageUninstallFailure.wxs b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageUninstallFailure/PerMachineArpEntryExePackageUninstallFailure.wxs new file mode 100644 index 00000000..ffa98d4e --- /dev/null +++ b/src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageUninstallFailure/PerMachineArpEntryExePackageUninstallFailure.wxs @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/TestBA/TestBAWixlib/TestExe.wxs b/src/test/burn/TestData/TestBA/TestBAWixlib/TestExe.wxs index f27275b0..84da0983 100644 --- a/src/test/burn/TestData/TestBA/TestBAWixlib/TestExe.wxs +++ b/src/test/burn/TestData/TestBA/TestBAWixlib/TestExe.wxs @@ -6,4 +6,11 @@ + + + + + + + diff --git a/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs index dc6515b5..e76461f3 100644 --- a/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs +++ b/src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs @@ -3,6 +3,7 @@ namespace WixToolsetTest.BurnE2E { using WixTestTools; + using WixToolset.Mba.Core; using Xunit; using Xunit.Abstractions; @@ -13,9 +14,9 @@ namespace WixToolsetTest.BurnE2E [RuntimeFact] public void CanInstallAndUninstallPerMachineArpEntryExePackage() { - const string arpId = "{4D9EC36A-1E63-4244-875C-3ECB0A2CAE30}"; var perMachineArpEntryExePackageBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackage"); var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageBundle, "TestExe"); + var arpId = arpEntryExePackage.ArpId; arpEntryExePackage.VerifyRegistered(false); @@ -23,21 +24,113 @@ namespace WixToolsetTest.BurnE2E perMachineArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache(); arpEntryExePackage.VerifyRegistered(true); - LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""); + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); var uninstallLogPath = perMachineArpEntryExePackageBundle.Uninstall(); perMachineArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache(); arpEntryExePackage.VerifyRegistered(false); - LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}"); + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); } [RuntimeFact] - public void CanUninstallPerMachineArpEntryExePackageOnRollback() + public void CanRecacheAndReinstallPerMachineArpEntryExePackageOnUninstallRollback() + { + var packageTestExe = this.CreatePackageInstaller("PackageTestExe"); + var perMachineArpEntryExePackageUninstallFailureBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackageUninstallFailure"); + var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageUninstallFailureBundle, "TestExe"); + var arpId = arpEntryExePackage.ArpId; + var testBAController = this.CreateTestBAController(); + + arpEntryExePackage.VerifyRegistered(false); + packageTestExe.VerifyInstalled(false); + + testBAController.SetPackageRequestedCacheType("TestExe", BOOTSTRAPPER_CACHE_TYPE.Remove); + + var installLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Install(); + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache(); + arpEntryExePackage.VerifyRegistered(true); + packageTestExe.VerifyInstalled(true); + + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); + + testBAController.ResetPackageStates("TestExe"); + testBAController.SetAllowAcquireAfterValidationFailure(); + + var uninstallLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Uninstall((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, "FAILWHENDEFERRED=1"); + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache(); + arpEntryExePackage.VerifyRegistered(true); + packageTestExe.VerifyInstalled(true); + + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe, default: None, requested: Acquire")); + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); + } + + [RuntimeFact] + public void CanReinstallPerMachineArpEntryExePackageOnUninstallRollback() + { + var packageTestExe = this.CreatePackageInstaller("PackageTestExe"); + var perMachineArpEntryExePackageUninstallFailureBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackageUninstallFailure"); + var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageUninstallFailureBundle, "TestExe"); + var arpId = arpEntryExePackage.ArpId; + + arpEntryExePackage.VerifyRegistered(false); + packageTestExe.VerifyInstalled(false); + + var installLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Install(); + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache(); + arpEntryExePackage.VerifyRegistered(true); + packageTestExe.VerifyInstalled(true); + + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); + + var uninstallLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Uninstall((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, "FAILWHENDEFERRED=1"); + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache(); + arpEntryExePackage.VerifyRegistered(true); + packageTestExe.VerifyInstalled(true); + + Assert.False(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe")); + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); + } + + [RuntimeFact] + public void CanSkipReinstallPerMachineArpEntryExePackageOnUninstallRollback() + { + var packageTestExe = this.CreatePackageInstaller("PackageTestExe"); + var perMachineArpEntryExePackageUninstallFailureBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackageUninstallFailure"); + var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageUninstallFailureBundle, "TestExe"); + var arpId = arpEntryExePackage.ArpId; + var testBAController = this.CreateTestBAController(); + + arpEntryExePackage.VerifyRegistered(false); + packageTestExe.VerifyInstalled(false); + + testBAController.SetPackageRequestedCacheType("TestExe", BOOTSTRAPPER_CACHE_TYPE.Remove); + + var installLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Install(); + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache(); + arpEntryExePackage.VerifyRegistered(true); + packageTestExe.VerifyInstalled(true); + + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); + + var uninstallLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Uninstall((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, "FAILWHENDEFERRED=1"); + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache(); + arpEntryExePackage.VerifyRegistered(false); + packageTestExe.VerifyInstalled(true); + + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe, default: None, requested: None")); + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); + } + + [RuntimeFact] + public void CanUninstallPerMachineArpEntryExePackageOnInstallRollback() { - const string arpId = "{80E90929-EEA5-48A7-A680-A0237A1CAD84}"; var perMachineArpEntryExePackageFailureBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackageFailure"); var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageFailureBundle, "TestExe"); + var arpId = arpEntryExePackage.ArpId; arpEntryExePackage.VerifyRegistered(false); @@ -45,16 +138,16 @@ namespace WixToolsetTest.BurnE2E perMachineArpEntryExePackageFailureBundle.VerifyUnregisteredAndRemovedFromPackageCache(); arpEntryExePackage.VerifyRegistered(false); - LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""); - LogVerifier.MessageInLogFile(installLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}"); + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); } [RuntimeFact] public void CanInstallAndUninstallPerUserArpEntryExePackage() { - const string arpId = "{9B5300C7-9B34-4670-9614-185B02AB87EF}"; var perUserArpEntryExePackageBundle = this.CreateBundleInstaller(@"PerUserArpEntryExePackage"); var arpEntryExePackage = this.CreateArpEntryInstaller(perUserArpEntryExePackageBundle, "TestExe"); + var arpId = arpEntryExePackage.ArpId; arpEntryExePackage.VerifyRegistered(false); @@ -62,21 +155,21 @@ namespace WixToolsetTest.BurnE2E perUserArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache(); arpEntryExePackage.VerifyRegistered(true); - LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""); + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"")); var uninstallLogPath = perUserArpEntryExePackageBundle.Uninstall(); perUserArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache(); arpEntryExePackage.VerifyRegistered(false); - LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}"); + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}")); } [RuntimeFact] public void FailsUninstallWhenPerUserArpEntryExePackageMissingQuietUninstallString() { - const string arpId = "{DE9F8594-5856-4454-AB10-3C01ED246D7D}"; var brokenPerUserArpEntryExePackageBundle = this.CreateBundleInstaller(@"BrokenPerUserArpEntryExePackage"); var arpEntryExePackage = this.CreateArpEntryInstaller(brokenPerUserArpEntryExePackageBundle, "TestExe"); + var arpId = arpEntryExePackage.ArpId; arpEntryExePackage.VerifyRegistered(false); brokenPerUserArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache(); @@ -85,7 +178,7 @@ namespace WixToolsetTest.BurnE2E brokenPerUserArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache(); arpEntryExePackage.VerifyRegistered(true); - LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\""); + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\"")); brokenPerUserArpEntryExePackageBundle.Uninstall((int)MSIExec.MSIExecReturnCode.ERROR_INVALID_PARAMETER); brokenPerUserArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache(); diff --git a/src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestBAController.cs b/src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestBAController.cs index 8e6611a2..3f9d76b8 100644 --- a/src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestBAController.cs +++ b/src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestBAController.cs @@ -42,6 +42,11 @@ namespace WixToolsetTest.BurnE2E } } + public void SetAllowAcquireAfterValidationFailure(string value = "true") + { + this.SetBurnTestValue("AllowAcquireAfterValidationFailure", value); + } + public void SetExplicitlyElevateAndPlanFromOnElevateBegin(string value = "true") { this.SetBurnTestValue("ExplicitlyElevateAndPlanFromOnElevateBegin", value); @@ -132,6 +137,16 @@ namespace WixToolsetTest.BurnE2E this.SetPackageState(packageId, "RetryExecuteFilesInUse", retryCount.HasValue ? retryCount.ToString() : null); } + /// + /// Sets the requested cache type for a package that the TestBA will return to the engine during plan. + /// + /// Package identity. + /// Cache type to request. + public void SetPackageRequestedCacheType(string packageId, BOOTSTRAPPER_CACHE_TYPE type) + { + this.SetPackageState(packageId, "CacheRequested", type.ToString()); + } + /// /// Sets the requested state for a package that the TestBA will return to the engine during plan. /// -- cgit v1.2.3-55-g6feb