From 0d873d28c2dd18444afa08b748e91f495ed1cf5c Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Sun, 15 Nov 2020 19:54:20 -0600 Subject: Add plan tests. --- src/engine/container.cpp | 36 +- src/engine/container.h | 5 +- src/engine/core.cpp | 4 + src/engine/logging.cpp | 21 + src/engine/logging.h | 4 + src/engine/manifest.cpp | 49 +- src/engine/manifest.h | 5 + src/engine/msiengine.cpp | 5 +- src/engine/msiengine.h | 6 + src/engine/plan.cpp | 34 +- src/engine/plan.h | 3 + src/test/BurnUnitTest/BurnUnitTest.vcxproj | 1 + src/test/BurnUnitTest/BurnUnitTest.vcxproj.filters | 3 + src/test/BurnUnitTest/PlanTest.cpp | 982 +++++++++++++++++++++ src/test/BurnUnitTest/precomp.h | 1 + 15 files changed, 1125 insertions(+), 34 deletions(-) create mode 100644 src/test/BurnUnitTest/PlanTest.cpp diff --git a/src/engine/container.cpp b/src/engine/container.cpp index ada9025b..55a16afb 100644 --- a/src/engine/container.cpp +++ b/src/engine/container.cpp @@ -17,7 +17,6 @@ static HRESULT GetAttachedContainerInfo( // function definitions extern "C" HRESULT ContainersParseFromXml( - __in BURN_SECTION* pSection, __in BURN_CONTAINERS* pContainers, __in IXMLDOMNode* pixnBundle ) @@ -128,14 +127,6 @@ extern "C" HRESULT ContainersParseFromXml( ExitOnFailure(hr, "Failed to get @Hash."); } - // If the container is attached, make sure the information in the section matches what the - // manifest contained and get the offset to the container. - if (pContainer->fAttached) - { - hr = SectionGetAttachedContainerInfo(pSection, pContainer->dwAttachedIndex, pContainer->type, &pContainer->qwAttachedOffset, &pContainer->qwFileSize, &pContainer->fActuallyAttached); - ExitOnFailure(hr, "Failed to get attached container information."); - } - // prepare next iteration ReleaseNullObject(pixnNode); } @@ -150,6 +141,33 @@ LExit: return hr; } +extern "C" HRESULT ContainersInitialize( + __in BURN_CONTAINERS* pContainers, + __in BURN_SECTION* pSection + ) +{ + HRESULT hr = S_OK; + + if (pContainers->rgContainers) + { + for (DWORD i = 0; i < pContainers->cContainers; ++i) + { + BURN_CONTAINER* pContainer = &pContainers->rgContainers[i]; + + // If the container is attached, make sure the information in the section matches what the + // manifest contained and get the offset to the container. + if (pContainer->fAttached) + { + hr = SectionGetAttachedContainerInfo(pSection, pContainer->dwAttachedIndex, pContainer->type, &pContainer->qwAttachedOffset, &pContainer->qwFileSize, &pContainer->fActuallyAttached); + ExitOnFailure(hr, "Failed to get attached container information."); + } + } + } + +LExit: + return hr; +} + extern "C" void ContainersUninitialize( __in BURN_CONTAINERS* pContainers ) diff --git a/src/engine/container.h b/src/engine/container.h index 2ca3d7ad..bbd9fa72 100644 --- a/src/engine/container.h +++ b/src/engine/container.h @@ -135,10 +135,13 @@ typedef struct _BURN_CONTAINER_CONTEXT // functions HRESULT ContainersParseFromXml( - __in BURN_SECTION* pSection, __in BURN_CONTAINERS* pContainers, __in IXMLDOMNode* pixnBundle ); +HRESULT ContainersInitialize( + __in BURN_CONTAINERS* pContainers, + __in BURN_SECTION* pSection + ); void ContainersUninitialize( __in BURN_CONTAINERS* pContainers ); diff --git a/src/engine/core.cpp b/src/engine/core.cpp index c34024fd..aeae6bea 100644 --- a/src/engine/core.cpp +++ b/src/engine/core.cpp @@ -96,6 +96,9 @@ extern "C" HRESULT CoreInitialize( hr = ManifestLoadXmlFromBuffer(pbBuffer, cbBuffer, pEngineState); ExitOnFailure(hr, "Failed to load manifest."); + hr = ContainersInitialize(&pEngineState->containers, &pEngineState->section); + ExitOnFailure(hr, "Failed to intialize containers."); + // Parse command line. hr = ParseCommandLine(pEngineState->argc, pEngineState->argv, &pEngineState->command, &pEngineState->companionConnection, &pEngineState->embeddedConnection, &pEngineState->variables, &pEngineState->mode, &pEngineState->automaticUpdates, &pEngineState->fDisableSystemRestore, &sczSourceProcessPath, &sczOriginalSource, &pEngineState->fDisableUnelevate, &pEngineState->log.dwAttributes, &pEngineState->log.sczPath, &pEngineState->registration.sczActiveParent, &pEngineState->sczIgnoreDependencies, &pEngineState->registration.sczAncestors, &sczSanitizedCommandLine); ExitOnFailure(hr, "Failed to parse command line."); @@ -411,6 +414,7 @@ extern "C" HRESULT CorePlan( pEngineState->plan.action = action; pEngineState->plan.wzBundleId = pEngineState->registration.sczId; pEngineState->plan.wzBundleProviderKey = pEngineState->registration.sczId; + pEngineState->plan.fDisableRollback = pEngineState->fDisableRollback; hr = PlanSetVariables(action, &pEngineState->variables); ExitOnFailure(hr, "Failed to update action."); diff --git a/src/engine/logging.cpp b/src/engine/logging.cpp index e69303f0..512b562c 100644 --- a/src/engine/logging.cpp +++ b/src/engine/logging.cpp @@ -468,6 +468,27 @@ extern "C" LPCSTR LoggingMsiInstallContext( } } +extern "C" LPCWSTR LoggingBurnMsiPropertyToString( + __in BURN_MSI_PROPERTY burnMsiProperty + ) +{ + switch (burnMsiProperty) + { + case BURN_MSI_PROPERTY_INSTALL: + return BURNMSIINSTALL_PROPERTY_NAME; + case BURN_MSI_PROPERTY_MODIFY: + return BURNMSIMODIFY_PROPERTY_NAME; + case BURN_MSI_PROPERTY_NONE: + return L"(none)"; + case BURN_MSI_PROPERTY_REPAIR: + return BURNMSIREPAIR_PROPERTY_NAME; + case BURN_MSI_PROPERTY_UNINSTALL: + return BURNMSIUNINSTALL_PROPERTY_NAME; + default: + return L"Invalid"; + } +} + extern "C" LPCSTR LoggingPerMachineToString( __in BOOL fPerMachine ) diff --git a/src/engine/logging.h b/src/engine/logging.h index 22dd54d9..381a295b 100644 --- a/src/engine/logging.h +++ b/src/engine/logging.h @@ -101,6 +101,10 @@ LPCSTR LoggingMsiInstallContext( __in MSIINSTALLCONTEXT context ); +LPCWSTR LoggingBurnMsiPropertyToString( + __in BURN_MSI_PROPERTY burnMsiProperty + ); + LPCSTR LoggingPerMachineToString( __in BOOL fPerMachine ); diff --git a/src/engine/manifest.cpp b/src/engine/manifest.cpp index 8783b15e..270b6b74 100644 --- a/src/engine/manifest.cpp +++ b/src/engine/manifest.cpp @@ -3,8 +3,33 @@ #include "precomp.h" +static HRESULT ParseFromXml( + __in IXMLDOMDocument* pixdDocument, + __in BURN_ENGINE_STATE* pEngineState + ); + // function definitions +extern "C" HRESULT ManifestLoadXml( + __in LPCWSTR wzDocument, + __in BURN_ENGINE_STATE* pEngineState + ) +{ + HRESULT hr = S_OK; + IXMLDOMDocument* pixdDocument = NULL; + + // load xml document + hr = XmlLoadDocument(wzDocument, &pixdDocument); + ExitOnFailure(hr, "Failed to load manifest as XML document."); + + hr = ParseFromXml(pixdDocument, pEngineState); + +LExit: + ReleaseObject(pixdDocument); + + return hr; +} + extern "C" HRESULT ManifestLoadXmlFromBuffer( __in_bcount(cbBuffer) BYTE* pbBuffer, __in SIZE_T cbBuffer, @@ -13,14 +38,29 @@ extern "C" HRESULT ManifestLoadXmlFromBuffer( { HRESULT hr = S_OK; IXMLDOMDocument* pixdDocument = NULL; - IXMLDOMElement* pixeBundle = NULL; - IXMLDOMNode* pixnLog = NULL; - IXMLDOMNode* pixnChain = NULL; // load xml document hr = XmlLoadDocumentFromBuffer(pbBuffer, cbBuffer, &pixdDocument); ExitOnFailure(hr, "Failed to load manifest as XML document."); + hr = ParseFromXml(pixdDocument, pEngineState); + +LExit: + ReleaseObject(pixdDocument); + + return hr; +} + +static HRESULT ParseFromXml( + __in IXMLDOMDocument* pixdDocument, + __in BURN_ENGINE_STATE* pEngineState + ) +{ + HRESULT hr = S_OK; + IXMLDOMElement* pixeBundle = NULL; + IXMLDOMNode* pixnLog = NULL; + IXMLDOMNode* pixnChain = NULL; + // get bundle element hr = pixdDocument->get_documentElement(&pixeBundle); ExitOnFailure(hr, "Failed to get bundle element."); @@ -105,7 +145,7 @@ extern "C" HRESULT ManifestLoadXmlFromBuffer( ExitOnFailure(hr, "Failed to parse update."); // parse containers - hr = ContainersParseFromXml(&pEngineState->section, &pEngineState->containers, pixeBundle); + hr = ContainersParseFromXml(&pEngineState->containers, pixeBundle); ExitOnFailure(hr, "Failed to parse containers."); // parse payloads @@ -124,6 +164,5 @@ LExit: ReleaseObject(pixnChain); ReleaseObject(pixnLog); ReleaseObject(pixeBundle); - ReleaseObject(pixdDocument); return hr; } diff --git a/src/engine/manifest.h b/src/engine/manifest.h index 6e535d60..223181d9 100644 --- a/src/engine/manifest.h +++ b/src/engine/manifest.h @@ -11,6 +11,11 @@ extern "C" { // function declarations +HRESULT ManifestLoadXml( + __in LPCWSTR wzDocument, + __in BURN_ENGINE_STATE* pEngineState + ); + HRESULT ManifestLoadXmlFromBuffer( __in_bcount(cbBuffer) BYTE* pbBuffer, __in SIZE_T cbBuffer, diff --git a/src/engine/msiengine.cpp b/src/engine/msiengine.cpp index 066734d0..c20e2ef8 100644 --- a/src/engine/msiengine.cpp +++ b/src/engine/msiengine.cpp @@ -4,10 +4,7 @@ // constants -#define BURNMSIINSTALL_PROPERTY_NAME L"BURNMSIINSTALL" -#define BURNMSIMODIFY_PROPERTY_NAME L"BURNMSIMODIFY" -#define BURNMSIREPAIR_PROPERTY_NAME L"BURNMSIREPAIR" -#define BURNMSIUNINSTALL_PROPERTY_NAME L"BURNMSIUNINSTALL" + // structs diff --git a/src/engine/msiengine.h b/src/engine/msiengine.h index 04c375c2..64bddcf0 100644 --- a/src/engine/msiengine.h +++ b/src/engine/msiengine.h @@ -1,6 +1,12 @@ #pragma once // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. +// constants +#define BURNMSIINSTALL_PROPERTY_NAME L"BURNMSIINSTALL" +#define BURNMSIMODIFY_PROPERTY_NAME L"BURNMSIMODIFY" +#define BURNMSIREPAIR_PROPERTY_NAME L"BURNMSIREPAIR" +#define BURNMSIUNINSTALL_PROPERTY_NAME L"BURNMSIUNINSTALL" + #if defined(__cplusplus) extern "C" { diff --git a/src/engine/plan.cpp b/src/engine/plan.cpp index 3c0e1c50..e2a3437d 100644 --- a/src/engine/plan.cpp +++ b/src/engine/plan.cpp @@ -74,7 +74,9 @@ static BOOL AlreadyPlannedCachePackage( __in_z LPCWSTR wzPackageId, __out HANDLE* phSyncpointEvent ); -static DWORD GetNextCheckpointId(); +static DWORD GetNextCheckpointId( + __in BURN_PLAN* pPlan + ); static HRESULT AppendCacheAction( __in BURN_PLAN* pPlan, __out BURN_CACHE_ACTION** ppCacheAction @@ -1621,7 +1623,7 @@ extern "C" HRESULT PlanExecuteCheckpoint( { HRESULT hr = S_OK; BURN_EXECUTE_ACTION* pAction = NULL; - DWORD dwCheckpointId = GetNextCheckpointId(); + DWORD dwCheckpointId = GetNextCheckpointId(pPlan); // execute checkpoint hr = PlanAppendExecuteAction(pPlan, &pAction); @@ -1808,7 +1810,7 @@ extern "C" HRESULT PlanRollbackBoundaryComplete( DWORD dwCheckpointId = 0; // Add checkpoints. - dwCheckpointId = GetNextCheckpointId(); + dwCheckpointId = GetNextCheckpointId(pPlan); hr = PlanAppendExecuteAction(pPlan, &pExecuteAction); ExitOnFailure(hr, "Failed to append execute action."); @@ -2095,7 +2097,7 @@ static HRESULT AddCachePackageHelper( // 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. - dwCheckpoint = GetNextCheckpointId(); + dwCheckpoint = GetNextCheckpointId(pPlan); hr = AppendCacheAction(pPlan, &pCacheAction); ExitOnFailure(hr, "Failed to append package start action."); @@ -2234,10 +2236,11 @@ static BOOL AlreadyPlannedCachePackage( return fPlanned; } -static DWORD GetNextCheckpointId() +static DWORD GetNextCheckpointId( + __in BURN_PLAN* pPlan + ) { - static DWORD dwCounter = 0; - return ++dwCounter; + return ++pPlan->dwNextCheckpointId; } static HRESULT AppendCacheAction( @@ -3039,11 +3042,11 @@ static void CacheActionLog( break; case BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT: - LogStringLine(REPORT_STANDARD, "%ls action[%u]: SIGNAL_SYNCPOINT event handle: 0x%x, skip until retried: %hs", wzBase, iAction, pAction->syncpoint.hEvent, LoggingBoolToString(pAction->fSkipUntilRetried)); + LogStringLine(REPORT_STANDARD, "%ls action[%u]: SIGNAL_SYNCPOINT event handle: 0x%p, skip until retried: %hs", wzBase, iAction, pAction->syncpoint.hEvent, LoggingBoolToString(pAction->fSkipUntilRetried)); break; case BURN_CACHE_ACTION_TYPE_TRANSACTION_BOUNDARY: - LogStringLine(REPORT_STANDARD, "%ls action[%u]: TRANSACTION_BOUNDARY id: %ls, event handle: 0x%x, vital: %ls, transaction: %ls", wzBase, iAction, pAction->rollbackBoundary.pRollbackBoundary->sczId, pAction->rollbackBoundary.hEvent, pAction->rollbackBoundary.pRollbackBoundary->fVital ? L"yes" : L"no", pAction->rollbackBoundary.pRollbackBoundary->fTransaction ? L"yes" : L"no"); + LogStringLine(REPORT_STANDARD, "%ls action[%u]: TRANSACTION_BOUNDARY id: %ls, event handle: 0x%p, vital: %ls, transaction: %ls", wzBase, iAction, pAction->rollbackBoundary.pRollbackBoundary->sczId, pAction->rollbackBoundary.hEvent, pAction->rollbackBoundary.pRollbackBoundary->fVital ? L"yes" : L"no", pAction->rollbackBoundary.pRollbackBoundary->fTransaction ? L"yes" : L"no"); break; default: @@ -3066,11 +3069,11 @@ static void ExecuteActionLog( break; case BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER: - LogStringLine(REPORT_STANDARD, "%ls action[%u]: PACKAGE_PROVIDER package id: %ls, action: %u", wzBase, iAction, pAction->packageProvider.pPackage->sczId, pAction->packageProvider.action); + LogStringLine(REPORT_STANDARD, "%ls action[%u]: PACKAGE_PROVIDER package id: %ls, action: %hs", wzBase, iAction, pAction->packageProvider.pPackage->sczId, LoggingDependencyActionToString(pAction->packageProvider.action)); break; case BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY: - LogStringLine(REPORT_STANDARD, "%ls action[%u]: PACKAGE_DEPENDENCY package id: %ls, bundle provider key: %ls, action: %u", wzBase, iAction, pAction->packageDependency.pPackage->sczId, pAction->packageDependency.sczBundleProviderKey, pAction->packageDependency.action); + LogStringLine(REPORT_STANDARD, "%ls action[%u]: PACKAGE_DEPENDENCY package id: %ls, bundle provider key: %ls, action: %hs", wzBase, iAction, pAction->packageDependency.pPackage->sczId, pAction->packageDependency.sczBundleProviderKey, LoggingDependencyActionToString(pAction->packageDependency.action)); break; case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: @@ -3078,15 +3081,15 @@ static void ExecuteActionLog( break; case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: - LogStringLine(REPORT_STANDARD, "%ls action[%u]: MSI_PACKAGE package id: %ls, action: %hs, action msi property: %u, ui level: %u, disable externaluihandler: %ls, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->msiPackage.pPackage->sczId, LoggingActionStateToString(pAction->msiPackage.action), pAction->msiPackage.actionMsiProperty, pAction->msiPackage.uiLevel, pAction->msiPackage.fDisableExternalUiHandler ? L"yes" : L"no", pAction->msiPackage.sczLogPath, pAction->msiPackage.dwLoggingAttributes); + LogStringLine(REPORT_STANDARD, "%ls action[%u]: MSI_PACKAGE package id: %ls, action: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %ls, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->msiPackage.pPackage->sczId, LoggingActionStateToString(pAction->msiPackage.action), LoggingBurnMsiPropertyToString(pAction->msiPackage.actionMsiProperty), pAction->msiPackage.uiLevel, pAction->msiPackage.fDisableExternalUiHandler ? L"yes" : L"no", pAction->msiPackage.sczLogPath, pAction->msiPackage.dwLoggingAttributes); for (DWORD j = 0; j < pAction->msiPackage.cPatches; ++j) { - LogStringLine(REPORT_STANDARD, " Patch[%u]: order: %u, msp package id: %ls", j, pAction->msiPackage.rgOrderedPatches->dwOrder, pAction->msiPackage.rgOrderedPatches[j].dwOrder, pAction->msiPackage.rgOrderedPatches[j].pPackage->sczId); + LogStringLine(REPORT_STANDARD, " Patch[%u]: order: %u, msp package id: %ls", j, pAction->msiPackage.rgOrderedPatches[j].dwOrder, pAction->msiPackage.rgOrderedPatches[j].pPackage->sczId); } break; case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET: - LogStringLine(REPORT_STANDARD, "%ls action[%u]: MSP_TARGET package id: %ls, action: %hs, target product code: %ls, target per-machine: %ls, action msi property: %u, ui level: %u, disable externaluihandler: %ls, log path: %ls", wzBase, iAction, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.sczTargetProductCode, pAction->mspTarget.fPerMachineTarget ? L"yes" : L"no", pAction->mspTarget.actionMsiProperty, pAction->mspTarget.uiLevel, pAction->mspTarget.fDisableExternalUiHandler ? L"yes" : L"no", pAction->mspTarget.sczLogPath); + LogStringLine(REPORT_STANDARD, "%ls action[%u]: MSP_TARGET package id: %ls, action: %hs, target product code: %ls, target per-machine: %ls, action msi property: %ls, ui level: %u, disable externaluihandler: %ls, log path: %ls", wzBase, iAction, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.sczTargetProductCode, pAction->mspTarget.fPerMachineTarget ? L"yes" : L"no", LoggingBurnMsiPropertyToString(pAction->mspTarget.actionMsiProperty), pAction->mspTarget.uiLevel, pAction->mspTarget.fDisableExternalUiHandler ? L"yes" : L"no", pAction->mspTarget.sczLogPath); for (DWORD j = 0; j < pAction->mspTarget.cOrderedPatches; ++j) { LogStringLine(REPORT_STANDARD, " Patch[%u]: order: %u, msp package id: %ls", j, pAction->mspTarget.rgOrderedPatches[j].dwOrder, pAction->mspTarget.rgOrderedPatches[j].pPackage->sczId); @@ -3106,7 +3109,7 @@ static void ExecuteActionLog( break; case BURN_EXECUTE_ACTION_TYPE_WAIT_SYNCPOINT: - LogStringLine(REPORT_STANDARD, "%ls action[%u]: WAIT_SYNCPOINT event handle: 0x%x", wzBase, iAction, pAction->syncpoint.hEvent); + LogStringLine(REPORT_STANDARD, "%ls action[%u]: WAIT_SYNCPOINT event handle: 0x%p", wzBase, iAction, pAction->syncpoint.hEvent); break; case BURN_EXECUTE_ACTION_TYPE_UNCACHE_PACKAGE: @@ -3131,6 +3134,7 @@ extern "C" void PlanDump( LogStringLine(REPORT_STANDARD, "Plan action: %hs", LoggingBurnActionToString(pPlan->action)); LogStringLine(REPORT_STANDARD, " per-machine: %hs", LoggingTrueFalseToString(pPlan->fPerMachine)); + LogStringLine(REPORT_STANDARD, " disable-rollback: %hs", LoggingTrueFalseToString(pPlan->fDisableRollback)); LogStringLine(REPORT_STANDARD, " keep registration by default: %hs", LoggingTrueFalseToString(pPlan->fKeepRegistrationDefault)); LogStringLine(REPORT_STANDARD, " estimated size: %llu", pPlan->qwEstimatedSize); diff --git a/src/engine/plan.h b/src/engine/plan.h index 4fd3380e..5fddd72f 100644 --- a/src/engine/plan.h +++ b/src/engine/plan.h @@ -325,6 +325,7 @@ typedef struct _BURN_PLAN DWORD dwRegistrationOperations; BOOL fKeepRegistrationDefault; BOOL fDisallowRemoval; + BOOL fDisableRollback; DWORD64 qwCacheSizeTotal; @@ -366,6 +367,8 @@ typedef struct _BURN_PLAN BURN_CACHE_PAYLOAD_PROGRESS* rgPayloadProgress; DWORD cPayloadProgress; STRINGDICT_HANDLE shPayloadProgress; + + DWORD dwNextCheckpointId; } BURN_PLAN; diff --git a/src/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/test/BurnUnitTest/BurnUnitTest.vcxproj index dde01be1..71f3ea09 100644 --- a/src/test/BurnUnitTest/BurnUnitTest.vcxproj +++ b/src/test/BurnUnitTest/BurnUnitTest.vcxproj @@ -36,6 +36,7 @@ + Create diff --git a/src/test/BurnUnitTest/BurnUnitTest.vcxproj.filters b/src/test/BurnUnitTest/BurnUnitTest.vcxproj.filters index 14261ba0..f9461f53 100644 --- a/src/test/BurnUnitTest/BurnUnitTest.vcxproj.filters +++ b/src/test/BurnUnitTest/BurnUnitTest.vcxproj.filters @@ -30,6 +30,9 @@ Source Files + + Source Files + Source Files diff --git a/src/test/BurnUnitTest/PlanTest.cpp b/src/test/BurnUnitTest/PlanTest.cpp new file mode 100644 index 00000000..86bc646b --- /dev/null +++ b/src/test/BurnUnitTest/PlanTest.cpp @@ -0,0 +1,982 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +static HRESULT WINAPI PlanTestBAProc( + __in BOOTSTRAPPER_APPLICATION_MESSAGE message, + __in const LPVOID pvArgs, + __inout LPVOID pvResults, + __in_opt LPVOID pvContext + ); + +static LPCWSTR wzMsiTransactionManifest = + L"" + L" " + L" " + L" "; + +static LPCWSTR wzSingleMsiManifest = + L"" + L" " + L" " + L" "; + +namespace Microsoft +{ +namespace Tools +{ +namespace WindowsInstallerXml +{ +namespace Test +{ +namespace Bootstrapper +{ + using namespace System; + using namespace Xunit; + + public ref class PlanTest : BurnUnitTest + { + public: + PlanTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture) + { + } + + [Fact] + void MsiTransactionInstallTest() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + InitializeEngineStateForCorePlan(wzMsiTransactionManifest, pEngineState); + DetectPackagesAsAbsent(pEngineState); + DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"1.0.0.0"); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + NativeAssert::Succeeded(hr, "CorePlan failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(TRUE, pPlan->fPerMachine); + Assert::Equal(FALSE, pPlan->fDisableRollback); + Assert::Equal(FALSE, pPlan->fKeepRegistrationDefault); + + BOOL fRollback = FALSE; + DWORD dwIndex = 0; + DWORD dwPackageStart = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + dwPackageStart = ValidateCachePackageStart(pPlan, fRollback, dwIndex++, L"PackageA", 6, 2, 33741, FALSE); + ValidateCacheAcquireContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", FALSE); + ValidateCacheExtractContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", FALSE, dwPackageStart, 6); + ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageA", L"PackageA", TRUE, FALSE, dwPackageStart); + ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageA", L"cab1QmlL013Hqv_44W64R0cvnHn_2c", TRUE, FALSE, dwPackageStart); + ValidateCachePackageStop(pPlan, fRollback, dwIndex++, L"PackageA", FALSE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, FALSE); + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 8); + dwPackageStart = ValidateCachePackageStart(pPlan, fRollback, dwIndex++, L"PackageB", 14, 2, 33753, FALSE); + ValidateCacheAcquireContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", TRUE); + ValidateCacheExtractContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", FALSE, dwPackageStart, 2); + ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageB", L"PackageB", TRUE, FALSE, dwPackageStart); + ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageB", L"cabQH1Sgh7w2K8tLIftUaaWVhMWt0s", TRUE, FALSE, dwPackageStart); + ValidateCachePackageStop(pPlan, fRollback, dwIndex++, L"PackageB", FALSE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, FALSE); + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 14); + dwPackageStart = ValidateCachePackageStart(pPlan, fRollback, dwIndex++, L"PackageC", 22, 2, 33739, FALSE); + ValidateCacheAcquireContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", TRUE); + ValidateCacheExtractContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", FALSE, dwPackageStart, 2); + ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageC", L"PackageC", TRUE, FALSE, dwPackageStart); + ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageC", L"cabRT8kdm93olnEAQB2GSO3u0400VI", TRUE, FALSE, dwPackageStart); + ValidateCachePackageStop(pPlan, fRollback, dwIndex++, L"PackageC", FALSE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, FALSE); + Assert::Equal(24ul, pPlan->cCacheActions); + + fRollback = TRUE; + dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE); + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 8); + ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageB", FALSE); + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 14); + ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageC", FALSE); + Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); + + Assert::Equal(106166ull, pPlan->qwEstimatedSize); + Assert::Equal(101233ull, pPlan->qwCacheSizeTotal); + + fRollback = FALSE; + dwIndex = 0; + DWORD dwExecuteCheckpointId = 2; + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[7].syncpoint.hEvent); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRegistration(pPlan, fRollback, dwIndex++, TRUE); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE); + ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[15].syncpoint.hEvent); + dwExecuteCheckpointId = 9; + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[23].syncpoint.hEvent); + dwExecuteCheckpointId = 15; + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[23].syncpoint.hEvent); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); + Assert::Equal(34ul, pPlan->cExecuteActions); + + fRollback = TRUE; + dwIndex = 0; + dwExecuteCheckpointId = 2; + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteRegistration(pPlan, fRollback, dwIndex++, FALSE); + ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE); + ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageB"); + dwExecuteCheckpointId = 9; + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageC"); + dwExecuteCheckpointId = 15; + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + Assert::Equal(33ul, pPlan->cRollbackActions); + + Assert::Equal(4ul, pPlan->cExecutePackagesTotal); + Assert::Equal(7ul, pPlan->cOverallProgressTicksTotal); + + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cCleanActions); + + UINT uIndex = 0; + ValidatePlannedProvider(pPlan, uIndex++, L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", NULL); + Assert::Equal(uIndex, pPlan->cPlannedProviders); + } + + [Fact] + void MsiTransactionUninstallTest() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + InitializeEngineStateForCorePlan(wzMsiTransactionManifest, pEngineState); + DetectPackagesAsPresentAndCached(pEngineState); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + NativeAssert::Succeeded(hr, "CorePlan failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); + Assert::Equal(TRUE, pPlan->fPerMachine); + Assert::Equal(FALSE, pPlan->fDisableRollback); + Assert::Equal(TRUE, pPlan->fKeepRegistrationDefault); + + BOOL fRollback = FALSE; + DWORD dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cCacheActions); + + fRollback = TRUE; + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); + + Assert::Equal(0ull, pPlan->qwEstimatedSize); + Assert::Equal(0ull, pPlan->qwCacheSizeTotal); + + fRollback = FALSE; + dwIndex = 0; + DWORD dwExecuteCheckpointId = 1; + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteRegistration(pPlan, fRollback, dwIndex++, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + Assert::Equal(dwIndex, pPlan->cExecuteActions); + + fRollback = TRUE; + dwIndex = 0; + dwExecuteCheckpointId = 1; + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRegistration(pPlan, fRollback, dwIndex++, TRUE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + Assert::Equal(dwIndex, pPlan->cRollbackActions); + + Assert::Equal(3ul, pPlan->cExecutePackagesTotal); + Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal); + + dwIndex = 0; + ValidateCleanAction(pPlan, dwIndex++, L"PackageC"); + ValidateCleanAction(pPlan, dwIndex++, L"PackageB"); + ValidateCleanAction(pPlan, dwIndex++, L"PackageA"); + Assert::Equal(dwIndex, pPlan->cCleanActions); + + UINT uIndex = 0; + ValidatePlannedProvider(pPlan, uIndex++, L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", NULL); + ValidatePlannedProvider(pPlan, uIndex++, L"{BE27CF2B-9E5F-4500-BAE3-5E0E522FB962}", NULL); + ValidatePlannedProvider(pPlan, uIndex++, L"{388E4963-13AD-4EE7-B907-AA8888F50E54}", NULL); + ValidatePlannedProvider(pPlan, uIndex++, L"{196E43EA-EF92-4FF8-B9AC-A0FD0D225BB4}", NULL); + Assert::Equal(uIndex, pPlan->cPlannedProviders); + } + + [Fact] + void SingleMsiInstallTest() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + InitializeEngineStateForCorePlan(wzSingleMsiManifest, pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPackagesAsAbsent(pEngineState); + DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0"); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + NativeAssert::Succeeded(hr, "CorePlan failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(TRUE, pPlan->fPerMachine); + Assert::Equal(FALSE, pPlan->fDisableRollback); + Assert::Equal(FALSE, pPlan->fKeepRegistrationDefault); + + BOOL fRollback = FALSE; + DWORD dwIndex = 0; + DWORD dwPackageStart = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + dwPackageStart = ValidateCachePackageStart(pPlan, fRollback, dwIndex++, L"PackageE", 5, 2, 33741, FALSE); + ValidateCacheExtractContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", FALSE, BURN_PLAN_INVALID_ACTION_INDEX, 2); + ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageE", L"PackageE", TRUE, FALSE, dwPackageStart); + ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageE", L"cabkAPka1fWa1PyiVdoVPuoB6Qvs3k", TRUE, FALSE, dwPackageStart); + ValidateCachePackageStop(pPlan, fRollback, dwIndex++, L"PackageE", FALSE); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, FALSE); + Assert::Equal(dwIndex, pPlan->cCacheActions); + + fRollback = TRUE; + dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageE", FALSE); + Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); + + Assert::Equal(35381ull, pPlan->qwEstimatedSize); + Assert::Equal(33741ull, pPlan->qwCacheSizeTotal); + + fRollback = FALSE; + dwIndex = 0; + DWORD dwExecuteCheckpointId = 2; + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[6].syncpoint.hEvent); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageE", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageE", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRegistration(pPlan, fRollback, dwIndex++, TRUE); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageE", L"{4a04385a-0081-44ba-acd1-9e4e95cfc97f}", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[6].syncpoint.hEvent); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); + Assert::Equal(dwIndex, pPlan->cExecuteActions); + + fRollback = TRUE; + dwIndex = 0; + dwExecuteCheckpointId = 2; + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteRegistration(pPlan, fRollback, dwIndex++, FALSE); + ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageE"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageE", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageE", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageE", L"{4a04385a-0081-44ba-acd1-9e4e95cfc97f}", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + Assert::Equal(dwIndex, pPlan->cRollbackActions); + + Assert::Equal(2ul, pPlan->cExecutePackagesTotal); + Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal); + + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cCleanActions); + + UINT uIndex = 0; + ValidatePlannedProvider(pPlan, uIndex++, L"{4a04385a-0081-44ba-acd1-9e4e95cfc97f}", NULL); + Assert::Equal(uIndex, pPlan->cPlannedProviders); + } + + [Fact] + void SingleMsiUninstallTest() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + InitializeEngineStateForCorePlan(wzSingleMsiManifest, pEngineState); + DetectPackagesAsPresentAndCached(pEngineState); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + NativeAssert::Succeeded(hr, "CorePlan failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); + Assert::Equal(TRUE, pPlan->fPerMachine); + Assert::Equal(FALSE, pPlan->fDisableRollback); + Assert::Equal(TRUE, pPlan->fKeepRegistrationDefault); + + BOOL fRollback = FALSE; + DWORD dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cCacheActions); + + fRollback = TRUE; + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); + + Assert::Equal(0ull, pPlan->qwEstimatedSize); + Assert::Equal(0ull, pPlan->qwCacheSizeTotal); + + fRollback = FALSE; + dwIndex = 0; + DWORD dwExecuteCheckpointId = 1; + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageE", L"{4a04385a-0081-44ba-acd1-9e4e95cfc97f}", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageE", BURN_DEPENDENCY_ACTION_UNREGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageE", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteRegistration(pPlan, fRollback, dwIndex++, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + Assert::Equal(dwIndex, pPlan->cExecuteActions); + + fRollback = TRUE; + dwIndex = 0; + dwExecuteCheckpointId = 1; + ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageE", L"{4a04385a-0081-44ba-acd1-9e4e95cfc97f}", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageE", BURN_DEPENDENCY_ACTION_REGISTER); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageE", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRegistration(pPlan, fRollback, dwIndex++, TRUE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + Assert::Equal(dwIndex, pPlan->cRollbackActions); + + Assert::Equal(1ul, pPlan->cExecutePackagesTotal); + Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal); + + dwIndex = 0; + ValidateCleanAction(pPlan, dwIndex++, L"PackageE"); + Assert::Equal(dwIndex, pPlan->cCleanActions); + + UINT uIndex = 0; + ValidatePlannedProvider(pPlan, uIndex++, L"{4a04385a-0081-44ba-acd1-9e4e95cfc97f}", NULL); + ValidatePlannedProvider(pPlan, uIndex++, L"{284F56B6-B6C7-404A-B9B5-78F63BF79494}", NULL); + Assert::Equal(uIndex, pPlan->cPlannedProviders); + } + + private: + // This doesn't initialize everything, just enough for CorePlan to work. + void InitializeEngineStateForCorePlan(LPCWSTR wzManifest, BURN_ENGINE_STATE* pEngineState) + { + HRESULT hr = S_OK; + + ::InitializeCriticalSection(&pEngineState->csActive); + ::InitializeCriticalSection(&pEngineState->userExperience.csEngineActive); + + hr = VariableInitialize(&pEngineState->variables); + NativeAssert::Succeeded(hr, "Failed to initialize variables."); + + hr = ManifestLoadXml(wzManifest, pEngineState); + NativeAssert::Succeeded(hr, "Failed to load manifest."); + + pEngineState->userExperience.pfnBAProc = PlanTestBAProc; + } + + void DetectAttachedContainerAsAttached(BURN_ENGINE_STATE* pEngineState) + { + for (DWORD i = 0; i < pEngineState->containers.cContainers; ++i) + { + BURN_CONTAINER* pContainer = pEngineState->containers.rgContainers + i; + if (pContainer->fAttached) + { + pContainer->fActuallyAttached = TRUE; + } + } + } + + void DetectPackagesAsAbsent(BURN_ENGINE_STATE* pEngineState) + { + DetectReset(&pEngineState->registration, &pEngineState->packages); + PlanReset(&pEngineState->plan, &pEngineState->packages); + + for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i) + { + BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i; + pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; + } + } + + void DetectPackagesAsPresentAndCached(BURN_ENGINE_STATE* pEngineState) + { + DetectReset(&pEngineState->registration, &pEngineState->packages); + PlanReset(&pEngineState->plan, &pEngineState->packages); + + pEngineState->registration.fInstalled = TRUE; + + for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i) + { + BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i; + pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT; + pPackage->cache = BURN_CACHE_STATE_COMPLETE; + + for (DWORD j = 0; j < pPackage->cPayloads; ++j) + { + pPackage->rgPayloads[j].fCached = TRUE; + } + } + } + + HRESULT DetectUpgradeBundle( + __in BURN_ENGINE_STATE* pEngineState, + __in LPCWSTR wzId, + __in LPCWSTR wzVersion + ) + { + HRESULT hr = S_OK; + BURN_RELATED_BUNDLES* pRelatedBundles = &pEngineState->registration.relatedBundles; + BURN_DEPENDENCY_PROVIDER dependencyProvider = { }; + + hr = StrAllocString(&dependencyProvider.sczKey, wzId, 0); + ExitOnFailure(hr, "Failed to copy provider key"); + + dependencyProvider.fImported = TRUE; + + hr = StrAllocString(&dependencyProvider.sczVersion, wzVersion, 0); + ExitOnFailure(hr, "Failed to copy version"); + + hr = MemEnsureArraySize(reinterpret_cast(&pRelatedBundles->rgRelatedBundles), pRelatedBundles->cRelatedBundles + 1, sizeof(BURN_RELATED_BUNDLE), 5); + ExitOnFailure(hr, "Failed to ensure there is space for related bundles."); + + BURN_RELATED_BUNDLE* pRelatedBundle = pRelatedBundles->rgRelatedBundles + pRelatedBundles->cRelatedBundles; + + hr = VerParseVersion(wzVersion, 0, FALSE, &pRelatedBundle->pVersion); + ExitOnFailure(hr, "Failed to parse pseudo bundle version: %ls", wzVersion); + + pRelatedBundle->relationType = BOOTSTRAPPER_RELATION_UPGRADE; + + hr = PseudoBundleInitialize(0, &pRelatedBundle->package, TRUE, wzId, pRelatedBundle->relationType, BOOTSTRAPPER_PACKAGE_STATE_PRESENT, NULL, NULL, NULL, 0, FALSE, L"-quiet", L"-repair -quiet", L"-uninstall -quiet", &dependencyProvider, NULL, 0); + ExitOnFailure(hr, "Failed to initialize related bundle to represent bundle: %ls", wzId); + + ++pRelatedBundles->cRelatedBundles; + + LExit: + return hr; + } + + void ValidateCacheAcquireContainer( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzContainerId, + __in BOOL fSkipUntilRetried + ) + { + BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_CACHE_ACTION_TYPE_ACQUIRE_CONTAINER, pAction->type); + NativeAssert::StringEqual(wzContainerId, pAction->extractContainer.pContainer->sczId); + Assert::Equal(fSkipUntilRetried, pAction->fSkipUntilRetried); + } + + BURN_CACHE_ACTION* ValidateCacheActionExists(BURN_PLAN* pPlan, BOOL fRollback, DWORD dwIndex) + { + Assert::InRange(dwIndex + 1ul, 1ul, (fRollback ? pPlan->cRollbackCacheActions : pPlan->cCacheActions)); + return (fRollback ? pPlan->rgRollbackCacheActions : pPlan->rgCacheActions) + dwIndex; + } + + void ValidateCacheCachePayload( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId, + __in LPCWSTR wzPayloadId, + __in BOOL fMove, + __in BOOL fSkipUntilRetried, + __in DWORD iTryAgainAction + ) + { + BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_CACHE_ACTION_TYPE_CACHE_PAYLOAD, pAction->type); + NativeAssert::StringEqual(wzPackageId, pAction->cachePayload.pPackage->sczId); + NativeAssert::StringEqual(wzPayloadId, pAction->cachePayload.pPayload->sczKey); + Assert::Equal(fMove, pAction->cachePayload.fMove); + Assert::Equal(fSkipUntilRetried, pAction->fSkipUntilRetried); + Assert::Equal(iTryAgainAction, pAction->cachePayload.iTryAgainAction); + } + + void ValidateCacheCheckpoint( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in DWORD dwId + ) + { + BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_CACHE_ACTION_TYPE_CHECKPOINT, pAction->type); + Assert::Equal(dwId, pAction->checkpoint.dwId); + } + + void ValidateCacheExtractContainer( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzContainerId, + __in BOOL fSkipUntilRetried, + __in DWORD iSkipUntilAcquiredByAction, + __in DWORD cPayloads + ) + { + BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_CACHE_ACTION_TYPE_EXTRACT_CONTAINER, pAction->type); + NativeAssert::StringEqual(wzContainerId, pAction->extractContainer.pContainer->sczId); + Assert::Equal(fSkipUntilRetried, pAction->fSkipUntilRetried); + Assert::Equal(iSkipUntilAcquiredByAction, pAction->extractContainer.iSkipUntilAcquiredByAction); + Assert::Equal(cPayloads, pAction->extractContainer.cPayloads); + } + + DWORD ValidateCachePackageStart( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId, + __in DWORD iPackageCompleteAction, + __in DWORD cCachePayloads, + __in DWORD64 qwCachePayloadSizeTotal, + __in BOOL fSkipUntilRetried + ) + { + BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_CACHE_ACTION_TYPE_PACKAGE_START, pAction->type); + NativeAssert::StringEqual(wzPackageId, pAction->packageStart.pPackage->sczId); + Assert::Equal(iPackageCompleteAction, pAction->packageStart.iPackageCompleteAction); + Assert::Equal(cCachePayloads, pAction->packageStart.cCachePayloads); + Assert::Equal(qwCachePayloadSizeTotal, pAction->packageStart.qwCachePayloadSizeTotal); + Assert::Equal(fSkipUntilRetried, pAction->fSkipUntilRetried); + return dwIndex + 1; + } + + void ValidateCachePackageStop( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId, + __in BOOL fSkipUntilRetried + ) + { + BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_CACHE_ACTION_TYPE_PACKAGE_STOP, pAction->type); + NativeAssert::StringEqual(wzPackageId, pAction->packageStop.pPackage->sczId); + Assert::Equal(fSkipUntilRetried, pAction->fSkipUntilRetried); + } + + void ValidateCacheRollbackPackage( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId, + __in BOOL fSkipUntilRetried + ) + { + BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_CACHE_ACTION_TYPE_ROLLBACK_PACKAGE, pAction->type); + NativeAssert::StringEqual(wzPackageId, pAction->rollbackPackage.pPackage->sczId); + Assert::Equal(fSkipUntilRetried, pAction->fSkipUntilRetried); + } + + void ValidateCacheSignalSyncpoint( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in BOOL fSkipUntilRetried + ) + { + 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); + Assert::Equal(fSkipUntilRetried, pAction->fSkipUntilRetried); + } + + void ValidateCleanAction( + __in BURN_PLAN* pPlan, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId + ) + { + Assert::InRange(dwIndex + 1ul, 1ul, pPlan->cCleanActions); + + BURN_CLEAN_ACTION* pCleanAction = pPlan->rgCleanActions + dwIndex; + Assert::NotEqual((DWORD_PTR)0, (DWORD_PTR)pCleanAction->pPackage); + NativeAssert::StringEqual(wzPackageId, pCleanAction->pPackage->sczId); + } + + BURN_EXECUTE_ACTION* ValidateExecuteActionExists(BURN_PLAN* pPlan, BOOL fRollback, DWORD dwIndex) + { + Assert::InRange(dwIndex + 1ul, 1ul, (fRollback ? pPlan->cRollbackActions : pPlan->cExecuteActions)); + return (fRollback ? pPlan->rgRollbackActions : pPlan->rgExecuteActions) + dwIndex; + } + + void ValidateExecuteCheckpoint( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in DWORD dwId + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_CHECKPOINT, pAction->type); + Assert::Equal(dwId, pAction->checkpoint.dwId); + } + + void ValidateExecuteExePackage( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId, + __in BOOTSTRAPPER_ACTION_STATE action, + __in LPCWSTR wzIgnoreDependencies + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE, pAction->type); + NativeAssert::StringEqual(wzPackageId, pAction->exePackage.pPackage->sczId); + Assert::Equal(action, pAction->exePackage.action); + NativeAssert::StringEqual(wzIgnoreDependencies, pAction->exePackage.sczIgnoreDependencies); + } + + void ValidateExecuteMsiPackage( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId, + __in BOOTSTRAPPER_ACTION_STATE action, + __in BURN_MSI_PROPERTY actionMsiProperty, + __in DWORD uiLevel, + __in BOOL fDisableExternalUiHandler, + __in DWORD dwLoggingAttributes + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE, pAction->type); + NativeAssert::StringEqual(wzPackageId, pAction->msiPackage.pPackage->sczId); + Assert::Equal(action, pAction->msiPackage.action); + Assert::Equal(actionMsiProperty, pAction->msiPackage.actionMsiProperty); + Assert::Equal(uiLevel, pAction->msiPackage.uiLevel); + Assert::Equal(fDisableExternalUiHandler, pAction->msiPackage.fDisableExternalUiHandler); + NativeAssert::NotNull(pAction->msiPackage.sczLogPath); + Assert::Equal(dwLoggingAttributes, pAction->msiPackage.dwLoggingAttributes); + } + + void ValidateExecutePackageDependency( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId, + __in LPCWSTR wzBundleProviderKey, + __in BURN_DEPENDENCY_ACTION action + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY, pAction->type); + NativeAssert::StringEqual(wzPackageId, pAction->packageDependency.pPackage->sczId); + NativeAssert::StringEqual(wzBundleProviderKey, pAction->packageDependency.sczBundleProviderKey); + Assert::Equal(action, pAction->packageDependency.action); + } + + void ValidateExecutePackageProvider( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId, + __in BURN_DEPENDENCY_ACTION action + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER, pAction->type); + NativeAssert::StringEqual(wzPackageId, pAction->packageProvider.pPackage->sczId); + Assert::Equal(action, pAction->packageProvider.action); + } + + void ValidateExecuteRegistration( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in BOOL fKeep + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_REGISTRATION, pAction->type); + Assert::Equal(fKeep, pAction->registration.fKeep); + } + + void ValidateExecuteRollbackBoundary( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzId, + __in BOOL fVital, + __in BOOL fTransaction + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY, pAction->type); + NativeAssert::StringEqual(wzId, pAction->rollbackBoundary.pRollbackBoundary->sczId); + Assert::Equal(fVital, pAction->rollbackBoundary.pRollbackBoundary->fVital); + Assert::Equal(fTransaction, pAction->rollbackBoundary.pRollbackBoundary->fTransaction); + } + + void ValidateExecuteUncachePackage( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_UNCACHE_PACKAGE, pAction->type); + NativeAssert::StringEqual(wzPackageId, pAction->uncachePackage.pPackage->sczId); + } + + void ValidateExecuteWaitSyncpoint( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in HANDLE hEvent + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_WAIT_SYNCPOINT, pAction->type); + Assert::Equal((DWORD_PTR)hEvent, (DWORD_PTR)pAction->syncpoint.hEvent); + } + + void ValidatePlannedProvider( + __in BURN_PLAN* pPlan, + __in UINT uIndex, + __in LPCWSTR wzKey, + __in LPCWSTR wzName + ) + { + Assert::InRange(uIndex + 1u, 1u, pPlan->cPlannedProviders); + + DEPENDENCY* pProvider = pPlan->rgPlannedProviders + uIndex; + NativeAssert::StringEqual(wzKey, pProvider->sczKey); + NativeAssert::StringEqual(wzName, pProvider->sczName); + } + }; +} +} +} +} +} + +static HRESULT WINAPI PlanTestBAProc( + __in BOOTSTRAPPER_APPLICATION_MESSAGE /*message*/, + __in const LPVOID /*pvArgs*/, + __inout LPVOID /*pvResults*/, + __in_opt LPVOID /*pvContext*/ + ) +{ + return S_OK; +} diff --git a/src/test/BurnUnitTest/precomp.h b/src/test/BurnUnitTest/precomp.h index fea30156..ddbdf9c6 100644 --- a/src/test/BurnUnitTest/precomp.h +++ b/src/test/BurnUnitTest/precomp.h @@ -69,6 +69,7 @@ #include "manifest.h" #include "splashscreen.h" #include "bitsengine.h" +#include "detect.h" #pragma managed #include -- cgit v1.2.3-55-g6feb