From d8e47230e094a506406a83eb78916abf2668b29c Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 22 Apr 2021 17:12:34 -0700 Subject: Move Integration into test --- src/test/burn/BurnE2ETests.sln | 79 +++ src/test/burn/Directory.Build.props | 29 + src/test/burn/Directory.Build.targets | 50 ++ src/test/burn/README.md | 50 ++ src/test/burn/TestBA/Hresult.cs | 22 + src/test/burn/TestBA/MessagePump.cs | 39 ++ .../burn/TestBA/TestBA.BootstrapperCore.config | 18 + src/test/burn/TestBA/TestBA.cs | 613 +++++++++++++++++ src/test/burn/TestBA/TestBA.csproj | 24 + src/test/burn/TestBA/TestBAFactory.cs | 22 + src/test/burn/TestBA/TestBA_x64.csproj | 24 + .../BundleA/BundleA.wixproj | 17 + .../BasicFunctionalityTests/BundleA/BundleA.wxs | 10 + .../BundleA_x64/BundleA_x64.wixproj | 18 + .../BundleA_x64/BundleA_x64.wxs | 10 + .../BundleB/BundleB.wixproj | 19 + .../BundleB_x64/BundleB_x64.wixproj | 21 + .../BundleC/BundleC.wixproj | 20 + .../BundleC_x64/BundleC_x64.wixproj | 21 + .../PackageA/PackageA.wixproj | 10 + .../PackageA_x64/PackageA_x64.wixproj | 10 + .../TestData/CacheTests/BundleA/BundleA.wixproj | 19 + .../burn/TestData/CacheTests/BundleA/BundleA.wxs | 11 + .../TestData/CacheTests/BundleB/BundleB.wixproj | 19 + .../burn/TestData/CacheTests/BundleB/BundleB.wxs | 11 + .../TestData/CacheTests/BundleC/BundleC.wixproj | 26 + .../burn/TestData/CacheTests/BundleC/BundleC.wxs | 12 + .../TestData/CacheTests/PackageA/PackageA.wixproj | 9 + .../TestData/CacheTests/PackageB/PackageB.wixproj | 9 + .../DependencyTests/BundleAv1/BundleA.props | 11 + .../DependencyTests/BundleAv1/BundleAv1.wixproj | 16 + .../DependencyTests/BundleAv1/BundleAv1.wxs | 21 + .../BundleAv1_0_1/BundleAv1_0_1.wixproj | 16 + .../BundleAv1_0_1/BundleAv1_0_1.wxs | 21 + .../TestData/DependencyTests/BundleB/Bundle.wxs | 40 ++ .../DependencyTests/BundleB/BundleB.wixproj | 18 + .../TestData/DependencyTests/BundleB/BundleB.wxs | 22 + .../DependencyTests/BundleC/BundleC.wixproj | 22 + .../TestData/DependencyTests/BundleC/BundleC.wxs | 12 + .../DependencyTests/BundleD/BundleD.wixproj | 22 + .../TestData/DependencyTests/BundleD/BundleD.wxs | 12 + .../DependencyTests/BundleE/BundleE.wixproj | 21 + .../TestData/DependencyTests/BundleE/BundleE.wxs | 19 + .../DependencyTests/BundleF/BundleF.wixproj | 21 + .../TestData/DependencyTests/BundleF/BundleF.wxs | 12 + .../BundleF_AddOnA/BundleF_AddOn.wxs | 22 + .../BundleF_AddOnA/BundleF_AddOnA.wixproj | 20 + .../BundleF_AddOnB/BundleF_AddOnB.wixproj | 21 + .../BundleF_PatchAv1_0_1/BundleF_PatchA.props | 11 + .../BundleF_PatchAv1_0_1.wixproj | 16 + .../BundleF_PatchAv1_0_1/BundleF_PatchAv1_0_1.wxs | 13 + .../BundleF_PatchAv1_0_2.wixproj | 17 + .../BundleF_PatchAv1_0_2/BundleF_PatchAv1_0_2.wxs | 16 + .../DependencyTests/BundleHv1/BundleH.props | 10 + .../DependencyTests/BundleHv1/BundleHv1.wixproj | 13 + .../DependencyTests/BundleHv1/BundleHv1.wxs | 11 + .../DependencyTests/BundleHv2/BundleHv2.wixproj | 16 + .../DependencyTests/BundleHv2/BundleHv2.wxs | 11 + .../DependencyTests/BundleJ/BundleJ.wixproj | 21 + .../TestData/DependencyTests/BundleJ/BundleJ.wxs | 12 + .../BundleJ_Patch/BundleJ_Patch.wixproj | 21 + .../BundleJ_Patch/BundleJ_Patch.wxs | 16 + .../DependencyTests/BundleKv1/BundleK.props | 10 + .../DependencyTests/BundleKv1/BundleKv1.wixproj | 12 + .../DependencyTests/BundleKv1/BundleKv1.wxs | 10 + .../DependencyTests/BundleKv2/BundleKv2.wixproj | 15 + .../DependencyTests/BundleKv2/BundleKv2.wxs | 10 + .../DependencyTests/BundleL/BundleL.wixproj | 20 + .../TestData/DependencyTests/BundleL/BundleL.wxs | 10 + .../DependencyTests/PackageAv1/PackageA.props | 12 + .../DependencyTests/PackageAv1/PackageAv1.wixproj | 7 + .../PackageAv1/ProductComponents.wxs | 16 + .../PackageAv1_0_1/PackageAv1_0_1.wixproj | 13 + .../PackageAv1_0_2/PackageAv1_0_2.wixproj | 13 + .../DependencyTests/PackageB/PackageB.wixproj | 13 + .../DependencyTests/PackageB/ProductComponents.wxs | 18 + .../DependencyTests/PackageC/PackageC.wixproj | 13 + .../DependencyTests/PackageDv1/Package.wxs | 63 ++ .../DependencyTests/PackageDv1/PackageD.props | 7 + .../DependencyTests/PackageDv1/PackageDv1.wixproj | 7 + .../DependencyTests/PackageDv2/PackageDv2.wixproj | 13 + .../DependencyTests/PackageEv1/PackageE.props | 12 + .../DependencyTests/PackageEv1/PackageEv1.wixproj | 7 + .../PackageEv1/ProductComponents.wxs | 16 + .../PackageEv1_0_1/PackageEv1_0_1.wixproj | 13 + .../DependencyTests/PackageF/PackageF.wixproj | 9 + .../TestData/DependencyTests/PatchA/PatchA.wixproj | 15 + .../TestData/DependencyTests/PatchA/PatchA.wxs | 22 + .../TestData/DependencyTests/PatchB/PatchB.wixproj | 15 + .../TestData/DependencyTests/PatchB/PatchB.wxs | 21 + .../ElevationTests/BundleA/BundleA.wixproj | 18 + .../TestData/ElevationTests/BundleA/BundleA.wxs | 10 + .../ElevationTests/PackageA/PackageA.wixproj | 9 + .../TestData/FailureTests/BundleA/BundleA.wixproj | 19 + .../burn/TestData/FailureTests/BundleA/BundleA.wxs | 11 + .../burn/TestData/FailureTests/BundleB/Bundle.wxs | 26 + .../TestData/FailureTests/BundleB/BundleB.wixproj | 16 + .../TestData/FailureTests/BundleC/BundleC.wixproj | 19 + .../burn/TestData/FailureTests/BundleC/BundleC.wxs | 11 + .../FailureTests/PackageA/PackageA.wixproj | 9 + .../FailureTests/PackageB/PackageB.wixproj | 9 + .../BundleAv1/Bundle.wxs | 40 ++ .../BundleAv1/BundleA.props | 7 + .../BundleAv1/BundleAv1.wixproj | 12 + .../BundleAv1/BundleAv1.wxs | 10 + .../BundleAv2/BundleAv2.wixproj | 18 + .../BundleAv2/BundleAv2.wxs | 10 + .../BundleCv1/Bundle.wxs | 40 ++ .../BundleCv1/BundleC.props | 7 + .../BundleCv1/BundleCv1.wixproj | 12 + .../BundleCv1/BundleCv1.wxs | 10 + .../BundleCv2/BundleCv2.wixproj | 18 + .../BundleCv2/BundleCv2.wxs | 10 + .../PackageAv1/PackageA.props | 9 + .../PackageAv1/PackageAv1.wixproj | 4 + .../PackageAv2/PackageAv2.wixproj | 7 + .../PackageCv1/PackageC.props | 9 + .../PackageCv1/PackageCv1.wixproj | 4 + .../PackageCv2/PackageCv2.wixproj | 7 + .../burn/TestData/LayoutTests/BundleA/Bundle.wxs | 42 ++ .../TestData/LayoutTests/BundleA/BundleA.wixproj | 23 + .../burn/TestData/LayoutTests/BundleA/BundleA.wxs | 26 + .../TestData/LayoutTests/PackageA/PackageA.wixproj | 9 + .../MsiTransactionTests/BundleAv1/BundleA.props | 12 + .../BundleAv1/BundleAv1.wixproj | 12 + .../MsiTransactionTests/BundleAv1/BundleAv1.wxs | 13 + .../BundleAv2/BundleAv2.wixproj | 15 + .../MsiTransactionTests/BundleAv2/BundleAv2.wxs | 13 + .../MsiTransactionTests/BundleBv1/BundleB.props | 13 + .../BundleBv1/BundleBv1.wixproj | 11 + .../MsiTransactionTests/BundleBv1/BundleBv1.wxs | 10 + .../BundleBv2/BundleBv2.wixproj | 18 + .../MsiTransactionTests/BundleBv2/BundleBv2.wxs | 13 + .../MsiTransactionTests/PackageA/PackageA.wixproj | 10 + .../MsiTransactionTests/PackageBv1/PackageB.props | 9 + .../PackageBv1/PackageBv1.wixproj | 7 + .../PackageBv2/PackageBv2.wixproj | 7 + .../MsiTransactionTests/PackageCv1/PackageC.props | 9 + .../PackageCv1/PackageCv1.wixproj | 7 + .../PackageCv2/PackageCv2.wixproj | 7 + .../MsiTransactionTests/PackageD/PackageD.wixproj | 9 + .../MsiTransactionTests/PackageF/PackageF.wixproj | 12 + .../TestData/PatchTests/BundleA/BundleA.wixproj | 19 + .../burn/TestData/PatchTests/BundleA/BundleA.wxs | 9 + .../PatchTests/BundlePatchA/BundlePatchA.wixproj | 19 + .../PatchTests/BundlePatchA/BundlePatchA.wxs | 9 + .../PatchTests/BundlePatchA2/BundlePatchA2.wixproj | 20 + .../PatchTests/BundlePatchA2/BundlePatchA2.wxs | 10 + .../TestData/PatchTests/PackageAv1/PackageA.props | 13 + .../PatchTests/PackageAv1/PackageAv1.wixproj | 4 + .../PatchTests/PackageAv1/ProductComponents.wxs | 15 + .../PackageAv1_0_1/PackageAv1_0_1.wixproj | 10 + .../burn/TestData/PatchTests/PatchA/PatchA.wixproj | 12 + .../burn/TestData/PatchTests/PatchA/PatchA.wxs | 24 + .../TestData/PatchTests/PatchA2/PatchA2.wixproj | 12 + .../burn/TestData/PatchTests/PatchA2/PatchA2.wxs | 23 + .../TestData/PrereqBaTests/BundleA/BundleA.wixproj | 21 + .../TestData/PrereqBaTests/BundleA/BundleA.wxs | 22 + .../PrereqBaTests/BundleA/bad.runtimeconfig.json | 10 + .../TestData/PrereqBaTests/BundleB/BundleB.wixproj | 21 + .../TestData/PrereqBaTests/BundleB/BundleB.wxs | 21 + .../burn/TestData/PrereqBaTests/BundleB/bad.config | 17 + .../PrereqBaTests/PackageA/PackageA.wixproj | 9 + .../PrereqBaTests/PackageB/PackageB.wixproj | 9 + .../PrereqBaTests/PackageF/PackageF.wixproj | 12 + .../RegistrationTests/BundleA/BundleA.wixproj | 18 + .../TestData/RegistrationTests/BundleA/BundleA.wxs | 10 + .../RegistrationTests/PackageA/PackageA.wixproj | 9 + .../RollbackBoundaryTests/BundleA/BundleA.wixproj | 20 + .../RollbackBoundaryTests/BundleA/BundleA.wxs | 15 + .../PackageA/PackageA.wixproj | 9 + .../PackageB/PackageB.wixproj | 9 + .../PackageC/PackageC.wixproj | 9 + .../PackageF/PackageF.wixproj | 12 + .../SlipstreamTests/BundleA/BundleA.wixproj | 19 + .../TestData/SlipstreamTests/BundleA/BundleA.wxs | 12 + .../BundleAReverse/BundleAReverse.wixproj | 19 + .../BundleAReverse/BundleAReverse.wxs | 12 + .../SlipstreamTests/BundleB/BundleB.wixproj | 20 + .../TestData/SlipstreamTests/BundleB/BundleB.wxs | 13 + .../SlipstreamTests/BundleC/BundleC.wixproj | 21 + .../TestData/SlipstreamTests/BundleC/BundleC.wxs | 14 + .../SlipstreamTests/BundleD/BundleD.wixproj | 19 + .../TestData/SlipstreamTests/BundleD/BundleD.wxs | 12 + .../BundleOnlyA/BundleOnlyA.wixproj | 18 + .../SlipstreamTests/BundleOnlyA/BundleOnlyA.wxs | 9 + .../BundleOnlyPatchA/BundleOnlyPatchA.wixproj | 18 + .../BundleOnlyPatchA/BundleOnlyPatchA.wxs | 9 + .../PackageAv0_9_0/PackageAv0_9_0.wixproj | 10 + .../SlipstreamTests/PackageAv1/PackageA.props | 11 + .../SlipstreamTests/PackageAv1/PackageAv1.props | 7 + .../SlipstreamTests/PackageAv1/PackageAv1.wixproj | 4 + .../PackageAv1/ProductComponents.wxs | 15 + .../PackageAv1_0_1/PackageAv1_0_1.wixproj | 10 + .../SlipstreamTests/PackageBv1/PackageB.props | 12 + .../SlipstreamTests/PackageBv1/PackageBv1.wixproj | 4 + .../PackageBv1/ProductComponents.wxs | 15 + .../PackageBv1_0_1/PackageBv1_0_1.wixproj | 10 + .../TestData/SlipstreamTests/PatchA/PatchA.wixproj | 12 + .../TestData/SlipstreamTests/PatchA/PatchA.wxs | 22 + .../SlipstreamTests/PatchAB/PatchAB.wixproj | 14 + .../TestData/SlipstreamTests/PatchAB/PatchAB.wxs | 27 + .../SlipstreamTests/PatchAB2/PatchAB2.wixproj | 14 + .../TestData/SlipstreamTests/PatchAB2/PatchAB2.wxs | 26 + src/test/burn/TestData/Templates/Bundle.wxs | 47 ++ src/test/burn/TestData/Templates/Package.wxs | 62 ++ src/test/burn/TestData/Templates/PackageFail.wxs | 50 ++ .../burn/TestData/Templates/PackagePerUser.wxs | 62 ++ .../burn/TestData/TestBA/TestBAWixlib/TestBA.wxs | 30 + .../burn/TestData/TestBA/TestBAWixlib/TestExe.wxs | 9 + .../TestBA/TestBAWixlib/testbawixlib.wixproj | 19 + .../TestBA/TestBAWixlib_x64/TestBA_x64.wxs | 30 + .../TestBA/TestBAWixlib_x64/TestExe_x64.wxs | 9 + .../TestBAWixlib_x64/testbawixlib_x64.wixproj | 20 + src/test/burn/TestData/TestData.proj | 25 + .../UpdateBundleTests/BundleAv1/BundleA.props | 10 + .../UpdateBundleTests/BundleAv1/BundleAv1.wixproj | 12 + .../UpdateBundleTests/BundleAv1/BundleAv1.wxs | 10 + .../UpdateBundleTests/BundleAv2/BundleAv2.wixproj | 15 + .../UpdateBundleTests/BundleAv2/BundleAv2.wxs | 10 + .../UpdateBundleTests/BundleBv1/Bundle.wxs | 42 ++ .../UpdateBundleTests/BundleBv1/BundleB.props | 7 + .../UpdateBundleTests/BundleBv1/BundleBv1.wixproj | 18 + .../UpdateBundleTests/BundleBv1/BundleBv1.wxs | 10 + .../UpdateBundleTests/BundleBv1/FeedBv1.0.xml | 32 + .../UpdateBundleTests/BundleBv1/FeedBv2.0.xml | 51 ++ .../UpdateBundleTests/BundleBv2/BundleBv2.wixproj | 18 + .../UpdateBundleTests/BundleBv2/BundleBv2.wxs | 10 + .../UpdateBundleTests/PackageAv1/PackageA.props | 9 + .../PackageAv1/PackageAv1.wixproj | 4 + .../PackageAv2/PackageAv2.wixproj | 7 + .../UpdateBundleTests/PackageBv1/PackageB.props | 9 + .../PackageBv1/PackageBv1.wixproj | 4 + .../PackageBv2/PackageBv2.wixproj | 7 + .../BundleAv1/BundleA.props | 10 + .../BundleAv1/BundleAv1.wixproj | 12 + .../BundleAv1/BundleAv1.wxs | 10 + .../BundleAv2/BundleAv2.wixproj | 15 + .../BundleAv2/BundleAv2.wxs | 10 + .../PackageAv1/PackageA.props | 9 + .../PackageAv1/PackageAv1.wixproj | 4 + .../PackageAv2/PackageAv2.wixproj | 7 + src/test/burn/TestExe/NetfxTask.cs | 295 ++++++++ src/test/burn/TestExe/Program.cs | 74 ++ src/test/burn/TestExe/Task.cs | 209 ++++++ src/test/burn/TestExe/TestExe.csproj | 20 + src/test/burn/TestExe/TestExe_x64.csproj | 17 + src/test/burn/TestExe/app.config | 10 + src/test/burn/Wix.Build.props | 11 + src/test/burn/Wix.Build.targets | 17 + src/test/burn/WixTestTools/BundleInstaller.cs | 197 ++++++ src/test/burn/WixTestTools/BundleRegistration.cs | 182 +++++ src/test/burn/WixTestTools/BundleVerifier.cs | 156 +++++ src/test/burn/WixTestTools/LogVerifier.cs | 252 +++++++ src/test/burn/WixTestTools/MSIExec.cs | 753 +++++++++++++++++++++ src/test/burn/WixTestTools/MsiUtilities.cs | 47 ++ src/test/burn/WixTestTools/PackageInstaller.cs | 104 +++ src/test/burn/WixTestTools/PackageVerifier.cs | 81 +++ src/test/burn/WixTestTools/TestTool.cs | 245 +++++++ src/test/burn/WixTestTools/WixTestBase.cs | 19 + src/test/burn/WixTestTools/WixTestContext.cs | 75 ++ src/test/burn/WixTestTools/WixTestTools.csproj | 21 + .../BasicFunctionalityTests.cs | 176 +++++ .../burn/WixToolsetTest.BurnE2E/BurnE2EFixture.cs | 28 + .../burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs | 63 ++ src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs | 133 ++++ .../burn/WixToolsetTest.BurnE2E/DependencyTests.cs | 611 +++++++++++++++++ .../burn/WixToolsetTest.BurnE2E/ElevationTests.cs | 30 + .../burn/WixToolsetTest.BurnE2E/FailureTests.cs | 112 +++ .../ForwardCompatibleBundleTests.cs | 469 +++++++++++++ src/test/burn/WixToolsetTest.BurnE2E/IWebServer.cs | 20 + .../burn/WixToolsetTest.BurnE2E/LayoutTests.cs | 68 ++ .../WixToolsetTest.BurnE2E/MsiTransactionTests.cs | 128 ++++ src/test/burn/WixToolsetTest.BurnE2E/PatchTests.cs | 137 ++++ .../burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs | 76 +++ .../WixToolsetTest.BurnE2E/RegistrationTests.cs | 78 +++ .../RollbackBoundaryTests.cs | 52 ++ .../burn/WixToolsetTest.BurnE2E/SlipstreamTests.cs | 353 ++++++++++ .../WixToolsetTest.BurnE2E/TestBAController.cs | 187 +++++ .../WixToolsetTest.BurnE2E/UpdateBundleTests.cs | 245 +++++++ .../UpgradeRelatedBundleTests.cs | 36 + .../WebServer/CoreOwinWebServer.cs | 70 ++ .../WixToolsetTest.BurnE2E.csproj | 33 + src/test/burn/WixToolsetTest.BurnE2E/runtests.cmd | 2 + src/test/burn/appveyor.cmd | 11 + src/test/burn/appveyor.yml | 27 + src/test/burn/global.json | 8 + src/test/burn/nuget.config | 16 + 288 files changed, 10484 insertions(+) create mode 100644 src/test/burn/BurnE2ETests.sln create mode 100644 src/test/burn/Directory.Build.props create mode 100644 src/test/burn/Directory.Build.targets create mode 100644 src/test/burn/README.md create mode 100644 src/test/burn/TestBA/Hresult.cs create mode 100644 src/test/burn/TestBA/MessagePump.cs create mode 100644 src/test/burn/TestBA/TestBA.BootstrapperCore.config create mode 100644 src/test/burn/TestBA/TestBA.cs create mode 100644 src/test/burn/TestBA/TestBA.csproj create mode 100644 src/test/burn/TestBA/TestBAFactory.cs create mode 100644 src/test/burn/TestBA/TestBA_x64.csproj create mode 100644 src/test/burn/TestData/BasicFunctionalityTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/BasicFunctionalityTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/BasicFunctionalityTests/BundleA_x64/BundleA_x64.wixproj create mode 100644 src/test/burn/TestData/BasicFunctionalityTests/BundleA_x64/BundleA_x64.wxs create mode 100644 src/test/burn/TestData/BasicFunctionalityTests/BundleB/BundleB.wixproj create mode 100644 src/test/burn/TestData/BasicFunctionalityTests/BundleB_x64/BundleB_x64.wixproj create mode 100644 src/test/burn/TestData/BasicFunctionalityTests/BundleC/BundleC.wixproj create mode 100644 src/test/burn/TestData/BasicFunctionalityTests/BundleC_x64/BundleC_x64.wixproj create mode 100644 src/test/burn/TestData/BasicFunctionalityTests/PackageA/PackageA.wixproj create mode 100644 src/test/burn/TestData/BasicFunctionalityTests/PackageA_x64/PackageA_x64.wixproj create mode 100644 src/test/burn/TestData/CacheTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/CacheTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/CacheTests/BundleB/BundleB.wixproj create mode 100644 src/test/burn/TestData/CacheTests/BundleB/BundleB.wxs create mode 100644 src/test/burn/TestData/CacheTests/BundleC/BundleC.wixproj create mode 100644 src/test/burn/TestData/CacheTests/BundleC/BundleC.wxs create mode 100644 src/test/burn/TestData/CacheTests/PackageA/PackageA.wixproj create mode 100644 src/test/burn/TestData/CacheTests/PackageB/PackageB.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleAv1/BundleA.props create mode 100644 src/test/burn/TestData/DependencyTests/BundleAv1/BundleAv1.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleAv1/BundleAv1.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleAv1_0_1/BundleAv1_0_1.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleAv1_0_1/BundleAv1_0_1.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleB/Bundle.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleB/BundleB.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleB/BundleB.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleC/BundleC.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleC/BundleC.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleD/BundleD.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleD/BundleD.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleE/BundleE.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleE/BundleE.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleF/BundleF.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleF/BundleF.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleF_AddOnA/BundleF_AddOn.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleF_AddOnA/BundleF_AddOnA.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleF_AddOnB/BundleF_AddOnB.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchA.props create mode 100644 src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchAv1_0_1.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchAv1_0_1.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_2/BundleF_PatchAv1_0_2.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_2/BundleF_PatchAv1_0_2.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleHv1/BundleH.props create mode 100644 src/test/burn/TestData/DependencyTests/BundleHv1/BundleHv1.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleHv1/BundleHv1.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleHv2/BundleHv2.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleHv2/BundleHv2.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleJ/BundleJ.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleJ/BundleJ.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleJ_Patch/BundleJ_Patch.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleJ_Patch/BundleJ_Patch.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleKv1/BundleK.props create mode 100644 src/test/burn/TestData/DependencyTests/BundleKv1/BundleKv1.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleKv1/BundleKv1.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleKv2/BundleKv2.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleKv2/BundleKv2.wxs create mode 100644 src/test/burn/TestData/DependencyTests/BundleL/BundleL.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/BundleL/BundleL.wxs create mode 100644 src/test/burn/TestData/DependencyTests/PackageAv1/PackageA.props create mode 100644 src/test/burn/TestData/DependencyTests/PackageAv1/PackageAv1.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PackageAv1/ProductComponents.wxs create mode 100644 src/test/burn/TestData/DependencyTests/PackageAv1_0_1/PackageAv1_0_1.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PackageAv1_0_2/PackageAv1_0_2.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PackageB/PackageB.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PackageB/ProductComponents.wxs create mode 100644 src/test/burn/TestData/DependencyTests/PackageC/PackageC.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PackageDv1/Package.wxs create mode 100644 src/test/burn/TestData/DependencyTests/PackageDv1/PackageD.props create mode 100644 src/test/burn/TestData/DependencyTests/PackageDv1/PackageDv1.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PackageDv2/PackageDv2.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PackageEv1/PackageE.props create mode 100644 src/test/burn/TestData/DependencyTests/PackageEv1/PackageEv1.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PackageEv1/ProductComponents.wxs create mode 100644 src/test/burn/TestData/DependencyTests/PackageEv1_0_1/PackageEv1_0_1.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PackageF/PackageF.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PatchA/PatchA.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PatchA/PatchA.wxs create mode 100644 src/test/burn/TestData/DependencyTests/PatchB/PatchB.wixproj create mode 100644 src/test/burn/TestData/DependencyTests/PatchB/PatchB.wxs create mode 100644 src/test/burn/TestData/ElevationTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/ElevationTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/ElevationTests/PackageA/PackageA.wixproj create mode 100644 src/test/burn/TestData/FailureTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/FailureTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/FailureTests/BundleB/Bundle.wxs create mode 100644 src/test/burn/TestData/FailureTests/BundleB/BundleB.wixproj create mode 100644 src/test/burn/TestData/FailureTests/BundleC/BundleC.wixproj create mode 100644 src/test/burn/TestData/FailureTests/BundleC/BundleC.wxs create mode 100644 src/test/burn/TestData/FailureTests/PackageA/PackageA.wixproj create mode 100644 src/test/burn/TestData/FailureTests/PackageB/PackageB.wixproj create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/Bundle.wxs create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleA.props create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleAv1.wixproj create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleAv1.wxs create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv2/BundleAv2.wixproj create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv2/BundleAv2.wxs create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/Bundle.wxs create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleC.props create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleCv1.wixproj create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleCv1.wxs create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv2/BundleCv2.wixproj create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv2/BundleCv2.wxs create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv1/PackageA.props create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv1/PackageAv1.wixproj create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv2/PackageAv2.wixproj create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv1/PackageC.props create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv1/PackageCv1.wixproj create mode 100644 src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv2/PackageCv2.wixproj create mode 100644 src/test/burn/TestData/LayoutTests/BundleA/Bundle.wxs create mode 100644 src/test/burn/TestData/LayoutTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/LayoutTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/LayoutTests/PackageA/PackageA.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleA.props create mode 100644 src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleAv1.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleAv1.wxs create mode 100644 src/test/burn/TestData/MsiTransactionTests/BundleAv2/BundleAv2.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/BundleAv2/BundleAv2.wxs create mode 100644 src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleB.props create mode 100644 src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleBv1.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleBv1.wxs create mode 100644 src/test/burn/TestData/MsiTransactionTests/BundleBv2/BundleBv2.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/BundleBv2/BundleBv2.wxs create mode 100644 src/test/burn/TestData/MsiTransactionTests/PackageA/PackageA.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/PackageBv1/PackageB.props create mode 100644 src/test/burn/TestData/MsiTransactionTests/PackageBv1/PackageBv1.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/PackageBv2/PackageBv2.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/PackageCv1/PackageC.props create mode 100644 src/test/burn/TestData/MsiTransactionTests/PackageCv1/PackageCv1.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/PackageCv2/PackageCv2.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/PackageD/PackageD.wixproj create mode 100644 src/test/burn/TestData/MsiTransactionTests/PackageF/PackageF.wixproj create mode 100644 src/test/burn/TestData/PatchTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/PatchTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/PatchTests/BundlePatchA/BundlePatchA.wixproj create mode 100644 src/test/burn/TestData/PatchTests/BundlePatchA/BundlePatchA.wxs create mode 100644 src/test/burn/TestData/PatchTests/BundlePatchA2/BundlePatchA2.wixproj create mode 100644 src/test/burn/TestData/PatchTests/BundlePatchA2/BundlePatchA2.wxs create mode 100644 src/test/burn/TestData/PatchTests/PackageAv1/PackageA.props create mode 100644 src/test/burn/TestData/PatchTests/PackageAv1/PackageAv1.wixproj create mode 100644 src/test/burn/TestData/PatchTests/PackageAv1/ProductComponents.wxs create mode 100644 src/test/burn/TestData/PatchTests/PackageAv1_0_1/PackageAv1_0_1.wixproj create mode 100644 src/test/burn/TestData/PatchTests/PatchA/PatchA.wixproj create mode 100644 src/test/burn/TestData/PatchTests/PatchA/PatchA.wxs create mode 100644 src/test/burn/TestData/PatchTests/PatchA2/PatchA2.wixproj create mode 100644 src/test/burn/TestData/PatchTests/PatchA2/PatchA2.wxs create mode 100644 src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/PrereqBaTests/BundleA/bad.runtimeconfig.json create mode 100644 src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wixproj create mode 100644 src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wxs create mode 100644 src/test/burn/TestData/PrereqBaTests/BundleB/bad.config create mode 100644 src/test/burn/TestData/PrereqBaTests/PackageA/PackageA.wixproj create mode 100644 src/test/burn/TestData/PrereqBaTests/PackageB/PackageB.wixproj create mode 100644 src/test/burn/TestData/PrereqBaTests/PackageF/PackageF.wixproj create mode 100644 src/test/burn/TestData/RegistrationTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/RegistrationTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/RegistrationTests/PackageA/PackageA.wixproj create mode 100644 src/test/burn/TestData/RollbackBoundaryTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/RollbackBoundaryTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/RollbackBoundaryTests/PackageA/PackageA.wixproj create mode 100644 src/test/burn/TestData/RollbackBoundaryTests/PackageB/PackageB.wixproj create mode 100644 src/test/burn/TestData/RollbackBoundaryTests/PackageC/PackageC.wixproj create mode 100644 src/test/burn/TestData/RollbackBoundaryTests/PackageF/PackageF.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleAReverse/BundleAReverse.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleAReverse/BundleAReverse.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleB/BundleB.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleB/BundleB.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleC/BundleC.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleC/BundleC.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleD/BundleD.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleD/BundleD.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleOnlyA/BundleOnlyA.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleOnlyA/BundleOnlyA.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleOnlyPatchA/BundleOnlyPatchA.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/BundleOnlyPatchA/BundleOnlyPatchA.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/PackageAv0_9_0/PackageAv0_9_0.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageA.props create mode 100644 src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageAv1.props create mode 100644 src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageAv1.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/PackageAv1/ProductComponents.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/PackageAv1_0_1/PackageAv1_0_1.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/PackageBv1/PackageB.props create mode 100644 src/test/burn/TestData/SlipstreamTests/PackageBv1/PackageBv1.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/PackageBv1/ProductComponents.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/PackageBv1_0_1/PackageBv1_0_1.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/PatchA/PatchA.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/PatchA/PatchA.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/PatchAB/PatchAB.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/PatchAB/PatchAB.wxs create mode 100644 src/test/burn/TestData/SlipstreamTests/PatchAB2/PatchAB2.wixproj create mode 100644 src/test/burn/TestData/SlipstreamTests/PatchAB2/PatchAB2.wxs create mode 100644 src/test/burn/TestData/Templates/Bundle.wxs create mode 100644 src/test/burn/TestData/Templates/Package.wxs create mode 100644 src/test/burn/TestData/Templates/PackageFail.wxs create mode 100644 src/test/burn/TestData/Templates/PackagePerUser.wxs create mode 100644 src/test/burn/TestData/TestBA/TestBAWixlib/TestBA.wxs create mode 100644 src/test/burn/TestData/TestBA/TestBAWixlib/TestExe.wxs create mode 100644 src/test/burn/TestData/TestBA/TestBAWixlib/testbawixlib.wixproj create mode 100644 src/test/burn/TestData/TestBA/TestBAWixlib_x64/TestBA_x64.wxs create mode 100644 src/test/burn/TestData/TestBA/TestBAWixlib_x64/TestExe_x64.wxs create mode 100644 src/test/burn/TestData/TestBA/TestBAWixlib_x64/testbawixlib_x64.wixproj create mode 100644 src/test/burn/TestData/TestData.proj create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleA.props create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleAv1.wixproj create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleAv1.wxs create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleAv2/BundleAv2.wixproj create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleAv2/BundleAv2.wxs create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleBv1/Bundle.wxs create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleB.props create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleBv1.wixproj create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleBv1.wxs create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleBv1/FeedBv1.0.xml create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleBv1/FeedBv2.0.xml create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleBv2/BundleBv2.wixproj create mode 100644 src/test/burn/TestData/UpdateBundleTests/BundleBv2/BundleBv2.wxs create mode 100644 src/test/burn/TestData/UpdateBundleTests/PackageAv1/PackageA.props create mode 100644 src/test/burn/TestData/UpdateBundleTests/PackageAv1/PackageAv1.wixproj create mode 100644 src/test/burn/TestData/UpdateBundleTests/PackageAv2/PackageAv2.wixproj create mode 100644 src/test/burn/TestData/UpdateBundleTests/PackageBv1/PackageB.props create mode 100644 src/test/burn/TestData/UpdateBundleTests/PackageBv1/PackageBv1.wixproj create mode 100644 src/test/burn/TestData/UpdateBundleTests/PackageBv2/PackageBv2.wixproj create mode 100644 src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleA.props create mode 100644 src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleAv1.wixproj create mode 100644 src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleAv1.wxs create mode 100644 src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv2/BundleAv2.wixproj create mode 100644 src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv2/BundleAv2.wxs create mode 100644 src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv1/PackageA.props create mode 100644 src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv1/PackageAv1.wixproj create mode 100644 src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv2/PackageAv2.wixproj create mode 100644 src/test/burn/TestExe/NetfxTask.cs create mode 100644 src/test/burn/TestExe/Program.cs create mode 100644 src/test/burn/TestExe/Task.cs create mode 100644 src/test/burn/TestExe/TestExe.csproj create mode 100644 src/test/burn/TestExe/TestExe_x64.csproj create mode 100644 src/test/burn/TestExe/app.config create mode 100644 src/test/burn/Wix.Build.props create mode 100644 src/test/burn/Wix.Build.targets create mode 100644 src/test/burn/WixTestTools/BundleInstaller.cs create mode 100644 src/test/burn/WixTestTools/BundleRegistration.cs create mode 100644 src/test/burn/WixTestTools/BundleVerifier.cs create mode 100644 src/test/burn/WixTestTools/LogVerifier.cs create mode 100644 src/test/burn/WixTestTools/MSIExec.cs create mode 100644 src/test/burn/WixTestTools/MsiUtilities.cs create mode 100644 src/test/burn/WixTestTools/PackageInstaller.cs create mode 100644 src/test/burn/WixTestTools/PackageVerifier.cs create mode 100644 src/test/burn/WixTestTools/TestTool.cs create mode 100644 src/test/burn/WixTestTools/WixTestBase.cs create mode 100644 src/test/burn/WixTestTools/WixTestContext.cs create mode 100644 src/test/burn/WixTestTools/WixTestTools.csproj create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/BasicFunctionalityTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/BurnE2EFixture.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/FailureTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/ForwardCompatibleBundleTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/IWebServer.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/LayoutTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/MsiTransactionTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/PatchTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/RegistrationTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/RollbackBoundaryTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/SlipstreamTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/UpdateBundleTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/UpgradeRelatedBundleTests.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/WebServer/CoreOwinWebServer.cs create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/WixToolsetTest.BurnE2E.csproj create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/runtests.cmd create mode 100644 src/test/burn/appveyor.cmd create mode 100644 src/test/burn/appveyor.yml create mode 100644 src/test/burn/global.json create mode 100644 src/test/burn/nuget.config (limited to 'src/test') diff --git a/src/test/burn/BurnE2ETests.sln b/src/test/burn/BurnE2ETests.sln new file mode 100644 index 00000000..7cdb0cf0 --- /dev/null +++ b/src/test/burn/BurnE2ETests.sln @@ -0,0 +1,79 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29503.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestBA", "src\TestBA\TestBA.csproj", "{04022D35-6D75-49D0-91D2-4208E09DBA6D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestExe", "src\TestExe\TestExe.csproj", "{B038B342-BE42-4951-82A9-7789412CF37F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixTestTools", "src\WixTestTools\WixTestTools.csproj", "{3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.BurnE2E", "src\WixToolsetTest.BurnE2E\WixToolsetTest.BurnE2E.csproj", "{FED9D707-E5C3-4867-87B0-FABDB5EB0823}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Debug|x64.ActiveCfg = Debug|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Debug|x64.Build.0 = Debug|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Debug|x86.ActiveCfg = Debug|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Debug|x86.Build.0 = Debug|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Release|Any CPU.Build.0 = Release|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Release|x64.ActiveCfg = Release|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Release|x64.Build.0 = Release|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Release|x86.ActiveCfg = Release|Any CPU + {04022D35-6D75-49D0-91D2-4208E09DBA6D}.Release|x86.Build.0 = Release|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Debug|x64.ActiveCfg = Debug|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Debug|x64.Build.0 = Debug|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Debug|x86.ActiveCfg = Debug|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Debug|x86.Build.0 = Debug|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Release|Any CPU.Build.0 = Release|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Release|x64.ActiveCfg = Release|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Release|x64.Build.0 = Release|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Release|x86.ActiveCfg = Release|Any CPU + {B038B342-BE42-4951-82A9-7789412CF37F}.Release|x86.Build.0 = Release|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Debug|x64.ActiveCfg = Debug|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Debug|x64.Build.0 = Debug|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Debug|x86.ActiveCfg = Debug|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Debug|x86.Build.0 = Debug|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Release|Any CPU.Build.0 = Release|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Release|x64.ActiveCfg = Release|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Release|x64.Build.0 = Release|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Release|x86.ActiveCfg = Release|Any CPU + {3D3B02F3-79B6-4BD5-AD49-2889DA3849A7}.Release|x86.Build.0 = Release|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|x64.ActiveCfg = Debug|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|x64.Build.0 = Debug|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|x86.ActiveCfg = Debug|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Debug|x86.Build.0 = Debug|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|Any CPU.Build.0 = Release|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|x64.ActiveCfg = Release|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|x64.Build.0 = Release|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|x86.ActiveCfg = Release|Any CPU + {FED9D707-E5C3-4867-87B0-FABDB5EB0823}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {74DE2EED-ECAA-4FDD-9792-9D3B0C0C1321} + EndGlobalSection +EndGlobal diff --git a/src/test/burn/Directory.Build.props b/src/test/burn/Directory.Build.props new file mode 100644 index 00000000..f83cc154 --- /dev/null +++ b/src/test/burn/Directory.Build.props @@ -0,0 +1,29 @@ + + + + + + Debug + false + MSB3246 + + $(MSBuildProjectName) + $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\)) + $(BaseOutputPath)obj\$(ProjectName)\ + $(BaseOutputPath)$(Configuration)\ + + WiX Toolset Team + WiX Toolset + Copyright (c) .NET Foundation and contributors. All rights reserved. + MS-RL + WiX Toolset + + + + + + + diff --git a/src/test/burn/Directory.Build.targets b/src/test/burn/Directory.Build.targets new file mode 100644 index 00000000..265b5cfd --- /dev/null +++ b/src/test/burn/Directory.Build.targets @@ -0,0 +1,50 @@ + + + + + + + true + $(SolutionPath) + $(NCrunchOriginalSolutionPath) + + + + + + + $([System.IO.File]::ReadAllText($(TheSolutionPath))) + $([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) )) + (?<="[PackageName]", ")(.*)(?=", ") + + + + + + %(Identity) + $(SolutionFileContent.Contains('\%(Identity).csproj')) + + + + + $(RegexPattern.Replace('[PackageName]','%(PackageName)') ) + $([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)')) + + + + + + + + + + + + + diff --git a/src/test/burn/README.md b/src/test/burn/README.md new file mode 100644 index 00000000..6c6e0dd9 --- /dev/null +++ b/src/test/burn/README.md @@ -0,0 +1,50 @@ +# integration + +This repo is for building installers, and then executing xunit tests that run them and verify that they worked. + +## Running tests + +The main focus of these tests is to validate behavior in a real environment. +Depending on who you talk to, these are integration or system-level or end-to-end (E2E) tests. +They modify machine state so it's strongly recommended *not* to run these tests on your dev box. +They should be run on a VM instead, where you can easily roll back. + +1. Run appveyor.cmd to build everything (the tests will refuse to run). +1. Copy the build\Release\netcoreapp3.1 folder to your VM. +1. Open a command prompt and navigate to the netcoreapp3.1 folder. +1. Run the runtests.cmd file to run the tests. + +You can modify the runtests.cmd to run specific tests. +For example, the following line runs only the specified test: + +> dotnet test --filter WixToolsetTest.BurnE2E.BasicFunctionalityTests.CanInstallAndUninstallSimpleBundle WixToolsetTest.BurnE2E.dll + +The VM must have: +1. x64 .NET Core SDK of 5.0 or later (for the test runner) +1. Any version of .NET Framework (for the .NET Framework TestBA) +1. x86 .NET Core Desktop Runtime of 5.0 or later (for the .NET Core TestBA) + +## Updating dependencies + +Use the `updatepackage.ps1` script from https://github.com/wixtoolset/Home. +For example: + +* updatepackage.ps1 -TargetFolder path\to\repo -PackageName WixToolset.Bal.wixext -NewVersion 4.0.91 +* updatepackage.ps1 -TargetFolder path\to\repo -PackageName WixToolset.Data -NewVersion 4.0.199 +* updatepackage.ps1 -TargetFolder path\to\repo -PackageName WixToolset.Dependency.wixext -NewVersion 4.0.25 +* updatepackage.ps1 -TargetFolder path\to\repo -PackageName WixToolset.Mba.Core -NewVersion 4.0.52 +* updatepackage.ps1 -TargetFolder path\to\repo -PackageName WixToolset.NetFx.wixext -NewVersion 4.0.67 +* updatepackage.ps1 -TargetFolder path\to\repo -PackageName WixToolset.Util.wixext -NewVersion 4.0.82 +* updatepackage.ps1 -TargetFolder path\to\repo -PackageName WixToolset.Sdk -NewVersion 4.0.0-build-0204 + +## Building with local changes + +The micro repo model makes this very difficult and painful. +The basic idea is to make your changes in each individual repo on the master branch (to get a stable version), commit, and then use appveyor.cmd to build the nuget package. +Put your custom nuget packages into a folder, and modify each repo's nuget.config with an entry to that folder. + +Alternatively, go into the NuGet package cache (%USERPROFILE%\.nuget\packages) and replace the official binaries with your locally built binaries. + +Both of those approaches will poison your NuGet package cache, so you probably will want to run the following command to clear it when you're done: + +> nuget locals all -clear \ No newline at end of file diff --git a/src/test/burn/TestBA/Hresult.cs b/src/test/burn/TestBA/Hresult.cs new file mode 100644 index 00000000..bc1aa8c0 --- /dev/null +++ b/src/test/burn/TestBA/Hresult.cs @@ -0,0 +1,22 @@ +// 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. + +namespace WixToolset.Test.BA +{ + using System; + + /// + /// Utility class to work with HRESULTs + /// + internal class Hresult + { + /// + /// Determines if an HRESULT was a success code or not. + /// + /// HRESULT to verify. + /// True if the status is a success code. + public static bool Succeeded(int status) + { + return status >= 0; + } + } +} diff --git a/src/test/burn/TestBA/MessagePump.cs b/src/test/burn/TestBA/MessagePump.cs new file mode 100644 index 00000000..21a00349 --- /dev/null +++ b/src/test/burn/TestBA/MessagePump.cs @@ -0,0 +1,39 @@ +// 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. + +namespace WixToolset.Test.BA +{ + using System; + using System.Runtime.InteropServices; + using System.Windows.Forms; + + public class MessagePump + { + const uint PM_REMOVE = 1; + + [DllImport("user32.dll", ExactSpelling = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool PeekMessageW(ref Message pMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg); + + [DllImport("user32.dll", ExactSpelling = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool TranslateMessage(ref Message pMsg); + + [DllImport("user32.dll", ExactSpelling = true)] + public static extern IntPtr DispatchMessageW(ref Message pMsg); + + public static void ProcessMessages(int maxMessages) + { + for (int i = 0; i < maxMessages; i++) + { + Message message = new Message(); + if (!PeekMessageW(ref message, IntPtr.Zero, 0, 0, PM_REMOVE)) + { + break; + } + + TranslateMessage(ref message); + DispatchMessageW(ref message); + } + } + } +} diff --git a/src/test/burn/TestBA/TestBA.BootstrapperCore.config b/src/test/burn/TestBA/TestBA.BootstrapperCore.config new file mode 100644 index 00000000..55876a00 --- /dev/null +++ b/src/test/burn/TestBA/TestBA.BootstrapperCore.config @@ -0,0 +1,18 @@ + + + + + + + +
+ + + + + + + + + + diff --git a/src/test/burn/TestBA/TestBA.cs b/src/test/burn/TestBA/TestBA.cs new file mode 100644 index 00000000..09378bc5 --- /dev/null +++ b/src/test/burn/TestBA/TestBA.cs @@ -0,0 +1,613 @@ +// 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. + +namespace WixToolset.Test.BA +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Threading; + using System.Windows.Forms; + using Microsoft.Win32; + using WixToolset.Mba.Core; + + /// + /// A minimal UX used for testing. + /// + public class TestBA : BootstrapperApplication + { + private const string BurnBundleVersionVariable = "WixBundleVersion"; + + private Form dummyWindow; + private IntPtr windowHandle; + private LaunchAction action; + private ManualResetEvent wait; + private int result; + + private string updateBundlePath; + + private bool immediatelyQuit; + private bool quitAfterDetect; + private bool explicitlyElevateAndPlanFromOnElevateBegin; + private int redetectRemaining; + private int sleepDuringCache; + private int cancelCacheAtProgress; + private int sleepDuringExecute; + private int cancelExecuteAtProgress; + private string cancelExecuteActionName; + private int cancelOnProgressAtProgress; + private int retryExecuteFilesInUse; + + private IBootstrapperCommand Command { get; } + + private IEngine Engine => this.engine; + + /// + /// Initializes test user experience. + /// + public TestBA(IEngine engine, IBootstrapperCommand bootstrapperCommand) + : base(engine) + { + this.Command = bootstrapperCommand; + this.wait = new ManualResetEvent(false); + } + + /// + /// Get the version of the install. + /// + public string Version { get; private set; } + + /// + /// Indicates if DetectUpdate found a newer version to update. + /// + private bool UpdateAvailable { get; set; } + + /// + /// UI Thread entry point for TestUX. + /// + protected override void OnStartup(StartupEventArgs args) + { + string immediatelyQuit = this.ReadPackageAction(null, "ImmediatelyQuit"); + if (!String.IsNullOrEmpty(immediatelyQuit) && Boolean.TryParse(immediatelyQuit, out this.immediatelyQuit) && this.immediatelyQuit) + { + this.Engine.Quit(0); + return; + } + + base.OnStartup(args); + + this.action = this.Command.Action; + this.TestVariables(); + + this.Version = this.engine.GetVariableVersion(BurnBundleVersionVariable); + this.Log("Version: {0}", this.Version); + + List verifyArguments = this.ReadVerifyArguments(); + + foreach (string arg in this.Command.CommandLineArgs) + { + // If we're not in the update already, process the updatebundle. + if (this.Command.Relation != RelationType.Update && arg.StartsWith("-updatebundle:", StringComparison.OrdinalIgnoreCase)) + { + this.updateBundlePath = arg.Substring(14); + FileInfo info = new FileInfo(this.updateBundlePath); + this.Engine.SetUpdate(this.updateBundlePath, null, info.Length, UpdateHashType.None, null); + this.UpdateAvailable = true; + this.action = LaunchAction.UpdateReplaceEmbedded; + } + else if (this.Command.Relation != RelationType.Update && arg.StartsWith("-checkupdate", StringComparison.OrdinalIgnoreCase)) + { + this.action = LaunchAction.UpdateReplace; + } + + verifyArguments.Remove(arg); + } + this.Log("Action: {0}", this.action); + + // If there are any verification arguments left, error out. + if (0 < verifyArguments.Count) + { + foreach (string expectedArg in verifyArguments) + { + this.Log("Failure. Expected command-line to have argument: {0}", expectedArg); + } + + this.Engine.Quit(-1); + return; + } + + int redetectCount; + string redetect = this.ReadPackageAction(null, "RedetectCount"); + if (String.IsNullOrEmpty(redetect) || !Int32.TryParse(redetect, out redetectCount)) + { + redetectCount = 0; + } + + string explicitlyElevateAndPlanFromOnElevateBegin = this.ReadPackageAction(null, "ExplicitlyElevateAndPlanFromOnElevateBegin"); + if (String.IsNullOrEmpty(explicitlyElevateAndPlanFromOnElevateBegin) || !Boolean.TryParse(explicitlyElevateAndPlanFromOnElevateBegin, out this.explicitlyElevateAndPlanFromOnElevateBegin)) + { + this.explicitlyElevateAndPlanFromOnElevateBegin = false; + } + + string quitAfterDetect = this.ReadPackageAction(null, "QuitAfterDetect"); + if (String.IsNullOrEmpty(quitAfterDetect) || !Boolean.TryParse(quitAfterDetect, out this.quitAfterDetect)) + { + this.quitAfterDetect = false; + } + + this.wait.WaitOne(); + + this.redetectRemaining = redetectCount; + for (int i = -1; i < redetectCount; i++) + { + this.Engine.Detect(this.windowHandle); + } + } + + protected override void Run() + { + this.dummyWindow = new Form(); + this.windowHandle = this.dummyWindow.Handle; + + this.Log("Running TestBA application"); + this.wait.Set(); + Application.Run(); + } + + private void ShutdownUiThread() + { + if (this.dummyWindow != null) + { + this.dummyWindow.Invoke(new Action(Application.ExitThread)); + this.dummyWindow.Dispose(); + } + + this.Engine.Quit(this.result & 0xFFFF); // return plain old Win32 error, not HRESULT. + } + + protected override void OnDetectUpdateBegin(DetectUpdateBeginEventArgs args) + { + this.Log("OnDetectUpdateBegin"); + if (LaunchAction.UpdateReplaceEmbedded == this.action || LaunchAction.UpdateReplace == this.action) + { + args.Skip = false; + } + } + + protected override void OnDetectUpdate(DetectUpdateEventArgs e) + { + // The list of updates is sorted in descending version, so the first callback should be the largest update available. + // This update should be either larger than ours (so we are out of date), the same as ours (so we are current) + // or smaller than ours (we have a private build). + // Enumerate all of the updates anyway in case something's broken. + this.Log(String.Format("Potential update v{0} from '{1}'; current version: v{2}", e.Version, e.UpdateLocation, this.Version)); + if (!this.UpdateAvailable && this.Engine.CompareVersions(e.Version, this.Version) > 0) + { + this.Log(String.Format("Selected update v{0}", e.Version)); + this.Engine.SetUpdate(null, e.UpdateLocation, e.Size, UpdateHashType.None, null); + this.UpdateAvailable = true; + } + } + + protected override void OnDetectUpdateComplete(DetectUpdateCompleteEventArgs e) + { + this.Log("OnDetectUpdateComplete"); + + // Failed to process an update, allow the existing bundle to still install. + if (!Hresult.Succeeded(e.Status)) + { + this.Log(String.Format("Failed to locate an update, status of 0x{0:X8}, updates disabled.", e.Status)); + e.IgnoreError = true; // But continue on... + } + } + + protected override void OnDetectComplete(DetectCompleteEventArgs args) + { + this.result = args.Status; + + if (Hresult.Succeeded(this.result) && + (this.UpdateAvailable || LaunchAction.UpdateReplaceEmbedded != this.action && LaunchAction.UpdateReplace != this.action)) + { + if (this.redetectRemaining > 0) + { + this.Log("Completed detection phase: {0} re-runs remaining", this.redetectRemaining--); + } + else if (this.quitAfterDetect) + { + this.ShutdownUiThread(); + } + else if (this.explicitlyElevateAndPlanFromOnElevateBegin) + { + this.Engine.Elevate(this.windowHandle); + } + else + { + this.Engine.Plan(this.action); + } + } + else + { + this.ShutdownUiThread(); + } + } + + protected override void OnDetectRelatedBundle(DetectRelatedBundleEventArgs args) + { + this.Log("OnDetectRelatedBundle() - id: {0}, missing from cache: {1}", args.ProductCode, args.MissingFromCache); + } + + protected override void OnElevateBegin(ElevateBeginEventArgs args) + { + if (this.explicitlyElevateAndPlanFromOnElevateBegin) + { + this.Engine.Plan(this.action); + + // Simulate showing some UI since these tests won't actually show the UAC prompt. + MessagePump.ProcessMessages(10); + } + } + + protected override void OnPlanPackageBegin(PlanPackageBeginEventArgs args) + { + RequestState state; + string action = this.ReadPackageAction(args.PackageId, "Requested"); + if (TryParseEnum(action, out state)) + { + args.State = state; + } + } + + protected override void OnPlanPatchTarget(PlanPatchTargetEventArgs args) + { + RequestState state; + string action = this.ReadPackageAction(args.PackageId, "Requested"); + if (TryParseEnum(action, out state)) + { + args.State = state; + } + } + + protected override void OnPlanMsiFeature(PlanMsiFeatureEventArgs args) + { + FeatureState state; + string action = this.ReadFeatureAction(args.PackageId, args.FeatureId, "Requested"); + if (TryParseEnum(action, out state)) + { + args.State = state; + } + } + + protected override void OnPlanComplete(PlanCompleteEventArgs args) + { + this.result = args.Status; + if (Hresult.Succeeded(this.result)) + { + this.Engine.Apply(this.windowHandle); + } + else + { + this.ShutdownUiThread(); + } + } + + protected override void OnCachePackageBegin(CachePackageBeginEventArgs args) + { + this.Log("OnCachePackageBegin() - package: {0}, payloads to cache: {1}", args.PackageId, args.CachePayloads); + + string slowProgress = this.ReadPackageAction(args.PackageId, "SlowCache"); + if (String.IsNullOrEmpty(slowProgress) || !Int32.TryParse(slowProgress, out this.sleepDuringCache)) + { + this.sleepDuringCache = 0; + } + else + { + this.Log(" SlowCache: {0}", this.sleepDuringCache); + } + + string cancelCache = this.ReadPackageAction(args.PackageId, "CancelCacheAtProgress"); + if (String.IsNullOrEmpty(cancelCache) || !Int32.TryParse(cancelCache, out this.cancelCacheAtProgress)) + { + this.cancelCacheAtProgress = -1; + } + else + { + this.Log(" CancelCacheAtProgress: {0}", this.cancelCacheAtProgress); + } + } + + 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); + + if (this.cancelCacheAtProgress >= 0 && this.cancelCacheAtProgress <= args.Progress) + { + args.Cancel = true; + this.Log("OnCacheAcquireProgress(cancel)"); + } + else if (this.sleepDuringCache > 0) + { + this.Log("OnCacheAcquireProgress(sleep {0})", this.sleepDuringCache); + Thread.Sleep(this.sleepDuringCache); + } + } + + protected override void OnCacheContainerOrPayloadVerifyProgress(CacheContainerOrPayloadVerifyProgressEventArgs args) + { + this.Log("OnCacheContainerOrPayloadVerifyProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage); + } + + protected override void OnCachePayloadExtractProgress(CachePayloadExtractProgressEventArgs args) + { + this.Log("OnCachePayloadExtractProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage); + } + + protected override void OnCacheVerifyProgress(CacheVerifyProgressEventArgs args) + { + this.Log("OnCacheVerifyProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%, step: {5}", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage, args.Step); + } + + protected override void OnExecutePackageBegin(ExecutePackageBeginEventArgs args) + { + this.Log("OnExecutePackageBegin() - package: {0}, rollback: {1}", args.PackageId, !args.ShouldExecute); + + string slowProgress = this.ReadPackageAction(args.PackageId, "SlowExecute"); + if (String.IsNullOrEmpty(slowProgress) || !Int32.TryParse(slowProgress, out this.sleepDuringExecute)) + { + this.sleepDuringExecute = 0; + } + else + { + this.Log(" SlowExecute: {0}", this.sleepDuringExecute); + } + + string cancelExecute = this.ReadPackageAction(args.PackageId, "CancelExecuteAtProgress"); + if (String.IsNullOrEmpty(cancelExecute) || !Int32.TryParse(cancelExecute, out this.cancelExecuteAtProgress)) + { + this.cancelExecuteAtProgress = -1; + } + else + { + this.Log(" CancelExecuteAtProgress: {0}", this.cancelExecuteAtProgress); + } + + this.cancelExecuteActionName = this.ReadPackageAction(args.PackageId, "CancelExecuteAtActionStart"); + if (!String.IsNullOrEmpty(this.cancelExecuteActionName)) + { + this.Log(" CancelExecuteAtActionState: {0}", this.cancelExecuteActionName); + } + + string cancelOnProgressAtProgress = this.ReadPackageAction(args.PackageId, "CancelOnProgressAtProgress"); + if (String.IsNullOrEmpty(cancelOnProgressAtProgress) || !Int32.TryParse(cancelOnProgressAtProgress, out this.cancelOnProgressAtProgress)) + { + this.cancelOnProgressAtProgress = -1; + } + else + { + this.Log(" CancelOnProgressAtProgress: {0}", this.cancelOnProgressAtProgress); + } + + string retryBeforeCancel = this.ReadPackageAction(args.PackageId, "RetryExecuteFilesInUse"); + if (String.IsNullOrEmpty(retryBeforeCancel) || !Int32.TryParse(retryBeforeCancel, out this.retryExecuteFilesInUse)) + { + this.retryExecuteFilesInUse = 0; + } + else + { + this.Log(" RetryExecuteFilesInUse: {0}", this.retryExecuteFilesInUse); + } + } + + protected override void OnExecuteFilesInUse(ExecuteFilesInUseEventArgs args) + { + this.Log("OnExecuteFilesInUse() - package: {0}, retries remaining: {1}, data: {2}", args.PackageId, this.retryExecuteFilesInUse, String.Join(", ", args.Files.ToArray())); + + if (this.retryExecuteFilesInUse > 0) + { + --this.retryExecuteFilesInUse; + args.Result = Result.Retry; + } + else + { + args.Result = Result.Abort; + } + } + + protected override void OnExecuteMsiMessage(ExecuteMsiMessageEventArgs args) + { + this.Log("OnExecuteMsiMessage() - MessageType: {0}, Message: {1}, Data: '{2}'", args.MessageType, args.Message, String.Join("','", args.Data.ToArray())); + + if (!String.IsNullOrEmpty(this.cancelExecuteActionName) && args.MessageType == InstallMessage.ActionStart && + args.Data.Count > 0 && args.Data[0] == this.cancelExecuteActionName) + { + this.Log("OnExecuteMsiMessage(cancelNextProgress)"); + this.cancelExecuteAtProgress = 0; + } + } + + protected override void OnExecuteProgress(ExecuteProgressEventArgs args) + { + this.Log("OnExecuteProgress() - package: {0}, progress: {1}%, overall progress: {2}%", args.PackageId, args.ProgressPercentage, args.OverallPercentage); + + if (this.cancelExecuteAtProgress >= 0 && this.cancelExecuteAtProgress <= args.ProgressPercentage) + { + args.Cancel = true; + this.Log("OnExecuteProgress(cancel)"); + } + else if (this.sleepDuringExecute > 0) + { + this.Log("OnExecuteProgress(sleep {0})", this.sleepDuringExecute); + Thread.Sleep(this.sleepDuringExecute); + } + } + + protected override void OnExecutePatchTarget(ExecutePatchTargetEventArgs args) + { + this.Log("OnExecutePatchTarget - Patch Package: {0}, Target Product Code: {1}", args.PackageId, args.TargetProductCode); + } + + protected override void OnProgress(ProgressEventArgs args) + { + this.Log("OnProgress() - progress: {0}%, overall progress: {1}%", args.ProgressPercentage, args.OverallPercentage); + if (this.Command.Display == Display.Embedded) + { + this.Engine.SendEmbeddedProgress(args.ProgressPercentage, args.OverallPercentage); + } + + if (this.cancelOnProgressAtProgress >= 0 && this.cancelOnProgressAtProgress <= args.OverallPercentage) + { + args.Cancel = true; + this.Log("OnProgress(cancel)"); + } + } + + protected override void OnApplyBegin(ApplyBeginEventArgs args) + { + this.cancelOnProgressAtProgress = -1; + this.cancelExecuteAtProgress = -1; + this.cancelCacheAtProgress = -1; + } + + protected override void OnApplyComplete(ApplyCompleteEventArgs args) + { + // Output what the privileges are now. + this.Log("After elevation: WixBundleElevated = {0}", this.Engine.GetVariableNumeric("WixBundleElevated")); + + this.result = args.Status; + this.ShutdownUiThread(); + } + + protected override void OnSystemShutdown(SystemShutdownEventArgs args) + { + // Always prevent shutdown. + this.Log("Disallowed system request to shut down the bootstrapper application."); + args.Cancel = true; + + this.ShutdownUiThread(); + } + + private void TestVariables() + { + // First make sure we can check and get standard variables of each type. + { + string value = null; + if (this.Engine.ContainsVariable("WindowsFolder")) + { + value = this.Engine.GetVariableString("WindowsFolder"); + this.Engine.Log(LogLevel.Verbose, "TEST: Successfully retrieved a string variable: WindowsFolder"); + } + else + { + throw new Exception("Engine did not define a standard variable: WindowsFolder"); + } + } + + { + long value = 0; + if (this.Engine.ContainsVariable("NTProductType")) + { + value = this.Engine.GetVariableNumeric("NTProductType"); + this.Engine.Log(LogLevel.Verbose, "TEST: Successfully retrieved a numeric variable: NTProductType"); + } + else + { + throw new Exception("Engine did not define a standard variable: NTProductType"); + } + } + + { + string value = null; + if (this.Engine.ContainsVariable("VersionMsi")) + { + value = this.Engine.GetVariableVersion("VersionMsi"); + this.Engine.Log(LogLevel.Verbose, "TEST: Successfully retrieved a version variable: VersionMsi"); + } + else + { + throw new Exception("Engine did not define a standard variable: VersionMsi"); + } + } + + // Now validate that Contians returns false for non-existant variables of each type. + if (this.Engine.ContainsVariable("TestStringVariableShouldNotExist")) + { + throw new Exception("Engine defined a variable that should not exist: TestStringVariableShouldNotExist"); + } + else + { + this.Engine.Log(LogLevel.Verbose, "TEST: Successfully checked for non-existent string variable: TestStringVariableShouldNotExist"); + } + + if (this.Engine.ContainsVariable("TestNumericVariableShouldNotExist")) + { + throw new Exception("Engine defined a variable that should not exist: TestNumericVariableShouldNotExist"); + } + else + { + this.Engine.Log(LogLevel.Verbose, "TEST: Successfully checked for non-existent numeric variable: TestNumericVariableShouldNotExist"); + } + + if (this.Engine.ContainsVariable("TestVersionVariableShouldNotExist")) + { + throw new Exception("Engine defined a variable that should not exist: TestVersionVariableShouldNotExist"); + } + else + { + this.Engine.Log(LogLevel.Verbose, "TEST: Successfully checked for non-existent version variable: TestVersionVariableShouldNotExist"); + } + + // Output what the initially run privileges were. + this.Engine.Log(LogLevel.Verbose, String.Format("TEST: WixBundleElevated = {0}", this.Engine.GetVariableNumeric("WixBundleElevated"))); + } + + private void Log(string format, params object[] args) + { + string relation = this.Command.Relation != RelationType.None ? String.Concat(" (", this.Command.Relation.ToString().ToLowerInvariant(), ")") : String.Empty; + string message = String.Format(format, args); + + this.Engine.Log(LogLevel.Standard, String.Concat("TESTBA", relation, ": ", message)); + } + + private List ReadVerifyArguments() + { + string testName = this.Engine.GetVariableString("TestGroupName"); + using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}", testName))) + { + string verifyArguments = testKey == null ? null : testKey.GetValue("VerifyArguments") as string; + return verifyArguments == null ? new List() : new List(verifyArguments.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)); + } + } + + private string ReadPackageAction(string packageId, string state) + { + string testName = this.Engine.GetVariableString("TestGroupName"); + using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}\{1}", testName, String.IsNullOrEmpty(packageId) ? String.Empty : packageId))) + { + return testKey == null ? null : testKey.GetValue(state) as string; + } + } + + private string ReadFeatureAction(string packageId, string featureId, string state) + { + string testName = this.Engine.GetVariableString("TestGroupName"); + using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}\{1}", testName, packageId))) + { + string registryName = String.Concat(featureId, state); + return testKey == null ? null : testKey.GetValue(registryName) as string; + } + } + + private static bool TryParseEnum(string value, out T t) + { + try + { + t = (T)Enum.Parse(typeof(T), value, true); + return true; + } + catch (ArgumentException) { } + catch (OverflowException) { } + + t = default(T); + return false; + } + } +} diff --git a/src/test/burn/TestBA/TestBA.csproj b/src/test/burn/TestBA/TestBA.csproj new file mode 100644 index 00000000..74df28dc --- /dev/null +++ b/src/test/burn/TestBA/TestBA.csproj @@ -0,0 +1,24 @@ + + + + + + net35;net5.0-windows + TestBA + WixToolset.Test.BA + embedded + win-x86 + true + true + Major + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestBA/TestBAFactory.cs b/src/test/burn/TestBA/TestBAFactory.cs new file mode 100644 index 00000000..ba1de367 --- /dev/null +++ b/src/test/burn/TestBA/TestBAFactory.cs @@ -0,0 +1,22 @@ +// 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. + +[assembly: WixToolset.Mba.Core.BootstrapperApplicationFactory(typeof(WixToolset.Test.BA.TestBAFactory))] +namespace WixToolset.Test.BA +{ + using WixToolset.Mba.Core; + + public class TestBAFactory : BaseBootstrapperApplicationFactory + { + private static int loadCount = 0; + + protected override IBootstrapperApplication Create(IEngine engine, IBootstrapperCommand bootstrapperCommand) + { + if (loadCount > 0) + { + engine.Log(LogLevel.Standard, $"Reloaded {loadCount} time(s)"); + } + ++loadCount; + return new TestBA(engine, bootstrapperCommand); + } + } +} diff --git a/src/test/burn/TestBA/TestBA_x64.csproj b/src/test/burn/TestBA/TestBA_x64.csproj new file mode 100644 index 00000000..1368e0f0 --- /dev/null +++ b/src/test/burn/TestBA/TestBA_x64.csproj @@ -0,0 +1,24 @@ + + + + + + net35;net5.0-windows + TestBA + WixToolset.Test.BA + embedded + win-x64 + true + true + Major + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/BasicFunctionalityTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/BasicFunctionalityTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..591272b3 --- /dev/null +++ b/src/test/burn/TestData/BasicFunctionalityTests/BundleA/BundleA.wixproj @@ -0,0 +1,17 @@ + + + + Bundle + hyperlinkLicense + {8C7E2C47-1EE7-4BBE-99A2-EAB7F3693F48} + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/BasicFunctionalityTests/BundleA/BundleA.wxs b/src/test/burn/TestData/BasicFunctionalityTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..bd164a29 --- /dev/null +++ b/src/test/burn/TestData/BasicFunctionalityTests/BundleA/BundleA.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/BasicFunctionalityTests/BundleA_x64/BundleA_x64.wixproj b/src/test/burn/TestData/BasicFunctionalityTests/BundleA_x64/BundleA_x64.wixproj new file mode 100644 index 00000000..3f405ce5 --- /dev/null +++ b/src/test/burn/TestData/BasicFunctionalityTests/BundleA_x64/BundleA_x64.wixproj @@ -0,0 +1,18 @@ + + + + Bundle + x64 + hyperlinkLicense + {6E86B95A-24F6-4C89-AF2E-470C0C734FCB} + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/BasicFunctionalityTests/BundleA_x64/BundleA_x64.wxs b/src/test/burn/TestData/BasicFunctionalityTests/BundleA_x64/BundleA_x64.wxs new file mode 100644 index 00000000..d34e51b6 --- /dev/null +++ b/src/test/burn/TestData/BasicFunctionalityTests/BundleA_x64/BundleA_x64.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/BasicFunctionalityTests/BundleB/BundleB.wixproj b/src/test/burn/TestData/BasicFunctionalityTests/BundleB/BundleB.wixproj new file mode 100644 index 00000000..8ea9afe0 --- /dev/null +++ b/src/test/burn/TestData/BasicFunctionalityTests/BundleB/BundleB.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + {02258734-E25E-4A2C-AFC5-55C34F1994CB} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/BasicFunctionalityTests/BundleB_x64/BundleB_x64.wixproj b/src/test/burn/TestData/BasicFunctionalityTests/BundleB_x64/BundleB_x64.wixproj new file mode 100644 index 00000000..1b1a5006 --- /dev/null +++ b/src/test/burn/TestData/BasicFunctionalityTests/BundleB_x64/BundleB_x64.wixproj @@ -0,0 +1,21 @@ + + + + Bundle + TestBA_x64 + {79F45B7A-D990-46E4-819B-078D87C3321A} + x64 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/BasicFunctionalityTests/BundleC/BundleC.wixproj b/src/test/burn/TestData/BasicFunctionalityTests/BundleC/BundleC.wixproj new file mode 100644 index 00000000..104a6003 --- /dev/null +++ b/src/test/burn/TestData/BasicFunctionalityTests/BundleC/BundleC.wixproj @@ -0,0 +1,20 @@ + + + + Bundle + TestBAdnc + {DD790BAA-FE9F-4B0D-8AF4-DE4E1D674637} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/BasicFunctionalityTests/BundleC_x64/BundleC_x64.wixproj b/src/test/burn/TestData/BasicFunctionalityTests/BundleC_x64/BundleC_x64.wixproj new file mode 100644 index 00000000..3b9d7360 --- /dev/null +++ b/src/test/burn/TestData/BasicFunctionalityTests/BundleC_x64/BundleC_x64.wixproj @@ -0,0 +1,21 @@ + + + + Bundle + TestBAdnc_x64 + {638D31D0-92BA-4BCD-82F0-7F549820D9AB} + x64 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/BasicFunctionalityTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/BasicFunctionalityTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..9943717c --- /dev/null +++ b/src/test/burn/TestData/BasicFunctionalityTests/PackageA/PackageA.wixproj @@ -0,0 +1,10 @@ + + + + a + {7FD50F1B-D134-4365-923C-DFA160F74738} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/BasicFunctionalityTests/PackageA_x64/PackageA_x64.wixproj b/src/test/burn/TestData/BasicFunctionalityTests/PackageA_x64/PackageA_x64.wixproj new file mode 100644 index 00000000..8dbab284 --- /dev/null +++ b/src/test/burn/TestData/BasicFunctionalityTests/PackageA_x64/PackageA_x64.wixproj @@ -0,0 +1,10 @@ + + + + a_x64 + {BDB9EF6A-B2DE-4929-9BE3-0CD71BDAEF6E} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/CacheTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/CacheTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..360bcf86 --- /dev/null +++ b/src/test/burn/TestData/CacheTests/BundleA/BundleA.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + {C48D0F58-0F8F-461D-A60D-D83E5F35BA8E} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/CacheTests/BundleA/BundleA.wxs b/src/test/burn/TestData/CacheTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..20262187 --- /dev/null +++ b/src/test/burn/TestData/CacheTests/BundleA/BundleA.wxs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/test/burn/TestData/CacheTests/BundleB/BundleB.wixproj b/src/test/burn/TestData/CacheTests/BundleB/BundleB.wixproj new file mode 100644 index 00000000..698b1d62 --- /dev/null +++ b/src/test/burn/TestData/CacheTests/BundleB/BundleB.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + {3CC71AD2-39F3-4803-A24C-6E6A492B721C} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/CacheTests/BundleB/BundleB.wxs b/src/test/burn/TestData/CacheTests/BundleB/BundleB.wxs new file mode 100644 index 00000000..95e714ec --- /dev/null +++ b/src/test/burn/TestData/CacheTests/BundleB/BundleB.wxs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/test/burn/TestData/CacheTests/BundleC/BundleC.wixproj b/src/test/burn/TestData/CacheTests/BundleC/BundleC.wixproj new file mode 100644 index 00000000..0acc29c4 --- /dev/null +++ b/src/test/burn/TestData/CacheTests/BundleC/BundleC.wixproj @@ -0,0 +1,26 @@ + + + + Bundle + {997BDF9A-2540-42DB-8F86-296BA243194B} + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/CacheTests/BundleC/BundleC.wxs b/src/test/burn/TestData/CacheTests/BundleC/BundleC.wxs new file mode 100644 index 00000000..ca21cc6e --- /dev/null +++ b/src/test/burn/TestData/CacheTests/BundleC/BundleC.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/burn/TestData/CacheTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/CacheTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..dd8176ed --- /dev/null +++ b/src/test/burn/TestData/CacheTests/PackageA/PackageA.wixproj @@ -0,0 +1,9 @@ + + + + {5D0BD93A-D1D8-4F59-8417-1390B18A6611} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/CacheTests/PackageB/PackageB.wixproj b/src/test/burn/TestData/CacheTests/PackageB/PackageB.wixproj new file mode 100644 index 00000000..efc57bb6 --- /dev/null +++ b/src/test/burn/TestData/CacheTests/PackageB/PackageB.wixproj @@ -0,0 +1,9 @@ + + + + {ADCE5902-224D-4C87-BA31-2D154B37EE22} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleAv1/BundleA.props b/src/test/burn/TestData/DependencyTests/BundleAv1/BundleA.props new file mode 100644 index 00000000..256501c7 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleAv1/BundleA.props @@ -0,0 +1,11 @@ + + + + Bundle + BundleA + {6950EF3F-674E-4689-A5C8-80D12AB6E34F} + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleAv1/BundleAv1.wixproj b/src/test/burn/TestData/DependencyTests/BundleAv1/BundleAv1.wixproj new file mode 100644 index 00000000..3f7882cf --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleAv1/BundleAv1.wixproj @@ -0,0 +1,16 @@ + + + + + 1.0.0.0 + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleAv1/BundleAv1.wxs b/src/test/burn/TestData/DependencyTests/BundleAv1/BundleAv1.wxs new file mode 100644 index 00000000..9218e823 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleAv1/BundleAv1.wxs @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleAv1_0_1/BundleAv1_0_1.wixproj b/src/test/burn/TestData/DependencyTests/BundleAv1_0_1/BundleAv1_0_1.wixproj new file mode 100644 index 00000000..e71ef750 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleAv1_0_1/BundleAv1_0_1.wixproj @@ -0,0 +1,16 @@ + + + + + 1.0.1.0 + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleAv1_0_1/BundleAv1_0_1.wxs b/src/test/burn/TestData/DependencyTests/BundleAv1_0_1/BundleAv1_0_1.wxs new file mode 100644 index 00000000..1590574f --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleAv1_0_1/BundleAv1_0_1.wxs @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleB/Bundle.wxs b/src/test/burn/TestData/DependencyTests/BundleB/Bundle.wxs new file mode 100644 index 00000000..8d2dce60 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleB/Bundle.wxs @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleB/BundleB.wixproj b/src/test/burn/TestData/DependencyTests/BundleB/BundleB.wixproj new file mode 100644 index 00000000..58a613d6 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleB/BundleB.wixproj @@ -0,0 +1,18 @@ + + + + Bundle + {228859BB-F917-4F43-A1E0-50C8DCCA92EF} + 1.0.0.0 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleB/BundleB.wxs b/src/test/burn/TestData/DependencyTests/BundleB/BundleB.wxs new file mode 100644 index 00000000..026100fa --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleB/BundleB.wxs @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleC/BundleC.wixproj b/src/test/burn/TestData/DependencyTests/BundleC/BundleC.wixproj new file mode 100644 index 00000000..ffa7e897 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleC/BundleC.wixproj @@ -0,0 +1,22 @@ + + + + Bundle + + {6950EF3F-674E-4689-A5C8-80D12AB6E34F} + 1.0.1.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleC/BundleC.wxs b/src/test/burn/TestData/DependencyTests/BundleC/BundleC.wxs new file mode 100644 index 00000000..2ce8ed44 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleC/BundleC.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleD/BundleD.wixproj b/src/test/burn/TestData/DependencyTests/BundleD/BundleD.wixproj new file mode 100644 index 00000000..6de1c0c1 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleD/BundleD.wixproj @@ -0,0 +1,22 @@ + + + + Bundle + + {6950EF3F-674E-4689-A5C8-80D12AB6E34F} + 1.0.1.0 + 1153 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleD/BundleD.wxs b/src/test/burn/TestData/DependencyTests/BundleD/BundleD.wxs new file mode 100644 index 00000000..8ee40558 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleD/BundleD.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleE/BundleE.wixproj b/src/test/burn/TestData/DependencyTests/BundleE/BundleE.wixproj new file mode 100644 index 00000000..cd4e89ca --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleE/BundleE.wixproj @@ -0,0 +1,21 @@ + + + + Bundle + {250B4261-E67F-47E0-AB15-209EF58B769D} + 1.0.0.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleE/BundleE.wxs b/src/test/burn/TestData/DependencyTests/BundleE/BundleE.wxs new file mode 100644 index 00000000..204e66ab --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleE/BundleE.wxs @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleF/BundleF.wixproj b/src/test/burn/TestData/DependencyTests/BundleF/BundleF.wixproj new file mode 100644 index 00000000..33154672 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleF/BundleF.wixproj @@ -0,0 +1,21 @@ + + + + Bundle + {EC2B2B3F-E57C-45A4-A0E8-762156DAD99D} + 1.0.0.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleF/BundleF.wxs b/src/test/burn/TestData/DependencyTests/BundleF/BundleF.wxs new file mode 100644 index 00000000..1347836a --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleF/BundleF.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleF_AddOnA/BundleF_AddOn.wxs b/src/test/burn/TestData/DependencyTests/BundleF_AddOnA/BundleF_AddOn.wxs new file mode 100644 index 00000000..c8ca4a3f --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleF_AddOnA/BundleF_AddOn.wxs @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleF_AddOnA/BundleF_AddOnA.wixproj b/src/test/burn/TestData/DependencyTests/BundleF_AddOnA/BundleF_AddOnA.wixproj new file mode 100644 index 00000000..a0708443 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleF_AddOnA/BundleF_AddOnA.wixproj @@ -0,0 +1,20 @@ + + + + Bundle + {022D0F5D-D140-47E1-A19A-5B2CEEE52668} + 1.0.0.0 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleF_AddOnB/BundleF_AddOnB.wixproj b/src/test/burn/TestData/DependencyTests/BundleF_AddOnB/BundleF_AddOnB.wixproj new file mode 100644 index 00000000..3c09fd2c --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleF_AddOnB/BundleF_AddOnB.wixproj @@ -0,0 +1,21 @@ + + + + Bundle + {8AB16F34-CA65-46E1-BDC0-08F157B4781C} + 1.0.0.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchA.props b/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchA.props new file mode 100644 index 00000000..cbc025ef --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchA.props @@ -0,0 +1,11 @@ + + + + Bundle + BundleF_PatchA + {90F41437-BEF8-4ED8-8902-C5DED74E4F6C} + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchAv1_0_1.wixproj b/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchAv1_0_1.wixproj new file mode 100644 index 00000000..c7d907a2 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchAv1_0_1.wixproj @@ -0,0 +1,16 @@ + + + + + 1.0.1.0 + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchAv1_0_1.wxs b/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchAv1_0_1.wxs new file mode 100644 index 00000000..8ef8a351 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_1/BundleF_PatchAv1_0_1.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_2/BundleF_PatchAv1_0_2.wixproj b/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_2/BundleF_PatchAv1_0_2.wixproj new file mode 100644 index 00000000..949309dc --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_2/BundleF_PatchAv1_0_2.wixproj @@ -0,0 +1,17 @@ + + + + + 1.0.2.0 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_2/BundleF_PatchAv1_0_2.wxs b/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_2/BundleF_PatchAv1_0_2.wxs new file mode 100644 index 00000000..2b47d5ed --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleF_PatchAv1_0_2/BundleF_PatchAv1_0_2.wxs @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleHv1/BundleH.props b/src/test/burn/TestData/DependencyTests/BundleHv1/BundleH.props new file mode 100644 index 00000000..14801ec3 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleHv1/BundleH.props @@ -0,0 +1,10 @@ + + + + Bundle + {C5EA6B61-EF32-48E0-A6F9-08EB6D096843} + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleHv1/BundleHv1.wixproj b/src/test/burn/TestData/DependencyTests/BundleHv1/BundleHv1.wixproj new file mode 100644 index 00000000..6ff25fcb --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleHv1/BundleHv1.wixproj @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleHv1/BundleHv1.wxs b/src/test/burn/TestData/DependencyTests/BundleHv1/BundleHv1.wxs new file mode 100644 index 00000000..b553d829 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleHv1/BundleHv1.wxs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleHv2/BundleHv2.wixproj b/src/test/burn/TestData/DependencyTests/BundleHv2/BundleHv2.wixproj new file mode 100644 index 00000000..794e72bc --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleHv2/BundleHv2.wixproj @@ -0,0 +1,16 @@ + + + + + 2.0.0.0 + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleHv2/BundleHv2.wxs b/src/test/burn/TestData/DependencyTests/BundleHv2/BundleHv2.wxs new file mode 100644 index 00000000..690f8e7a --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleHv2/BundleHv2.wxs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleJ/BundleJ.wixproj b/src/test/burn/TestData/DependencyTests/BundleJ/BundleJ.wixproj new file mode 100644 index 00000000..85fd0f92 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleJ/BundleJ.wixproj @@ -0,0 +1,21 @@ + + + + Bundle + {37BDF884-C24A-4C12-9D0C-421FC30747F2} + 1.0.0.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleJ/BundleJ.wxs b/src/test/burn/TestData/DependencyTests/BundleJ/BundleJ.wxs new file mode 100644 index 00000000..422b4b22 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleJ/BundleJ.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleJ_Patch/BundleJ_Patch.wixproj b/src/test/burn/TestData/DependencyTests/BundleJ_Patch/BundleJ_Patch.wixproj new file mode 100644 index 00000000..212ef3d6 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleJ_Patch/BundleJ_Patch.wixproj @@ -0,0 +1,21 @@ + + + + Bundle + {353B5A34-3B46-424E-8817-25B3D01C8C16} + 1.0.1.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleJ_Patch/BundleJ_Patch.wxs b/src/test/burn/TestData/DependencyTests/BundleJ_Patch/BundleJ_Patch.wxs new file mode 100644 index 00000000..ddd4d8db --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleJ_Patch/BundleJ_Patch.wxs @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleKv1/BundleK.props b/src/test/burn/TestData/DependencyTests/BundleKv1/BundleK.props new file mode 100644 index 00000000..15257eb3 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleKv1/BundleK.props @@ -0,0 +1,10 @@ + + + + Bundle + {F7B7CCD8-ACFE-45D8-9EC2-934BBC3BE597} + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleKv1/BundleKv1.wixproj b/src/test/burn/TestData/DependencyTests/BundleKv1/BundleKv1.wixproj new file mode 100644 index 00000000..e7abd24a --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleKv1/BundleKv1.wixproj @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleKv1/BundleKv1.wxs b/src/test/burn/TestData/DependencyTests/BundleKv1/BundleKv1.wxs new file mode 100644 index 00000000..c4a85814 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleKv1/BundleKv1.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleKv2/BundleKv2.wixproj b/src/test/burn/TestData/DependencyTests/BundleKv2/BundleKv2.wixproj new file mode 100644 index 00000000..e9e7478e --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleKv2/BundleKv2.wixproj @@ -0,0 +1,15 @@ + + + + + 2.0.0.0 + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleKv2/BundleKv2.wxs b/src/test/burn/TestData/DependencyTests/BundleKv2/BundleKv2.wxs new file mode 100644 index 00000000..c4a85814 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleKv2/BundleKv2.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/BundleL/BundleL.wixproj b/src/test/burn/TestData/DependencyTests/BundleL/BundleL.wixproj new file mode 100644 index 00000000..c5727cf6 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleL/BundleL.wixproj @@ -0,0 +1,20 @@ + + + + Bundle + {2EDB07DC-DCCD-419F-AD25-52ABF36B53AE} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/BundleL/BundleL.wxs b/src/test/burn/TestData/DependencyTests/BundleL/BundleL.wxs new file mode 100644 index 00000000..d3789e63 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/BundleL/BundleL.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/PackageAv1/PackageA.props b/src/test/burn/TestData/DependencyTests/PackageAv1/PackageA.props new file mode 100644 index 00000000..8cbe9aa9 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageAv1/PackageA.props @@ -0,0 +1,12 @@ + + + + PackageA + true + {6F171EC9-0774-4974-A8D1-493EF53CAB74} + {45E933B7-B56A-44D5-8EEC-625EC199085E} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageAv1/PackageAv1.wixproj b/src/test/burn/TestData/DependencyTests/PackageAv1/PackageAv1.wixproj new file mode 100644 index 00000000..1cac7394 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageAv1/PackageAv1.wixproj @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageAv1/ProductComponents.wxs b/src/test/burn/TestData/DependencyTests/PackageAv1/ProductComponents.wxs new file mode 100644 index 00000000..eca7f6b4 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageAv1/ProductComponents.wxs @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/PackageAv1_0_1/PackageAv1_0_1.wixproj b/src/test/burn/TestData/DependencyTests/PackageAv1_0_1/PackageAv1_0_1.wixproj new file mode 100644 index 00000000..d395391e --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageAv1_0_1/PackageAv1_0_1.wixproj @@ -0,0 +1,13 @@ + + + + + 1.0.1.0 + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageAv1_0_2/PackageAv1_0_2.wixproj b/src/test/burn/TestData/DependencyTests/PackageAv1_0_2/PackageAv1_0_2.wixproj new file mode 100644 index 00000000..e7a497f4 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageAv1_0_2/PackageAv1_0_2.wixproj @@ -0,0 +1,13 @@ + + + + + 1.0.2.0 + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageB/PackageB.wixproj b/src/test/burn/TestData/DependencyTests/PackageB/PackageB.wixproj new file mode 100644 index 00000000..a82822f8 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageB/PackageB.wixproj @@ -0,0 +1,13 @@ + + + + true + {E26243B0-F1A2-4E74-A82D-25B306908E78} + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageB/ProductComponents.wxs b/src/test/burn/TestData/DependencyTests/PackageB/ProductComponents.wxs new file mode 100644 index 00000000..b59e53e1 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageB/ProductComponents.wxs @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/PackageC/PackageC.wixproj b/src/test/burn/TestData/DependencyTests/PackageC/PackageC.wixproj new file mode 100644 index 00000000..ef61d053 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageC/PackageC.wixproj @@ -0,0 +1,13 @@ + + + + {F21201D4-4782-4658-99C9-2E75D51FCFA6} + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageDv1/Package.wxs b/src/test/burn/TestData/DependencyTests/PackageDv1/Package.wxs new file mode 100644 index 00000000..e3089c7c --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageDv1/Package.wxs @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/PackageDv1/PackageD.props b/src/test/burn/TestData/DependencyTests/PackageDv1/PackageD.props new file mode 100644 index 00000000..999de0de --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageDv1/PackageD.props @@ -0,0 +1,7 @@ + + + + PackageD + {AD82A938-2F54-45B8-A637-B14D8405A959} + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageDv1/PackageDv1.wixproj b/src/test/burn/TestData/DependencyTests/PackageDv1/PackageDv1.wixproj new file mode 100644 index 00000000..3d9cf384 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageDv1/PackageDv1.wixproj @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageDv2/PackageDv2.wixproj b/src/test/burn/TestData/DependencyTests/PackageDv2/PackageDv2.wixproj new file mode 100644 index 00000000..2bb6e8bd --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageDv2/PackageDv2.wixproj @@ -0,0 +1,13 @@ + + + + + 2.0.0.0 + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageEv1/PackageE.props b/src/test/burn/TestData/DependencyTests/PackageEv1/PackageE.props new file mode 100644 index 00000000..96f07b8c --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageEv1/PackageE.props @@ -0,0 +1,12 @@ + + + + PackageE + true + {70FA13C7-0338-483F-A256-E5C83750BDE5} + {212A5698-457E-440F-88CC-98FC49A17378} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageEv1/PackageEv1.wixproj b/src/test/burn/TestData/DependencyTests/PackageEv1/PackageEv1.wixproj new file mode 100644 index 00000000..091b7b24 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageEv1/PackageEv1.wixproj @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageEv1/ProductComponents.wxs b/src/test/burn/TestData/DependencyTests/PackageEv1/ProductComponents.wxs new file mode 100644 index 00000000..d388d2a3 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageEv1/ProductComponents.wxs @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/PackageEv1_0_1/PackageEv1_0_1.wixproj b/src/test/burn/TestData/DependencyTests/PackageEv1_0_1/PackageEv1_0_1.wixproj new file mode 100644 index 00000000..1fb93130 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageEv1_0_1/PackageEv1_0_1.wixproj @@ -0,0 +1,13 @@ + + + + + 1.0.1.0 + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PackageF/PackageF.wixproj b/src/test/burn/TestData/DependencyTests/PackageF/PackageF.wixproj new file mode 100644 index 00000000..25b610ac --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PackageF/PackageF.wixproj @@ -0,0 +1,9 @@ + + + + {069AECC6-84DC-4FA4-B506-CD3A9A76F2F4} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PatchA/PatchA.wixproj b/src/test/burn/TestData/DependencyTests/PatchA/PatchA.wixproj new file mode 100644 index 00000000..b6653a19 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PatchA/PatchA.wixproj @@ -0,0 +1,15 @@ + + + + PatchCreation + .msp + 1079 + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PatchA/PatchA.wxs b/src/test/burn/TestData/DependencyTests/PatchA/PatchA.wxs new file mode 100644 index 00000000..acb6f887 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PatchA/PatchA.wxs @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/DependencyTests/PatchB/PatchB.wixproj b/src/test/burn/TestData/DependencyTests/PatchB/PatchB.wixproj new file mode 100644 index 00000000..cf28a9c9 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PatchB/PatchB.wixproj @@ -0,0 +1,15 @@ + + + + PatchCreation + .msp + 1079 + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/DependencyTests/PatchB/PatchB.wxs b/src/test/burn/TestData/DependencyTests/PatchB/PatchB.wxs new file mode 100644 index 00000000..a906dbc8 --- /dev/null +++ b/src/test/burn/TestData/DependencyTests/PatchB/PatchB.wxs @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/ElevationTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/ElevationTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..a1650507 --- /dev/null +++ b/src/test/burn/TestData/ElevationTests/BundleA/BundleA.wixproj @@ -0,0 +1,18 @@ + + + + Bundle + {5DDF6D9F-FF04-40E8-919C-8DD1DCE4B592} + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ElevationTests/BundleA/BundleA.wxs b/src/test/burn/TestData/ElevationTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..bd164a29 --- /dev/null +++ b/src/test/burn/TestData/ElevationTests/BundleA/BundleA.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/ElevationTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/ElevationTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..87f99513 --- /dev/null +++ b/src/test/burn/TestData/ElevationTests/PackageA/PackageA.wixproj @@ -0,0 +1,9 @@ + + + + {D803BB11-5B94-42EA-8289-7A17E55699A3} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/FailureTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/FailureTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..321f139c --- /dev/null +++ b/src/test/burn/TestData/FailureTests/BundleA/BundleA.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + {FE5197EB-E324-411E-B3AC-760E566E1000} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/FailureTests/BundleA/BundleA.wxs b/src/test/burn/TestData/FailureTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..95e714ec --- /dev/null +++ b/src/test/burn/TestData/FailureTests/BundleA/BundleA.wxs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/test/burn/TestData/FailureTests/BundleB/Bundle.wxs b/src/test/burn/TestData/FailureTests/BundleB/Bundle.wxs new file mode 100644 index 00000000..ea3d029e --- /dev/null +++ b/src/test/burn/TestData/FailureTests/BundleB/Bundle.wxs @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/FailureTests/BundleB/BundleB.wixproj b/src/test/burn/TestData/FailureTests/BundleB/BundleB.wixproj new file mode 100644 index 00000000..1a5d5837 --- /dev/null +++ b/src/test/burn/TestData/FailureTests/BundleB/BundleB.wixproj @@ -0,0 +1,16 @@ + + + + Bundle + {C60B9483-CE87-4FDA-AE5A-B39A52E956E8} + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/FailureTests/BundleC/BundleC.wixproj b/src/test/burn/TestData/FailureTests/BundleC/BundleC.wixproj new file mode 100644 index 00000000..60bd5ef7 --- /dev/null +++ b/src/test/burn/TestData/FailureTests/BundleC/BundleC.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + {9E9964D0-2120-4358-8136-D4A8727E0C59} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/FailureTests/BundleC/BundleC.wxs b/src/test/burn/TestData/FailureTests/BundleC/BundleC.wxs new file mode 100644 index 00000000..48c4ab72 --- /dev/null +++ b/src/test/burn/TestData/FailureTests/BundleC/BundleC.wxs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/test/burn/TestData/FailureTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/FailureTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..3b0e74e2 --- /dev/null +++ b/src/test/burn/TestData/FailureTests/PackageA/PackageA.wixproj @@ -0,0 +1,9 @@ + + + + {82FB39B2-56FA-4631-AA03-8B8D3215E6AE} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/FailureTests/PackageB/PackageB.wixproj b/src/test/burn/TestData/FailureTests/PackageB/PackageB.wixproj new file mode 100644 index 00000000..96f7a031 --- /dev/null +++ b/src/test/burn/TestData/FailureTests/PackageB/PackageB.wixproj @@ -0,0 +1,9 @@ + + + + {94160B95-81DD-4DAB-AE2D-246A9E3A108E} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/Bundle.wxs b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/Bundle.wxs new file mode 100644 index 00000000..175d9a1f --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/Bundle.wxs @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleA.props b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleA.props new file mode 100644 index 00000000..329ea107 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleA.props @@ -0,0 +1,7 @@ + + + + Bundle + {5ACFAE02-DDF0-4F1C-BEAD-1E0998E5CF9B} + + diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleAv1.wixproj b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleAv1.wixproj new file mode 100644 index 00000000..d968e8ab --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleAv1.wixproj @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleAv1.wxs b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleAv1.wxs new file mode 100644 index 00000000..7bf16212 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv1/BundleAv1.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv2/BundleAv2.wixproj b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv2/BundleAv2.wixproj new file mode 100644 index 00000000..a50dbb87 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv2/BundleAv2.wixproj @@ -0,0 +1,18 @@ + + + + + 2.0.0.0 + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv2/BundleAv2.wxs b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv2/BundleAv2.wxs new file mode 100644 index 00000000..5cbee5a8 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleAv2/BundleAv2.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/Bundle.wxs b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/Bundle.wxs new file mode 100644 index 00000000..dd305e42 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/Bundle.wxs @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleC.props b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleC.props new file mode 100644 index 00000000..73a9bb63 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleC.props @@ -0,0 +1,7 @@ + + + + Bundle + {D387D602-533C-495D-B14E-AA9D46AF314B} + + diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleCv1.wixproj b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleCv1.wixproj new file mode 100644 index 00000000..5b025236 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleCv1.wixproj @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleCv1.wxs b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleCv1.wxs new file mode 100644 index 00000000..43e75910 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv1/BundleCv1.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv2/BundleCv2.wixproj b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv2/BundleCv2.wixproj new file mode 100644 index 00000000..e0512e06 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv2/BundleCv2.wixproj @@ -0,0 +1,18 @@ + + + + + 2.0.0.0 + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv2/BundleCv2.wxs b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv2/BundleCv2.wxs new file mode 100644 index 00000000..53115c96 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/BundleCv2/BundleCv2.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv1/PackageA.props b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv1/PackageA.props new file mode 100644 index 00000000..de83c1f5 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv1/PackageA.props @@ -0,0 +1,9 @@ + + + + {F764127F-8893-4483-A136-F53660C32423} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv1/PackageAv1.wixproj b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv1/PackageAv1.wixproj new file mode 100644 index 00000000..45d3b2c8 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv1/PackageAv1.wixproj @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv2/PackageAv2.wixproj b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv2/PackageAv2.wixproj new file mode 100644 index 00000000..b419f663 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageAv2/PackageAv2.wixproj @@ -0,0 +1,7 @@ + + + + + 2.0.0.0 + + \ No newline at end of file diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv1/PackageC.props b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv1/PackageC.props new file mode 100644 index 00000000..91d3bdda --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv1/PackageC.props @@ -0,0 +1,9 @@ + + + + {DF1C1C42-F5B9-4167-914B-1AF97E829C48} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv1/PackageCv1.wixproj b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv1/PackageCv1.wixproj new file mode 100644 index 00000000..45615706 --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv1/PackageCv1.wixproj @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv2/PackageCv2.wixproj b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv2/PackageCv2.wixproj new file mode 100644 index 00000000..640ad21d --- /dev/null +++ b/src/test/burn/TestData/ForwardCompatibleBundleTests/PackageCv2/PackageCv2.wixproj @@ -0,0 +1,7 @@ + + + + + 2.0.0.0 + + \ No newline at end of file diff --git a/src/test/burn/TestData/LayoutTests/BundleA/Bundle.wxs b/src/test/burn/TestData/LayoutTests/BundleA/Bundle.wxs new file mode 100644 index 00000000..e74b8394 --- /dev/null +++ b/src/test/burn/TestData/LayoutTests/BundleA/Bundle.wxs @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/LayoutTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/LayoutTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..4cf9c875 --- /dev/null +++ b/src/test/burn/TestData/LayoutTests/BundleA/BundleA.wixproj @@ -0,0 +1,23 @@ + + + + Bundle + {D255FA2D-2B4A-4D78-AE90-C09FECD8491E} + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/LayoutTests/BundleA/BundleA.wxs b/src/test/burn/TestData/LayoutTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..ea46c5b2 --- /dev/null +++ b/src/test/burn/TestData/LayoutTests/BundleA/BundleA.wxs @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/LayoutTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/LayoutTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..be425985 --- /dev/null +++ b/src/test/burn/TestData/LayoutTests/PackageA/PackageA.wixproj @@ -0,0 +1,9 @@ + + + + {CA12F025-6F6F-4E3C-A1D7-FE8CD45A77F5} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleA.props b/src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleA.props new file mode 100644 index 00000000..f831fb29 --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleA.props @@ -0,0 +1,12 @@ + + + + Bundle + 1151 + hyperlinkLicense + {90ED10D5-B187-4470-B498-05D80DAB729A} + + + + + diff --git a/src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleAv1.wixproj b/src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleAv1.wixproj new file mode 100644 index 00000000..cb9f4b89 --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleAv1.wixproj @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleAv1.wxs b/src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleAv1.wxs new file mode 100644 index 00000000..544fe6a6 --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/BundleAv1/BundleAv1.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/MsiTransactionTests/BundleAv2/BundleAv2.wixproj b/src/test/burn/TestData/MsiTransactionTests/BundleAv2/BundleAv2.wixproj new file mode 100644 index 00000000..8272c6bd --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/BundleAv2/BundleAv2.wixproj @@ -0,0 +1,15 @@ + + + + + 2.0.0.0 + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/BundleAv2/BundleAv2.wxs b/src/test/burn/TestData/MsiTransactionTests/BundleAv2/BundleAv2.wxs new file mode 100644 index 00000000..8623537b --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/BundleAv2/BundleAv2.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleB.props b/src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleB.props new file mode 100644 index 00000000..87b402e4 --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleB.props @@ -0,0 +1,13 @@ + + + + Bundle + {552FD011-4DD6-42B2-A4C6-AD1417C829B2} + + + + + + + + diff --git a/src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleBv1.wixproj b/src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleBv1.wixproj new file mode 100644 index 00000000..1a56957b --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleBv1.wixproj @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleBv1.wxs b/src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleBv1.wxs new file mode 100644 index 00000000..00d927ec --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/BundleBv1/BundleBv1.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/MsiTransactionTests/BundleBv2/BundleBv2.wixproj b/src/test/burn/TestData/MsiTransactionTests/BundleBv2/BundleBv2.wixproj new file mode 100644 index 00000000..e1cb68db --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/BundleBv2/BundleBv2.wixproj @@ -0,0 +1,18 @@ + + + + + 1151 + TestBAdnc + 2.0.0.0 + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/BundleBv2/BundleBv2.wxs b/src/test/burn/TestData/MsiTransactionTests/BundleBv2/BundleBv2.wxs new file mode 100644 index 00000000..d1861e75 --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/BundleBv2/BundleBv2.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/MsiTransactionTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/MsiTransactionTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..2ef7c05e --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/PackageA/PackageA.wixproj @@ -0,0 +1,10 @@ + + + + a + {7772FCDF-5FDB-497D-B5DF-C6D17D667976} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/PackageBv1/PackageB.props b/src/test/burn/TestData/MsiTransactionTests/PackageBv1/PackageB.props new file mode 100644 index 00000000..decdfb6a --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/PackageBv1/PackageB.props @@ -0,0 +1,9 @@ + + + + {EAFC0C6B-626E-415C-8132-536FBD19F49B} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/PackageBv1/PackageBv1.wixproj b/src/test/burn/TestData/MsiTransactionTests/PackageBv1/PackageBv1.wixproj new file mode 100644 index 00000000..6dc1e4d8 --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/PackageBv1/PackageBv1.wixproj @@ -0,0 +1,7 @@ + + + + + bv1 + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/PackageBv2/PackageBv2.wixproj b/src/test/burn/TestData/MsiTransactionTests/PackageBv2/PackageBv2.wixproj new file mode 100644 index 00000000..126d0f53 --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/PackageBv2/PackageBv2.wixproj @@ -0,0 +1,7 @@ + + + + + 2.0.0.0 + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/PackageCv1/PackageC.props b/src/test/burn/TestData/MsiTransactionTests/PackageCv1/PackageC.props new file mode 100644 index 00000000..b3d057bd --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/PackageCv1/PackageC.props @@ -0,0 +1,9 @@ + + + + {A18BDC12-DAEC-43EE-87D1-31B2C2BC6269} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/PackageCv1/PackageCv1.wixproj b/src/test/burn/TestData/MsiTransactionTests/PackageCv1/PackageCv1.wixproj new file mode 100644 index 00000000..617e61c3 --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/PackageCv1/PackageCv1.wixproj @@ -0,0 +1,7 @@ + + + + + cv1 + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/PackageCv2/PackageCv2.wixproj b/src/test/burn/TestData/MsiTransactionTests/PackageCv2/PackageCv2.wixproj new file mode 100644 index 00000000..640ad21d --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/PackageCv2/PackageCv2.wixproj @@ -0,0 +1,7 @@ + + + + + 2.0.0.0 + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/PackageD/PackageD.wixproj b/src/test/burn/TestData/MsiTransactionTests/PackageD/PackageD.wixproj new file mode 100644 index 00000000..1df5da24 --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/PackageD/PackageD.wixproj @@ -0,0 +1,9 @@ + + + + {78B072D5-1C23-4895-9C4C-1B52E3C80621} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/MsiTransactionTests/PackageF/PackageF.wixproj b/src/test/burn/TestData/MsiTransactionTests/PackageF/PackageF.wixproj new file mode 100644 index 00000000..753b054e --- /dev/null +++ b/src/test/burn/TestData/MsiTransactionTests/PackageF/PackageF.wixproj @@ -0,0 +1,12 @@ + + + + {3D59F8F2-8AC5-403E-B6F7-453870DE7063} + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PatchTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/PatchTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..72419d2d --- /dev/null +++ b/src/test/burn/TestData/PatchTests/BundleA/BundleA.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + true + {486FC795-69A5-4130-8727-4068F645A0A1} + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PatchTests/BundleA/BundleA.wxs b/src/test/burn/TestData/PatchTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..e3e0f4d7 --- /dev/null +++ b/src/test/burn/TestData/PatchTests/BundleA/BundleA.wxs @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/test/burn/TestData/PatchTests/BundlePatchA/BundlePatchA.wixproj b/src/test/burn/TestData/PatchTests/BundlePatchA/BundlePatchA.wixproj new file mode 100644 index 00000000..a506e843 --- /dev/null +++ b/src/test/burn/TestData/PatchTests/BundlePatchA/BundlePatchA.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + true + {AA083618-6280-44B8-9899-57BCC57906A5} + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PatchTests/BundlePatchA/BundlePatchA.wxs b/src/test/burn/TestData/PatchTests/BundlePatchA/BundlePatchA.wxs new file mode 100644 index 00000000..bf0c0451 --- /dev/null +++ b/src/test/burn/TestData/PatchTests/BundlePatchA/BundlePatchA.wxs @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/test/burn/TestData/PatchTests/BundlePatchA2/BundlePatchA2.wixproj b/src/test/burn/TestData/PatchTests/BundlePatchA2/BundlePatchA2.wixproj new file mode 100644 index 00000000..9a022091 --- /dev/null +++ b/src/test/burn/TestData/PatchTests/BundlePatchA2/BundlePatchA2.wixproj @@ -0,0 +1,20 @@ + + + + Bundle + true + {1BE09331-2327-4534-9223-59B54EFAE7A5} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PatchTests/BundlePatchA2/BundlePatchA2.wxs b/src/test/burn/TestData/PatchTests/BundlePatchA2/BundlePatchA2.wxs new file mode 100644 index 00000000..24063db3 --- /dev/null +++ b/src/test/burn/TestData/PatchTests/BundlePatchA2/BundlePatchA2.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/PatchTests/PackageAv1/PackageA.props b/src/test/burn/TestData/PatchTests/PackageAv1/PackageA.props new file mode 100644 index 00000000..a9d9b981 --- /dev/null +++ b/src/test/burn/TestData/PatchTests/PackageAv1/PackageA.props @@ -0,0 +1,13 @@ + + + + PackageA + true + {724F9BA5-DD9D-4851-855E-ECC35B27BF11} + true + {C56DA396-7A9A-4177-8264-638161CE9EB8} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PatchTests/PackageAv1/PackageAv1.wixproj b/src/test/burn/TestData/PatchTests/PackageAv1/PackageAv1.wixproj new file mode 100644 index 00000000..45d3b2c8 --- /dev/null +++ b/src/test/burn/TestData/PatchTests/PackageAv1/PackageAv1.wixproj @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PatchTests/PackageAv1/ProductComponents.wxs b/src/test/burn/TestData/PatchTests/PackageAv1/ProductComponents.wxs new file mode 100644 index 00000000..72b5d4bd --- /dev/null +++ b/src/test/burn/TestData/PatchTests/PackageAv1/ProductComponents.wxs @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/PatchTests/PackageAv1_0_1/PackageAv1_0_1.wixproj b/src/test/burn/TestData/PatchTests/PackageAv1_0_1/PackageAv1_0_1.wixproj new file mode 100644 index 00000000..9ceda117 --- /dev/null +++ b/src/test/burn/TestData/PatchTests/PackageAv1_0_1/PackageAv1_0_1.wixproj @@ -0,0 +1,10 @@ + + + + + 1.0.1.0 + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PatchTests/PatchA/PatchA.wixproj b/src/test/burn/TestData/PatchTests/PatchA/PatchA.wixproj new file mode 100644 index 00000000..da9acb5e --- /dev/null +++ b/src/test/burn/TestData/PatchTests/PatchA/PatchA.wixproj @@ -0,0 +1,12 @@ + + + + PatchCreation + .msp + 1079 + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PatchTests/PatchA/PatchA.wxs b/src/test/burn/TestData/PatchTests/PatchA/PatchA.wxs new file mode 100644 index 00000000..ba961762 --- /dev/null +++ b/src/test/burn/TestData/PatchTests/PatchA/PatchA.wxs @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/PatchTests/PatchA2/PatchA2.wixproj b/src/test/burn/TestData/PatchTests/PatchA2/PatchA2.wixproj new file mode 100644 index 00000000..da9acb5e --- /dev/null +++ b/src/test/burn/TestData/PatchTests/PatchA2/PatchA2.wixproj @@ -0,0 +1,12 @@ + + + + PatchCreation + .msp + 1079 + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PatchTests/PatchA2/PatchA2.wxs b/src/test/burn/TestData/PatchTests/PatchA2/PatchA2.wxs new file mode 100644 index 00000000..e2aa3e2b --- /dev/null +++ b/src/test/burn/TestData/PatchTests/PatchA2/PatchA2.wxs @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..13bb159b --- /dev/null +++ b/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wixproj @@ -0,0 +1,21 @@ + + + + Bundle + BrokenDnc + {A4456636-916A-43A0-87BF-A897C2717A00} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wxs b/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..c903988b --- /dev/null +++ b/src/test/burn/TestData/PrereqBaTests/BundleA/BundleA.wxs @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/PrereqBaTests/BundleA/bad.runtimeconfig.json b/src/test/burn/TestData/PrereqBaTests/BundleA/bad.runtimeconfig.json new file mode 100644 index 00000000..07a1a830 --- /dev/null +++ b/src/test/burn/TestData/PrereqBaTests/BundleA/bad.runtimeconfig.json @@ -0,0 +1,10 @@ +{ + "runtimeOptions": { + "tfm": "net5.5", + "rollForward": "Disable", + "framework": { + "name": "Microsoft.WindowsDesktop.App", + "version": "5.5.0" + } + } +} \ No newline at end of file diff --git a/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wixproj b/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wixproj new file mode 100644 index 00000000..cfbc77b5 --- /dev/null +++ b/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wixproj @@ -0,0 +1,21 @@ + + + + Bundle + BrokenMba + {157A1FBA-3825-4AAA-B13D-F45435A79D64} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wxs b/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wxs new file mode 100644 index 00000000..603c3aee --- /dev/null +++ b/src/test/burn/TestData/PrereqBaTests/BundleB/BundleB.wxs @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/PrereqBaTests/BundleB/bad.config b/src/test/burn/TestData/PrereqBaTests/BundleB/bad.config new file mode 100644 index 00000000..1512e59a --- /dev/null +++ b/src/test/burn/TestData/PrereqBaTests/BundleB/bad.config @@ -0,0 +1,17 @@ + + + + + + + +
+ + + + + + + + + diff --git a/src/test/burn/TestData/PrereqBaTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/PrereqBaTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..d46982fa --- /dev/null +++ b/src/test/burn/TestData/PrereqBaTests/PackageA/PackageA.wixproj @@ -0,0 +1,9 @@ + + + + {A13BFF68-61DF-4015-9AD1-03854B5E0212} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PrereqBaTests/PackageB/PackageB.wixproj b/src/test/burn/TestData/PrereqBaTests/PackageB/PackageB.wixproj new file mode 100644 index 00000000..d5edf338 --- /dev/null +++ b/src/test/burn/TestData/PrereqBaTests/PackageB/PackageB.wixproj @@ -0,0 +1,9 @@ + + + + {3DD4621A-F7AB-4548-89A8-6DCB0A9BC954} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/PrereqBaTests/PackageF/PackageF.wixproj b/src/test/burn/TestData/PrereqBaTests/PackageF/PackageF.wixproj new file mode 100644 index 00000000..0a750fe0 --- /dev/null +++ b/src/test/burn/TestData/PrereqBaTests/PackageF/PackageF.wixproj @@ -0,0 +1,12 @@ + + + + {7DEEE928-CD7F-49AD-8000-2ED6339D8A78} + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/RegistrationTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/RegistrationTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..a6ccd842 --- /dev/null +++ b/src/test/burn/TestData/RegistrationTests/BundleA/BundleA.wixproj @@ -0,0 +1,18 @@ + + + + Bundle + {17041020-8A61-4A3B-8FDB-4591CB900049} + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/RegistrationTests/BundleA/BundleA.wxs b/src/test/burn/TestData/RegistrationTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..bd164a29 --- /dev/null +++ b/src/test/burn/TestData/RegistrationTests/BundleA/BundleA.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/RegistrationTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/RegistrationTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..7e5dbb8c --- /dev/null +++ b/src/test/burn/TestData/RegistrationTests/PackageA/PackageA.wixproj @@ -0,0 +1,9 @@ + + + + {BF26D3E4-1D6B-480E-B312-3FECE6363E43} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/RollbackBoundaryTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/RollbackBoundaryTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..648cc934 --- /dev/null +++ b/src/test/burn/TestData/RollbackBoundaryTests/BundleA/BundleA.wixproj @@ -0,0 +1,20 @@ + + + + Bundle + hyperlinkLicense + {E8426C86-D5E4-45FA-B09D-789DC7E5E00A} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/RollbackBoundaryTests/BundleA/BundleA.wxs b/src/test/burn/TestData/RollbackBoundaryTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..795dc13a --- /dev/null +++ b/src/test/burn/TestData/RollbackBoundaryTests/BundleA/BundleA.wxs @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/RollbackBoundaryTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/RollbackBoundaryTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..25d9e279 --- /dev/null +++ b/src/test/burn/TestData/RollbackBoundaryTests/PackageA/PackageA.wixproj @@ -0,0 +1,9 @@ + + + + {14A06CEA-CC9E-478F-AD20-5C9624827090} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/RollbackBoundaryTests/PackageB/PackageB.wixproj b/src/test/burn/TestData/RollbackBoundaryTests/PackageB/PackageB.wixproj new file mode 100644 index 00000000..2dc4f3a6 --- /dev/null +++ b/src/test/burn/TestData/RollbackBoundaryTests/PackageB/PackageB.wixproj @@ -0,0 +1,9 @@ + + + + {C0B6E75E-4378-4589-B3C5-A23FFA39F59B} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/RollbackBoundaryTests/PackageC/PackageC.wixproj b/src/test/burn/TestData/RollbackBoundaryTests/PackageC/PackageC.wixproj new file mode 100644 index 00000000..a4b5134b --- /dev/null +++ b/src/test/burn/TestData/RollbackBoundaryTests/PackageC/PackageC.wixproj @@ -0,0 +1,9 @@ + + + + {1C977E8F-4E79-4E3B-A5B1-C4B0BE774041} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/RollbackBoundaryTests/PackageF/PackageF.wixproj b/src/test/burn/TestData/RollbackBoundaryTests/PackageF/PackageF.wixproj new file mode 100644 index 00000000..071c40a0 --- /dev/null +++ b/src/test/burn/TestData/RollbackBoundaryTests/PackageF/PackageF.wixproj @@ -0,0 +1,12 @@ + + + + {E348D377-E5E7-44B0-897E-5DC8D401BF80} + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/SlipstreamTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..b6ab068a --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleA/BundleA.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + {62C28DAF-A13E-4F55-ACA1-FB843630789C} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/BundleA/BundleA.wxs b/src/test/burn/TestData/SlipstreamTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..17dc6c05 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleA/BundleA.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/BundleAReverse/BundleAReverse.wixproj b/src/test/burn/TestData/SlipstreamTests/BundleAReverse/BundleAReverse.wixproj new file mode 100644 index 00000000..ac33c5ad --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleAReverse/BundleAReverse.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + {F6BB4AE2-F7D4-4768-8314-3AF694C400E9} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/BundleAReverse/BundleAReverse.wxs b/src/test/burn/TestData/SlipstreamTests/BundleAReverse/BundleAReverse.wxs new file mode 100644 index 00000000..2008fa8b --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleAReverse/BundleAReverse.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/BundleB/BundleB.wixproj b/src/test/burn/TestData/SlipstreamTests/BundleB/BundleB.wixproj new file mode 100644 index 00000000..3ca849a3 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleB/BundleB.wixproj @@ -0,0 +1,20 @@ + + + + Bundle + {604878DE-F0EB-4FE1-B11E-DC19F07F82F5} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/BundleB/BundleB.wxs b/src/test/burn/TestData/SlipstreamTests/BundleB/BundleB.wxs new file mode 100644 index 00000000..90ddd258 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleB/BundleB.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/BundleC/BundleC.wixproj b/src/test/burn/TestData/SlipstreamTests/BundleC/BundleC.wixproj new file mode 100644 index 00000000..377e939c --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleC/BundleC.wixproj @@ -0,0 +1,21 @@ + + + + Bundle + {16B551B5-6EBE-417F-8CB2-50936F079301} + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/BundleC/BundleC.wxs b/src/test/burn/TestData/SlipstreamTests/BundleC/BundleC.wxs new file mode 100644 index 00000000..4702d845 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleC/BundleC.wxs @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/BundleD/BundleD.wixproj b/src/test/burn/TestData/SlipstreamTests/BundleD/BundleD.wixproj new file mode 100644 index 00000000..12f11444 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleD/BundleD.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + {5372D18C-8C62-4C22-A24B-6BB2FB4AA966} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/BundleD/BundleD.wxs b/src/test/burn/TestData/SlipstreamTests/BundleD/BundleD.wxs new file mode 100644 index 00000000..64bdc1b5 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleD/BundleD.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/BundleOnlyA/BundleOnlyA.wixproj b/src/test/burn/TestData/SlipstreamTests/BundleOnlyA/BundleOnlyA.wixproj new file mode 100644 index 00000000..193244ca --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleOnlyA/BundleOnlyA.wixproj @@ -0,0 +1,18 @@ + + + + Bundle + {80A9925A-2EC1-4BD5-BB69-2553BF7FCED9} + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/BundleOnlyA/BundleOnlyA.wxs b/src/test/burn/TestData/SlipstreamTests/BundleOnlyA/BundleOnlyA.wxs new file mode 100644 index 00000000..e3e0f4d7 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleOnlyA/BundleOnlyA.wxs @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/BundleOnlyPatchA/BundleOnlyPatchA.wixproj b/src/test/burn/TestData/SlipstreamTests/BundleOnlyPatchA/BundleOnlyPatchA.wixproj new file mode 100644 index 00000000..11995ddd --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleOnlyPatchA/BundleOnlyPatchA.wixproj @@ -0,0 +1,18 @@ + + + + Bundle + {9B026C22-924C-4CEA-8726-FD07C1706A9F} + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/BundleOnlyPatchA/BundleOnlyPatchA.wxs b/src/test/burn/TestData/SlipstreamTests/BundleOnlyPatchA/BundleOnlyPatchA.wxs new file mode 100644 index 00000000..88a93d7a --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/BundleOnlyPatchA/BundleOnlyPatchA.wxs @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/PackageAv0_9_0/PackageAv0_9_0.wixproj b/src/test/burn/TestData/SlipstreamTests/PackageAv0_9_0/PackageAv0_9_0.wixproj new file mode 100644 index 00000000..50aa6ec6 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PackageAv0_9_0/PackageAv0_9_0.wixproj @@ -0,0 +1,10 @@ + + + + + 0.9.0.0 + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageA.props b/src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageA.props new file mode 100644 index 00000000..734e0d6d --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageA.props @@ -0,0 +1,11 @@ + + + + PackageA + true + {DB87BB66-FE5D-4293-81AC-EE313D3F864B} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageAv1.props b/src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageAv1.props new file mode 100644 index 00000000..2936f349 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageAv1.props @@ -0,0 +1,7 @@ + + + + + {5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B} + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageAv1.wixproj b/src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageAv1.wixproj new file mode 100644 index 00000000..e85be384 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PackageAv1/PackageAv1.wixproj @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PackageAv1/ProductComponents.wxs b/src/test/burn/TestData/SlipstreamTests/PackageAv1/ProductComponents.wxs new file mode 100644 index 00000000..72b5d4bd --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PackageAv1/ProductComponents.wxs @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/PackageAv1_0_1/PackageAv1_0_1.wixproj b/src/test/burn/TestData/SlipstreamTests/PackageAv1_0_1/PackageAv1_0_1.wixproj new file mode 100644 index 00000000..dbce9cfe --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PackageAv1_0_1/PackageAv1_0_1.wixproj @@ -0,0 +1,10 @@ + + + + + 1.0.1.0 + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PackageBv1/PackageB.props b/src/test/burn/TestData/SlipstreamTests/PackageBv1/PackageB.props new file mode 100644 index 00000000..920088fb --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PackageBv1/PackageB.props @@ -0,0 +1,12 @@ + + + + PackageB + true + {83B1ADF3-A8DD-41D3-9114-57703DA17754} + {552F8D3B-99E1-4772-8E8C-CC47E5ED5F71} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PackageBv1/PackageBv1.wixproj b/src/test/burn/TestData/SlipstreamTests/PackageBv1/PackageBv1.wixproj new file mode 100644 index 00000000..7b6f83a3 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PackageBv1/PackageBv1.wixproj @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PackageBv1/ProductComponents.wxs b/src/test/burn/TestData/SlipstreamTests/PackageBv1/ProductComponents.wxs new file mode 100644 index 00000000..72b5d4bd --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PackageBv1/ProductComponents.wxs @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/PackageBv1_0_1/PackageBv1_0_1.wixproj b/src/test/burn/TestData/SlipstreamTests/PackageBv1_0_1/PackageBv1_0_1.wixproj new file mode 100644 index 00000000..3ec790ad --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PackageBv1_0_1/PackageBv1_0_1.wixproj @@ -0,0 +1,10 @@ + + + + + 1.0.1.0 + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PatchA/PatchA.wixproj b/src/test/burn/TestData/SlipstreamTests/PatchA/PatchA.wixproj new file mode 100644 index 00000000..da9acb5e --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PatchA/PatchA.wixproj @@ -0,0 +1,12 @@ + + + + PatchCreation + .msp + 1079 + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PatchA/PatchA.wxs b/src/test/burn/TestData/SlipstreamTests/PatchA/PatchA.wxs new file mode 100644 index 00000000..7c3818b0 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PatchA/PatchA.wxs @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/PatchAB/PatchAB.wixproj b/src/test/burn/TestData/SlipstreamTests/PatchAB/PatchAB.wixproj new file mode 100644 index 00000000..81fa9e12 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PatchAB/PatchAB.wixproj @@ -0,0 +1,14 @@ + + + + PatchCreation + .msp + 1079 + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PatchAB/PatchAB.wxs b/src/test/burn/TestData/SlipstreamTests/PatchAB/PatchAB.wxs new file mode 100644 index 00000000..f700f35c --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PatchAB/PatchAB.wxs @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/SlipstreamTests/PatchAB2/PatchAB2.wixproj b/src/test/burn/TestData/SlipstreamTests/PatchAB2/PatchAB2.wixproj new file mode 100644 index 00000000..81fa9e12 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PatchAB2/PatchAB2.wixproj @@ -0,0 +1,14 @@ + + + + PatchCreation + .msp + 1079 + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/SlipstreamTests/PatchAB2/PatchAB2.wxs b/src/test/burn/TestData/SlipstreamTests/PatchAB2/PatchAB2.wxs new file mode 100644 index 00000000..ebd5bed0 --- /dev/null +++ b/src/test/burn/TestData/SlipstreamTests/PatchAB2/PatchAB2.wxs @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/Templates/Bundle.wxs b/src/test/burn/TestData/Templates/Bundle.wxs new file mode 100644 index 00000000..06409504 --- /dev/null +++ b/src/test/burn/TestData/Templates/Bundle.wxs @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/Templates/Package.wxs b/src/test/burn/TestData/Templates/Package.wxs new file mode 100644 index 00000000..48ed5e02 --- /dev/null +++ b/src/test/burn/TestData/Templates/Package.wxs @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/Templates/PackageFail.wxs b/src/test/burn/TestData/Templates/PackageFail.wxs new file mode 100644 index 00000000..0139c22b --- /dev/null +++ b/src/test/burn/TestData/Templates/PackageFail.wxs @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/Templates/PackagePerUser.wxs b/src/test/burn/TestData/Templates/PackagePerUser.wxs new file mode 100644 index 00000000..5e18fefd --- /dev/null +++ b/src/test/burn/TestData/Templates/PackagePerUser.wxs @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/TestBA/TestBAWixlib/TestBA.wxs b/src/test/burn/TestData/TestBA/TestBAWixlib/TestBA.wxs new file mode 100644 index 00000000..348a0cbb --- /dev/null +++ b/src/test/burn/TestData/TestBA/TestBAWixlib/TestBA.wxs @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/TestBA/TestBAWixlib/TestExe.wxs b/src/test/burn/TestData/TestBA/TestBAWixlib/TestExe.wxs new file mode 100644 index 00000000..f27275b0 --- /dev/null +++ b/src/test/burn/TestData/TestBA/TestBAWixlib/TestExe.wxs @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/test/burn/TestData/TestBA/TestBAWixlib/testbawixlib.wixproj b/src/test/burn/TestData/TestBA/TestBAWixlib/testbawixlib.wixproj new file mode 100644 index 00000000..ae90dd73 --- /dev/null +++ b/src/test/burn/TestData/TestBA/TestBAWixlib/testbawixlib.wixproj @@ -0,0 +1,19 @@ + + + + Library + true + en-us + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/TestBA/TestBAWixlib_x64/TestBA_x64.wxs b/src/test/burn/TestData/TestBA/TestBAWixlib_x64/TestBA_x64.wxs new file mode 100644 index 00000000..078f4f01 --- /dev/null +++ b/src/test/burn/TestData/TestBA/TestBAWixlib_x64/TestBA_x64.wxs @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/TestBA/TestBAWixlib_x64/TestExe_x64.wxs b/src/test/burn/TestData/TestBA/TestBAWixlib_x64/TestExe_x64.wxs new file mode 100644 index 00000000..02bed038 --- /dev/null +++ b/src/test/burn/TestData/TestBA/TestBAWixlib_x64/TestExe_x64.wxs @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/test/burn/TestData/TestBA/TestBAWixlib_x64/testbawixlib_x64.wixproj b/src/test/burn/TestData/TestBA/TestBAWixlib_x64/testbawixlib_x64.wixproj new file mode 100644 index 00000000..9b7d3c17 --- /dev/null +++ b/src/test/burn/TestData/TestBA/TestBAWixlib_x64/testbawixlib_x64.wixproj @@ -0,0 +1,20 @@ + + + + Library + true + en-us + x64 + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/TestData.proj b/src/test/burn/TestData/TestData.proj new file mode 100644 index 00000000..c5682fc7 --- /dev/null +++ b/src/test/burn/TestData/TestData.proj @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleA.props b/src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleA.props new file mode 100644 index 00000000..19b37770 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleA.props @@ -0,0 +1,10 @@ + + + + Bundle + {AF745E41-CEAC-4C9F-83D8-663BAB1AF5CC} + + + + + diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleAv1.wixproj b/src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleAv1.wixproj new file mode 100644 index 00000000..d968e8ab --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleAv1.wixproj @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleAv1.wxs b/src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleAv1.wxs new file mode 100644 index 00000000..7bf16212 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleAv1/BundleAv1.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleAv2/BundleAv2.wixproj b/src/test/burn/TestData/UpdateBundleTests/BundleAv2/BundleAv2.wixproj new file mode 100644 index 00000000..07e9581b --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleAv2/BundleAv2.wixproj @@ -0,0 +1,15 @@ + + + + + 2.0.0.0 + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleAv2/BundleAv2.wxs b/src/test/burn/TestData/UpdateBundleTests/BundleAv2/BundleAv2.wxs new file mode 100644 index 00000000..5cbee5a8 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleAv2/BundleAv2.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleBv1/Bundle.wxs b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/Bundle.wxs new file mode 100644 index 00000000..906121f4 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/Bundle.wxs @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleB.props b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleB.props new file mode 100644 index 00000000..8a275612 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleB.props @@ -0,0 +1,7 @@ + + + + Bundle + {BF325BA5-5012-47C7-828C-577B6979CB28} + + diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleBv1.wixproj b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleBv1.wixproj new file mode 100644 index 00000000..b2685e2e --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleBv1.wixproj @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleBv1.wxs b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleBv1.wxs new file mode 100644 index 00000000..00d927ec --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/BundleBv1.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleBv1/FeedBv1.0.xml b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/FeedBv1.0.xml new file mode 100644 index 00000000..743548be --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/FeedBv1.0.xml @@ -0,0 +1,32 @@ + + + + + + BundleB v1.0 + Bundle Subtitle. + 1116353B-7C6E-4C29-BFA1-D4A972CD421D + 2014-07-14T12:39:00.000Z + http://localhost:9999/e2e/BundleB/feed + + manual build + + Bundle v1.0 + v1.0 + + Bundle_Author + http://mycompany.com/software + Bundle_Author@mycompany.com + + + + + <p>Change list:</p><ul> + <li>Initial release.</li> + </ul> + + + 1.0.0.0 + 2014-07-14T12:39:00.000Z + + diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleBv1/FeedBv2.0.xml b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/FeedBv2.0.xml new file mode 100644 index 00000000..c8e3f6ea --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleBv1/FeedBv2.0.xml @@ -0,0 +1,51 @@ + + + + + + BundleB v2.0 + Bundle Subtitle. + 1116353B-7C6E-4C29-BFA1-D4A972CD421D + 2014-07-14T12:39:00.000Z + http://localhost:9999/e2e/BundleB/feed + + manual build + + Bundle v2.0 + v2.0 + + Bundle_Author + http://mycompany.com/software + Bundle_Author@mycompany.com + + + + + <p>Change list:</p><ul> + <li>Updated release.</li> + </ul> + + + 2.0.0.0 + 2014-11-10T12:39:00.000Z + + + Bundle v1.0 + v1.0 + + Bundle_Author + http://mycompany.com/software + Bundle_Author@mycompany.com + + + + + <p>Change list:</p><ul> + <li>Initial release.</li> + </ul> + + + 1.0.0.0 + 2014-11-09T12:39:00.000Z + + diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleBv2/BundleBv2.wixproj b/src/test/burn/TestData/UpdateBundleTests/BundleBv2/BundleBv2.wixproj new file mode 100644 index 00000000..a11fc252 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleBv2/BundleBv2.wixproj @@ -0,0 +1,18 @@ + + + + + 2.0.0.0 + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpdateBundleTests/BundleBv2/BundleBv2.wxs b/src/test/burn/TestData/UpdateBundleTests/BundleBv2/BundleBv2.wxs new file mode 100644 index 00000000..2043b084 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/BundleBv2/BundleBv2.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/UpdateBundleTests/PackageAv1/PackageA.props b/src/test/burn/TestData/UpdateBundleTests/PackageAv1/PackageA.props new file mode 100644 index 00000000..bc734540 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/PackageAv1/PackageA.props @@ -0,0 +1,9 @@ + + + + {AB55C215-3268-4005-9657-6B0567F0A4B1} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpdateBundleTests/PackageAv1/PackageAv1.wixproj b/src/test/burn/TestData/UpdateBundleTests/PackageAv1/PackageAv1.wixproj new file mode 100644 index 00000000..45d3b2c8 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/PackageAv1/PackageAv1.wixproj @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpdateBundleTests/PackageAv2/PackageAv2.wixproj b/src/test/burn/TestData/UpdateBundleTests/PackageAv2/PackageAv2.wixproj new file mode 100644 index 00000000..b419f663 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/PackageAv2/PackageAv2.wixproj @@ -0,0 +1,7 @@ + + + + + 2.0.0.0 + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpdateBundleTests/PackageBv1/PackageB.props b/src/test/burn/TestData/UpdateBundleTests/PackageBv1/PackageB.props new file mode 100644 index 00000000..e677cb7e --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/PackageBv1/PackageB.props @@ -0,0 +1,9 @@ + + + + {6B971C9E-2FB0-4BF7-8D77-D2DF71FD9A14} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpdateBundleTests/PackageBv1/PackageBv1.wixproj b/src/test/burn/TestData/UpdateBundleTests/PackageBv1/PackageBv1.wixproj new file mode 100644 index 00000000..7b6f83a3 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/PackageBv1/PackageBv1.wixproj @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpdateBundleTests/PackageBv2/PackageBv2.wixproj b/src/test/burn/TestData/UpdateBundleTests/PackageBv2/PackageBv2.wixproj new file mode 100644 index 00000000..126d0f53 --- /dev/null +++ b/src/test/burn/TestData/UpdateBundleTests/PackageBv2/PackageBv2.wixproj @@ -0,0 +1,7 @@ + + + + + 2.0.0.0 + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleA.props b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleA.props new file mode 100644 index 00000000..ee20a72c --- /dev/null +++ b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleA.props @@ -0,0 +1,10 @@ + + + + Bundle + {8C01FD92-87BE-419B-88EC-36754E93CA67} + + + + + diff --git a/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleAv1.wixproj b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleAv1.wixproj new file mode 100644 index 00000000..d968e8ab --- /dev/null +++ b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleAv1.wixproj @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleAv1.wxs b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleAv1.wxs new file mode 100644 index 00000000..7bf16212 --- /dev/null +++ b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1/BundleAv1.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv2/BundleAv2.wixproj b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv2/BundleAv2.wixproj new file mode 100644 index 00000000..07e9581b --- /dev/null +++ b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv2/BundleAv2.wixproj @@ -0,0 +1,15 @@ + + + + + 2.0.0.0 + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv2/BundleAv2.wxs b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv2/BundleAv2.wxs new file mode 100644 index 00000000..5cbee5a8 --- /dev/null +++ b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv2/BundleAv2.wxs @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv1/PackageA.props b/src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv1/PackageA.props new file mode 100644 index 00000000..53541e10 --- /dev/null +++ b/src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv1/PackageA.props @@ -0,0 +1,9 @@ + + + + {E7AF5E0D-EC10-4339-9126-76A76011DA3A} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv1/PackageAv1.wixproj b/src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv1/PackageAv1.wixproj new file mode 100644 index 00000000..45d3b2c8 --- /dev/null +++ b/src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv1/PackageAv1.wixproj @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv2/PackageAv2.wixproj b/src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv2/PackageAv2.wixproj new file mode 100644 index 00000000..b419f663 --- /dev/null +++ b/src/test/burn/TestData/UpgradeRelatedBundleTests/PackageAv2/PackageAv2.wixproj @@ -0,0 +1,7 @@ + + + + + 2.0.0.0 + + \ No newline at end of file diff --git a/src/test/burn/TestExe/NetfxTask.cs b/src/test/burn/TestExe/NetfxTask.cs new file mode 100644 index 00000000..35b1ea95 --- /dev/null +++ b/src/test/burn/TestExe/NetfxTask.cs @@ -0,0 +1,295 @@ +// 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. + +#if NET35 +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Management; +using Microsoft.Win32; + +namespace TestExe +{ + public class ProcessInfoTask : Task + { + public ProcessInfoTask(string Data) : base(Data) { } + + public override void RunTask() + { + try + { + string processInfoXml = ""; + + // Get information about the process and who is running it + Process thisProc = Process.GetCurrentProcess(); + string username = thisProc.StartInfo.EnvironmentVariables["username"].ToString(); + + int parentProcId = GetParentProcess(thisProc.Id); + Process parentProc = Process.GetProcessById(parentProcId); + string parentUsername = parentProc.StartInfo.EnvironmentVariables["username"].ToString(); + + int grandparentProcId = GetParentProcess(parentProc.Id); + Process grandparentProc = Process.GetProcessById(grandparentProcId); + string grandparentUsername = grandparentProc.StartInfo.EnvironmentVariables["username"].ToString(); + + processInfoXml += ""; + processInfoXml += " " + thisProc.ProcessName + ""; + processInfoXml += " " + thisProc.Id.ToString() + ""; + processInfoXml += " " + thisProc.SessionId.ToString() + ""; + processInfoXml += " " + thisProc.MachineName + ""; + // this stuff isn't set since we didn't start the process and tell it what to use. So don't bother + //processInfoXml += " "; + //processInfoXml += " " + thisProc.StartInfo.FileName + ""; + //processInfoXml += " " + thisProc.StartInfo.UserName + ""; + //processInfoXml += " " + thisProc.StartInfo.WorkingDirectory + ""; + //processInfoXml += " " + thisProc.StartInfo.Arguments + ""; + //processInfoXml += " "; + processInfoXml += " " + thisProc.StartTime.ToString() + ""; + processInfoXml += " " + username + ""; + processInfoXml += " "; + processInfoXml += " " + parentProc.ProcessName + ""; + processInfoXml += " " + parentProc.Id.ToString() + ""; + processInfoXml += " " + parentProc.StartTime.ToString() + ""; + processInfoXml += " " + parentUsername + ""; + processInfoXml += " "; + processInfoXml += " "; + processInfoXml += " " + grandparentProc.ProcessName + ""; + processInfoXml += " " + grandparentProc.Id.ToString() + ""; + processInfoXml += " " + grandparentProc.StartTime.ToString() + ""; + processInfoXml += " " + grandparentUsername + ""; + processInfoXml += " "; + processInfoXml += ""; + + string logFile = System.Environment.ExpandEnvironmentVariables(this.data); + Console.WriteLine("Creating Process Info data file: " + logFile); + StreamWriter textFile = File.CreateText(logFile); + textFile.WriteLine(processInfoXml); + textFile.Close(); + } + catch (Exception eX) + { + Console.WriteLine("Creating Process Info data file failed"); + Console.WriteLine(eX.Message); + } + + + } + + private static int GetParentProcess(int Id) + { + int parentPid = 0; + using (ManagementObject mo = new ManagementObject("win32_process.handle='" + Id.ToString() + "'")) + { + mo.Get(); + parentPid = Convert.ToInt32(mo["ParentProcessId"]); + } + return parentPid; + } + } + + /// + /// Task class that will create a registry key and write a name and value in it + /// + public class RegistryWriterTask : Task + { + private string hive; + private string keyPath; + private string[] keyPathArray; + private string name; + private RegistryValueKind regValueKind; + private object value; + + public RegistryWriterTask(string Data) : base(Data) { } + + public override void RunTask() + { + if (this.parseRegKeyNameTypeValue(System.Environment.ExpandEnvironmentVariables(this.data))) + { + RegistryKey rk = Registry.LocalMachine; + + if (this.hive == "HKCU") { rk = Microsoft.Win32.Registry.CurrentUser; } + if (this.hive == "HKCC") { rk = Microsoft.Win32.Registry.CurrentConfig; } + if (this.hive == "HKLM") { rk = Microsoft.Win32.Registry.LocalMachine; } + + foreach (string key in this.keyPathArray) + { + rk = rk.CreateSubKey(key, RegistryKeyPermissionCheck.ReadWriteSubTree); + } + + rk.SetValue(this.name, this.value, this.regValueKind); + Console.WriteLine("Created registry key: '{0}' name: '{1}' value: '{2}' of type: '{3}'", + this.hive + "\\" + this.keyPath, + this.name, + this.value.ToString(), + this.regValueKind.ToString()); + } + else + { + Console.WriteLine("Unable to write registry key."); + } + + } + + private bool parseRegKeyNameTypeValue(string delimittedData) + { + string[] splitString = delimittedData.Split(new string[] { "," }, StringSplitOptions.None); + if (splitString.Length != 4) + { + Console.WriteLine("Invalid regkey. Unable to parse key,name,type,value from: \"" + delimittedData + "\""); + return false; + } + else + { + this.keyPath = splitString[0]; + this.name = splitString[1]; + string datatype = splitString[2]; + if (datatype == "DWord") + { + this.value = UInt32.Parse(splitString[3]); + } + else if (datatype == "QWord") + { + this.value = UInt64.Parse(splitString[3]); + } + else + { + this.value = splitString[3]; + } + + if (this.keyPath.ToUpper().StartsWith("HKLM\\")) + { + this.hive = "HKLM"; + this.keyPath = this.keyPath.Replace("HKLM\\", ""); + } + else if (this.keyPath.ToUpper().StartsWith("HKCC\\")) + { + this.hive = "HKCC"; + this.keyPath = this.keyPath.Replace("HKCC\\", ""); + } + else if (this.keyPath.ToUpper().StartsWith("HKCU\\")) + { + this.hive = "HKCU"; + this.keyPath = this.keyPath.Replace("HKCU\\", ""); + } + else + { + Console.WriteLine("Invalid regkey. Unable to determin hive. regkey must start with either: [HKLM], [HKCU], or [HKCC]"); + return false; + } + this.keyPathArray = this.keyPath.Split(new string[] { "\\" }, StringSplitOptions.None); + + try + { + this.regValueKind = (RegistryValueKind)System.Enum.Parse(typeof(RegistryValueKind), datatype); + } + catch (Exception ex) + { + Console.WriteLine("Invalid datatype. It must be: String, DWord, or QWord (case sensitive)"); + Console.WriteLine(ex.Message); + return false; + } + } + return true; + } + } + + /// + /// Task class that will delete a registry key value or registry key and all of its children + /// + public class RegistryDeleterTask : Task + { + private string hive; + private string keyPath; + private string[] keyPathArray; + private string name; + + public RegistryDeleterTask(string Data) : base(Data) { } + + public override void RunTask() + { + if (this.parseRegKeyName(System.Environment.ExpandEnvironmentVariables(this.data))) + { + try + { + RegistryKey rk = Registry.LocalMachine; + + if (this.hive == "HKCU") { rk = Microsoft.Win32.Registry.CurrentUser; } + if (this.hive == "HKCC") { rk = Microsoft.Win32.Registry.CurrentConfig; } + if (this.hive == "HKLM") { rk = Microsoft.Win32.Registry.LocalMachine; } + + RegistryKey rkParent = null; + foreach (string key in this.keyPathArray) + { + rkParent = rk; + rk = rk.OpenSubKey(key, true); + } + + if (String.IsNullOrEmpty(this.name)) + { + // delete the key and all of its children + string subkeyToDelete = this.keyPathArray[this.keyPathArray.Length - 1]; + rkParent.DeleteSubKeyTree(subkeyToDelete); + Console.WriteLine("Deleted registry key: '{0}'", this.hive + "\\" + this.keyPath); + } + else + { + // just delete this value + rk.DeleteValue(this.name); + Console.WriteLine("Deleted registry key: '{0}' name: '{1}'", this.hive + "\\" + this.keyPath, this.name); + } + } + catch (Exception ex) + { + Console.WriteLine("Unable to delete registry key: '{0}'", this.hive + "\\" + this.keyPath); + Console.WriteLine(ex.Message); + } + } + else + { + Console.WriteLine("Unable to delete registry key."); + } + + } + + private bool parseRegKeyName(string delimittedData) + { + string[] splitString = delimittedData.Split(new string[] { "," }, StringSplitOptions.None); + + if (splitString.Length > 2) + { + Console.WriteLine("Unable to parse registry key and name."); + return false; + } + + this.keyPath = splitString[0]; + if (splitString.Length == 2) + { + this.name = splitString[1]; + } + + if (this.keyPath.ToUpper().StartsWith("HKLM\\")) + { + this.hive = "HKLM"; + this.keyPath = this.keyPath.Replace("HKLM\\", ""); + } + else if (this.keyPath.ToUpper().StartsWith("HKCC\\")) + { + this.hive = "HKCC"; + this.keyPath = this.keyPath.Replace("HKCC\\", ""); + } + else if (this.keyPath.ToUpper().StartsWith("HKCU\\")) + { + this.hive = "HKCU"; + this.keyPath = this.keyPath.Replace("HKCU\\", ""); + } + else + { + Console.WriteLine("Invalid regkey. Unable to determine hive. regkey must start with either: [HKLM], [HKCU], or [HKCC]"); + return false; + } + this.keyPathArray = this.keyPath.Split(new string[] { "\\" }, StringSplitOptions.None); + return true; + } + } +} +#endif diff --git a/src/test/burn/TestExe/Program.cs b/src/test/burn/TestExe/Program.cs new file mode 100644 index 00000000..e92c413b --- /dev/null +++ b/src/test/burn/TestExe/Program.cs @@ -0,0 +1,74 @@ +// 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. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace TestExe +{ + class Program + { + static List tasks; + static int exitCodeToReturn = 0; + + static int Main(string[] args) + { + Usage(); + tasks = TaskParser.ParseTasks(args); + + foreach (Task t in tasks) + { + // special case for the ExitCodeTask + if (t.GetType() == typeof(ExitCodeTask)) + { + exitCodeToReturn = int.Parse(t.data); + } + else + { + t.RunTask(); + } + } + + Console.WriteLine("Exiting with ExitCode = {0}", exitCodeToReturn); + return exitCodeToReturn; + } + + static void Usage() + { + Console.WriteLine(@"TestExe.exe"); + Console.WriteLine(@""); + Console.WriteLine(@"TestExe can be passed various switches to define how it will behave and what tasks it will perform."); + Console.WriteLine(@"All switches are optional."); + Console.WriteLine(@"Any # of switches can be combined in any order."); + Console.WriteLine(@"Switches can be specified multiple times."); + Console.WriteLine(@"The order of the switches listed is the order they will be processed."); + Console.WriteLine(@"Info is written to stdout to describe what tasks are being performed as they are executed."); + Console.WriteLine(@""); + Console.WriteLine(@"Usage: TestExe.exe [tasks...]"); + Console.WriteLine(@""); + Console.WriteLine(@""); + Console.WriteLine(@"/ec # Exit code to return. Can only be specified once. If not specified, 0 will be returned. Example: “/ec 3010” would return 3010"); + Console.WriteLine(@"/s # Milliseconds to sleep before continuing. Example: “/s 5000” would sleep 5 seconds."); + Console.WriteLine(@"/sr #-# Random range of Milliseconds to sleep before continuing. Example: “/sr 5000-10000” would sleep between 5-10 seconds."); + Console.WriteLine(@"/log filename Create a log file called filename. Contents of the log are static text. Example: “/log %temp%\test.log” would create a %temp%\test.log file."); + Console.WriteLine(@"/Pinfo filename Create an xml file containing information about the process: PID, start time, user running the process, etc."); + Console.WriteLine(@"/fe filename Wait for a file to exist before continuing. Example: “/fe %temp%\cache\file.msi” would wait until %temp%\cache\file.msi exists."); + Console.WriteLine(@"/regw regkey,name,type,value (Re)writes a registry key with the specified value"); + Console.WriteLine(@"/regd regkey,[name] Deletes registry key name or key and all of its children (subkeys and values)"); + Console.WriteLine(@""); + Console.WriteLine(@"Example: "); + Console.WriteLine(@""); + Console.WriteLine(@"TestExe.exe /ec 1603 /Pinfo %temp%\Pinfo1.xml /s 1000 /log %temp%\log1.log /sr 5000-10000 /log %temp%\log2.log"); + Console.WriteLine(@""); + Console.WriteLine(@"This would result in the following execution:"); + Console.WriteLine(@" - Create an xml file with the current process info in it."); + Console.WriteLine(@" - Sleep 1 seconds"); + Console.WriteLine(@" - Create log1.log"); + Console.WriteLine(@" - Sleep between 5-10 seconds"); + Console.WriteLine(@" - Create log2.log"); + Console.WriteLine(@" - Exit with 1603"); + Console.WriteLine(@""); + } + } +} diff --git a/src/test/burn/TestExe/Task.cs b/src/test/burn/TestExe/Task.cs new file mode 100644 index 00000000..7d39bfd9 --- /dev/null +++ b/src/test/burn/TestExe/Task.cs @@ -0,0 +1,209 @@ +// 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. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using Microsoft.Win32; + +namespace TestExe +{ + public abstract class Task + { + public string data; + + public Task(string Data) + { + this.data = Data; + } + + public abstract void RunTask(); + + } + + public class ExitCodeTask : Task + { + public ExitCodeTask(string Data) : base(Data) { } + + public override void RunTask() + { + // this task does nothing. Just stores data about what exit code to return. + } + } + + public class SleepTask : Task + { + public SleepTask(string Data) : base(Data) { } + + public override void RunTask() + { + int milliseconds = int.Parse(this.data); + Console.WriteLine("Starting to sleep for {0} milliseconds", milliseconds); + System.Threading.Thread.Sleep(milliseconds); + } + } + + public class SleepRandomTask : Task + { + public SleepRandomTask(string Data) : base(Data) { } + + public override void RunTask() + { + int low = int.Parse(this.data.Split(new string[] { ":" }, 2, StringSplitOptions.None)[0]); + int high = int.Parse(this.data.Split(new string[] { ":" }, 2, StringSplitOptions.None)[1]); + + Random r = new Random(); + int milliseconds = r.Next(high - low) + low; + Console.WriteLine("Starting to sleep for {0} milliseconds", milliseconds); + System.Threading.Thread.Sleep(milliseconds); + } + } + + public class LargeFileTask : Task + { + public LargeFileTask(string Data) : base(Data) { } + + public override void RunTask() + { + string[] tokens = this.data.Split(new char[] { '|' }, 2); + string filePath = System.Environment.ExpandEnvironmentVariables(tokens[0]); + long size = long.Parse(tokens[1]); + using (var stream = File.Create(filePath)) + { + stream.Seek(size - 1, SeekOrigin.Begin); + stream.WriteByte(1); + } + } + } + + public class LogTask : Task + { + string[] argsUsed; + public LogTask(string Data, string[] args) + : base(Data) + { + this.argsUsed = args; + } + + public override void RunTask() + { + string logFile = ""; + string argsUsedString = ""; + + foreach (string a in this.argsUsed) + { + argsUsedString += a + " "; + } + + try + { + logFile = System.Environment.ExpandEnvironmentVariables(this.data); + Console.WriteLine("creating log file: " + logFile); + StreamWriter textFile = File.CreateText(logFile); + textFile.WriteLine("This is a log file created by TestExe.exe"); + textFile.WriteLine("Args used: " + argsUsedString); + textFile.Close(); + } + catch + { + Console.WriteLine("creating a log file failed for: {0}", logFile); + } + + } + } + + public class FileExistsTask : Task + { + public FileExistsTask(string Data) : base(Data) { } + + public override void RunTask() + { + string fileToExist = System.Environment.ExpandEnvironmentVariables(this.data); + + if (!String.IsNullOrEmpty(fileToExist)) + { + Console.WriteLine("Waiting for this file to exist: \"" + fileToExist + "\""); + while (!System.IO.File.Exists(fileToExist)) + { + System.Threading.Thread.Sleep(250); + } + Console.WriteLine("Found: \"" + fileToExist + "\""); + } + + } + } + + public class TaskParser + { + + public static List ParseTasks(string[] args) + { + List tasks = new List(); + + try + { + // for invalid args. return empty list + if (args.Length % 2 == 0) + { + Task t; + + for (int i = 0; i < args.Length; i += 2) + { + switch (args[i].ToLower()) + { + case "/ec": + t = new ExitCodeTask(args[i + 1]); + tasks.Add(t); + break; + case "/s": + t = new SleepTask(args[i + 1]); + tasks.Add(t); + break; + case "/sr": + t = new SleepRandomTask(args[i + 1]); + tasks.Add(t); + break; + case "/lf": + t = new LargeFileTask(args[i + 1]); + tasks.Add(t); + break; + case "/log": + t = new LogTask(args[i + 1], args); + tasks.Add(t); + break; + case "/fe": + t = new FileExistsTask(args[i + 1]); + tasks.Add(t); + break; +#if NET35 + case "/pinfo": + t = new ProcessInfoTask(args[i + 1]); + tasks.Add(t); + break; + case "/regw": + t = new RegistryWriterTask(args[i + 1]); + tasks.Add(t); + break; + case "/regd": + t = new RegistryDeleterTask(args[i + 1]); + tasks.Add(t); + break; +#endif + + default: + Console.WriteLine("Error: Invalid switch specified."); + return new List(); + } + } + } + } + catch + { + Console.WriteLine("Error: Invalid switch data specified. Couldn't parse the data."); + return new List(); + } + + return tasks; + } + } +} diff --git a/src/test/burn/TestExe/TestExe.csproj b/src/test/burn/TestExe/TestExe.csproj new file mode 100644 index 00000000..5a130422 --- /dev/null +++ b/src/test/burn/TestExe/TestExe.csproj @@ -0,0 +1,20 @@ + + + + + + net35;netcoreapp3.1 + TestExe + TestExe + Exe + embedded + win-x86 + false + true + Major + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestExe/TestExe_x64.csproj b/src/test/burn/TestExe/TestExe_x64.csproj new file mode 100644 index 00000000..1dd2d8e6 --- /dev/null +++ b/src/test/burn/TestExe/TestExe_x64.csproj @@ -0,0 +1,17 @@ + + + + + + net35 + TestExe + TestExe + Exe + embedded + win-x64 + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestExe/app.config b/src/test/burn/TestExe/app.config new file mode 100644 index 00000000..f9811b74 --- /dev/null +++ b/src/test/burn/TestExe/app.config @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/test/burn/Wix.Build.props b/src/test/burn/Wix.Build.props new file mode 100644 index 00000000..06cf5b1d --- /dev/null +++ b/src/test/burn/Wix.Build.props @@ -0,0 +1,11 @@ + + + + $([System.IO.Path]::GetFileName($([System.IO.Path]::GetDirectoryName($(MSBuildProjectDirectory))))) + $(BaseOutputPath)obj\$(TestGroupName)\$(ProjectName)\ + $(OutputPath)netcoreapp3.1\TestData\$(TestGroupName)\ + None + -wx + 1154;$(SuppressSpecificWarnings) + + diff --git a/src/test/burn/Wix.Build.targets b/src/test/burn/Wix.Build.targets new file mode 100644 index 00000000..17a46e2a --- /dev/null +++ b/src/test/burn/Wix.Build.targets @@ -0,0 +1,17 @@ + + + + + $(MSBuildProjectName) + $(MSBuildProjectName) + http://localhost:9999/e2e/ + TestGroupName=$(TestGroupName);PackageName=$(PackageName);BundleName=$(BundleName);WebServerBaseUrl=$(WebServerBaseUrl);$(DefineConstants) + BA=$(BA);$(DefineConstants) + CabPrefix=$(CabPrefix);$(DefineConstants) + SoftwareTag=1;$(DefineConstants) + ProductCode=$(ProductCode);$(DefineConstants) + ProductComponents=1;$(DefineConstants) + UpgradeCode=$(UpgradeCode);$(DefineConstants) + Version=$(Version);$(DefineConstants) + + diff --git a/src/test/burn/WixTestTools/BundleInstaller.cs b/src/test/burn/WixTestTools/BundleInstaller.cs new file mode 100644 index 00000000..a49c4024 --- /dev/null +++ b/src/test/burn/WixTestTools/BundleInstaller.cs @@ -0,0 +1,197 @@ +// 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. + +namespace WixTestTools +{ + using System; + using System.IO; + using System.Text; + + public partial class BundleInstaller : IDisposable + { + public BundleInstaller(WixTestContext testContext, string name) + { + this.Bundle = Path.Combine(testContext.TestDataFolder, $"{name}.exe"); + this.BundlePdb = Path.Combine(testContext.TestDataFolder, $"{name}.wixpdb"); + this.TestContext = testContext; + this.TestGroupName = testContext.TestGroupName; + this.TestName = testContext.TestName; + } + + public string Bundle { get; } + + private WixTestContext TestContext { get; } + + public string TestGroupName { get; } + + public string TestName { get; } + + /// + /// Installs the bundle with optional arguments. + /// + /// Expected exit code, defaults to success. + /// Optional arguments to pass to the tool. + /// Path to the generated log file. + public string Install(int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) + { + return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.Install, arguments); + } + + /// + /// Installs the bundle with optional arguments. + /// + /// This should be the bundle in the package cache. + /// Expected exit code, defaults to success. + /// Optional arguments to pass to the tool. + /// Path to the generated log file. + public string Install(string bundlePath, int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) + { + return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.Install, arguments, bundlePath: bundlePath); + } + + /// + /// Calls Layout for the bundle with optional arguments. + /// + /// The destination directory. + /// Expected exit code, defaults to success. + /// Optional arguments to pass to the tool. + /// Path to the generated log file. + public string Layout(string layoutDirectory, int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) + { + return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.AdministrativeInstall, arguments, layoutDirectory: layoutDirectory); + } + + /// + /// Calls Layout for the bundle with optional arguments. + /// + /// Path to the bundle to run. + /// The destination directory. + /// Expected exit code, defaults to success. + /// Optional arguments to pass to the tool. + /// Path to the generated log file. + public string Layout(string bundlePath, string layoutDirectory, int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) + { + return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.AdministrativeInstall, arguments, bundlePath: bundlePath, layoutDirectory: layoutDirectory); + } + + /// + /// Modify the bundle with optional arguments. + /// + /// Expected exit code, defaults to success. + /// Optional arguments to pass to the tool. + /// Path to the generated log file. + public string Modify(int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) + { + return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.Modify, arguments); + } + + /// + /// Modify the bundle with optional arguments. + /// + /// This should be the bundle in the package cache. + /// Expected exit code, defaults to success. + /// Optional arguments to pass to the tool. + /// Path to the generated log file. + public string Modify(string bundlePath, int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) + { + return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.Modify, arguments, bundlePath: bundlePath); + } + + /// + /// Repairs the bundle with optional arguments. + /// + /// Expected exit code, defaults to success. + /// Optional arguments to pass to the tool. + /// Path to the generated log file. + public string Repair(int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) + { + return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.Repair, arguments); + } + + /// + /// Uninstalls the bundle with optional arguments. + /// + /// Expected exit code, defaults to success. + /// Optional arguments to pass to the tool. + /// Path to the generated log file. + public string Uninstall(int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) + { + return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.Uninstall, arguments); + } + + /// + /// Uninstalls the bundle at the given path with optional arguments. + /// + /// This should be the bundle in the package cache. + /// Expected exit code, defaults to success. + /// Optional arguments to pass to the tool. + /// Path to the generated log file. + public string Uninstall(string bundlePath, int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) + { + return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.Uninstall, arguments, bundlePath: bundlePath); + } + + /// + /// Executes the bundle with optional arguments. + /// + /// Expected exit code. + /// Install mode. + /// Optional arguments to pass to the tool. + /// Path to the generated log file. + private string RunBundleWithArguments(int expectedExitCode, MSIExec.MSIExecMode mode, string[] arguments, bool assertOnError = true, string bundlePath = null, string layoutDirectory = null) + { + TestTool bundle = new TestTool(bundlePath ?? this.Bundle); + var sb = new StringBuilder(); + + // Be sure to run silent. + sb.Append(" -quiet"); + + // Generate the log file name. + string logFile = Path.Combine(Path.GetTempPath(), String.Format("{0}_{1}_{2:yyyyMMddhhmmss}_{4}_{3}.log", this.TestGroupName, this.TestName, DateTime.UtcNow, Path.GetFileNameWithoutExtension(this.Bundle), mode)); + sb.AppendFormat(" -log \"{0}\"", logFile); + + // Set operation. + switch (mode) + { + case MSIExec.MSIExecMode.AdministrativeInstall: + sb.Append($" -layout \"{layoutDirectory}\""); + break; + + case MSIExec.MSIExecMode.Modify: + sb.Append(" -modify"); + break; + + case MSIExec.MSIExecMode.Repair: + sb.Append(" -repair"); + break; + + case MSIExec.MSIExecMode.Cleanup: + case MSIExec.MSIExecMode.Uninstall: + sb.Append(" -uninstall"); + break; + } + + // Add additional arguments. + if (null != arguments) + { + sb.Append(" "); + sb.Append(String.Join(" ", arguments)); + } + + // Set the arguments. + bundle.Arguments = sb.ToString(); + + // Run the tool and assert the expected code. + bundle.ExpectedExitCode = expectedExitCode; + bundle.Run(assertOnError); + + // Return the log file name. + return logFile; + } + + public void Dispose() + { + string[] args = { "-burn.ignoredependencies=ALL" }; + this.RunBundleWithArguments((int)MSIExec.MSIExecReturnCode.SUCCESS, MSIExec.MSIExecMode.Cleanup, args, assertOnError: false); + } + } +} diff --git a/src/test/burn/WixTestTools/BundleRegistration.cs b/src/test/burn/WixTestTools/BundleRegistration.cs new file mode 100644 index 00000000..75660838 --- /dev/null +++ b/src/test/burn/WixTestTools/BundleRegistration.cs @@ -0,0 +1,182 @@ +// 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. + +namespace WixTestTools +{ + using System; + using Microsoft.Win32; + + public class BundleRegistration + { + public const string BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; + public const string BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY_WOW6432NODE = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH = "BundleCachePath"; + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_ADDON_CODE = "BundleAddonCode"; + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_DETECT_CODE = "BundleDetectCode"; + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE = "BundlePatchCode"; + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE = "BundleUpgradeCode"; + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_DISPLAY_NAME = "DisplayName"; + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION = "BundleVersion"; + public const string BURN_REGISTRATION_REGISTRY_ENGINE_VERSION = "EngineVersion"; + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY = "BundleProviderKey"; + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_TAG = "BundleTag"; + public const string REGISTRY_REBOOT_PENDING_FORMAT = "{0}.RebootRequired"; + public const string REGISTRY_BUNDLE_INSTALLED = "Installed"; + public const string REGISTRY_BUNDLE_DISPLAY_ICON = "DisplayIcon"; + public const string REGISTRY_BUNDLE_DISPLAY_VERSION = "DisplayVersion"; + public const string REGISTRY_BUNDLE_ESTIMATED_SIZE = "EstimatedSize"; + public const string REGISTRY_BUNDLE_PUBLISHER = "Publisher"; + public const string REGISTRY_BUNDLE_HELP_LINK = "HelpLink"; + public const string REGISTRY_BUNDLE_HELP_TELEPHONE = "HelpTelephone"; + public const string REGISTRY_BUNDLE_URL_INFO_ABOUT = "URLInfoAbout"; + public const string REGISTRY_BUNDLE_URL_UPDATE_INFO = "URLUpdateInfo"; + public const string REGISTRY_BUNDLE_PARENT_DISPLAY_NAME = "ParentDisplayName"; + public const string REGISTRY_BUNDLE_PARENT_KEY_NAME = "ParentKeyName"; + public const string REGISTRY_BUNDLE_COMMENTS = "Comments"; + public const string REGISTRY_BUNDLE_CONTACT = "Contact"; + public const string REGISTRY_BUNDLE_NO_MODIFY = "NoModify"; + public const string REGISTRY_BUNDLE_MODIFY_PATH = "ModifyPath"; + public const string REGISTRY_BUNDLE_NO_ELEVATE_ON_MODIFY = "NoElevateOnModify"; + public const string REGISTRY_BUNDLE_NO_REMOVE = "NoRemove"; + public const string REGISTRY_BUNDLE_SYSTEM_COMPONENT = "SystemComponent"; + public const string REGISTRY_BUNDLE_QUIET_UNINSTALL_STRING = "QuietUninstallString"; + public const string REGISTRY_BUNDLE_UNINSTALL_STRING = "UninstallString"; + public const string REGISTRY_BUNDLE_RESUME_COMMAND_LINE = "BundleResumeCommandLine"; + public const string REGISTRY_BUNDLE_VERSION_MAJOR = "VersionMajor"; + public const string REGISTRY_BUNDLE_VERSION_MINOR = "VersionMinor"; + + public string[] AddonCodes { get; set; } + + public string CachePath { get; set; } + + public string DisplayName { get; set; } + + public string[] DetectCodes { get; set; } + + public string EngineVersion { get; set; } + + public int? EstimatedSize { get; set; } + + public int? Installed { get; set; } + + public string ModifyPath { get; set; } + + public string[] PatchCodes { get; set; } + + public string ProviderKey { get; set; } + + public string Publisher { get; set; } + + public string QuietUninstallString { get; set; } + + public string QuietUninstallCommand { get; set; } + + public string QuietUninstallCommandArguments { get; set; } + + public string Tag { get; set; } + + public string UninstallCommand { get; set; } + + public string UninstallCommandArguments { get; set; } + + public string UninstallString { get; set; } + + public string[] UpgradeCodes { get; set; } + + public string UrlInfoAbout { get; set; } + + public string UrlUpdateInfo { get; set; } + + public string Version { get; set; } + + public static bool TryGetPerMachineBundleRegistrationById(string bundleId, bool x64, out BundleRegistration registration) + { + var baseKeyPath = x64 ? BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY : BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY_WOW6432NODE; + var registrationKeyPath = $"{baseKeyPath}\\{bundleId}"; + using var registrationKey = Registry.LocalMachine.OpenSubKey(registrationKeyPath); + var success = registrationKey != null; + registration = success ? GetBundleRegistration(registrationKey) : null; + return success; + } + + public static bool TryGetPerUserBundleRegistrationById(string bundleId, out BundleRegistration registration) + { + var registrationKeyPath = $"{BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY}\\{bundleId}"; + using var registrationKey = Registry.CurrentUser.OpenSubKey(registrationKeyPath); + var success = registrationKey != null; + registration = success ? GetBundleRegistration(registrationKey) : null; + return success; + } + + private static BundleRegistration GetBundleRegistration(RegistryKey idKey) + { + var registration = new BundleRegistration(); + + registration.AddonCodes = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_ADDON_CODE) as string[]; + registration.CachePath = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH) as string; + registration.DetectCodes = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_DETECT_CODE) as string[]; + registration.PatchCodes = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE) as string[]; + registration.ProviderKey = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY) as string; + registration.Tag = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_TAG) as string; + registration.UpgradeCodes = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE) as string[]; + registration.Version = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION) as string; + registration.DisplayName = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_DISPLAY_NAME) as string; + registration.EngineVersion = idKey.GetValue(BURN_REGISTRATION_REGISTRY_ENGINE_VERSION) as string; + registration.EstimatedSize = idKey.GetValue(REGISTRY_BUNDLE_ESTIMATED_SIZE) as int?; + registration.Installed = idKey.GetValue(REGISTRY_BUNDLE_INSTALLED) as int?; + registration.ModifyPath = idKey.GetValue(REGISTRY_BUNDLE_MODIFY_PATH) as string; + registration.Publisher = idKey.GetValue(REGISTRY_BUNDLE_PUBLISHER) as string; + registration.UrlInfoAbout = idKey.GetValue(REGISTRY_BUNDLE_URL_INFO_ABOUT) as string; + registration.UrlUpdateInfo = idKey.GetValue(REGISTRY_BUNDLE_URL_UPDATE_INFO) as string; + + registration.QuietUninstallString = idKey.GetValue(REGISTRY_BUNDLE_QUIET_UNINSTALL_STRING) as string; + if (!String.IsNullOrEmpty(registration.QuietUninstallString)) + { + var closeQuote = registration.QuietUninstallString.IndexOf("\"", 1); + if (closeQuote > 0) + { + registration.QuietUninstallCommand = registration.QuietUninstallString.Substring(1, closeQuote - 1).Trim(); + registration.QuietUninstallCommandArguments = registration.QuietUninstallString.Substring(closeQuote + 1).Trim(); + } + } + + registration.UninstallString = idKey.GetValue(REGISTRY_BUNDLE_UNINSTALL_STRING) as string; + if (!String.IsNullOrEmpty(registration.UninstallString)) + { + var closeQuote = registration.UninstallString.IndexOf("\"", 1); + if (closeQuote > 0) + { + registration.UninstallCommand = registration.UninstallString.Substring(1, closeQuote - 1).Trim(); + registration.UninstallCommandArguments = registration.UninstallString.Substring(closeQuote + 1).Trim(); + } + } + + return registration; + } + + public static bool TryGetDependencyProviderValue(string providerId, string name, out string value) + { + value = null; + + string key = String.Format(@"Installer\Dependencies\{0}", providerId); + using (RegistryKey providerKey = Registry.ClassesRoot.OpenSubKey(key)) + { + if (null == providerKey) + { + return false; + } + + value = providerKey.GetValue(name) as string; + return value != null; + } + } + + public static bool DependencyDependentExists(string providerId, string dependentId) + { + string key = String.Format(@"Installer\Dependencies\{0}\Dependents\{1}", providerId, dependentId); + using (RegistryKey dependentKey = Registry.ClassesRoot.OpenSubKey(key)) + { + return null != dependentKey; + } + } + } +} diff --git a/src/test/burn/WixTestTools/BundleVerifier.cs b/src/test/burn/WixTestTools/BundleVerifier.cs new file mode 100644 index 00000000..984df169 --- /dev/null +++ b/src/test/burn/WixTestTools/BundleVerifier.cs @@ -0,0 +1,156 @@ +// 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. + +namespace WixTestTools +{ + using System; + using System.IO; + using System.Linq; + using System.Text; + using Microsoft.Win32; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using Xunit; + + public partial class BundleInstaller + { + public const string FULL_BURN_POLICY_REGISTRY_PATH = "SOFTWARE\\WOW6432Node\\Policies\\WiX\\Burn"; + public const string PACKAGE_CACHE_FOLDER_NAME = "Package Cache"; + + public string BundlePdb { get; } + + private WixBundleSymbol BundleSymbol { get; set; } + + private WixBundleSymbol GetBundleSymbol() + { + if (this.BundleSymbol == null) + { + using var wixOutput = WixOutput.Read(this.BundlePdb); + var intermediate = Intermediate.Load(wixOutput); + var section = intermediate.Sections.Single(); + this.BundleSymbol = section.Symbols.OfType().Single(); + } + + return this.BundleSymbol; + } + + public string GetPackageCachePathForCacheId(string cacheId, bool perMachine) + { + string cachePath; + if (perMachine) + { + using var policyKey = Registry.LocalMachine.OpenSubKey(FULL_BURN_POLICY_REGISTRY_PATH); + var redirectedCachePath = policyKey?.GetValue("PackageCache") as string; + cachePath = redirectedCachePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), PACKAGE_CACHE_FOLDER_NAME); + } + else + { + cachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), PACKAGE_CACHE_FOLDER_NAME); + } + return Path.Combine(cachePath, cacheId); + } + + public string GetExpectedCachedBundlePath() + { + var bundleSymbol = this.GetBundleSymbol(); + var cachePath = this.GetPackageCachePathForCacheId(bundleSymbol.BundleId, bundleSymbol.PerMachine); + return Path.Combine(cachePath, Path.GetFileName(this.Bundle)); + } + + public string ManuallyCache() + { + var expectedCachePath = this.GetExpectedCachedBundlePath(); + Directory.CreateDirectory(Path.GetDirectoryName(expectedCachePath)); + File.Copy(this.Bundle, expectedCachePath); + return expectedCachePath; + } + + public void ManuallyUncache() + { + var expectedCachePath = this.GetExpectedCachedBundlePath(); + File.Delete(expectedCachePath); + } + + public bool TryGetRegistration(out BundleRegistration registration) + { + var bundleSymbol = this.GetBundleSymbol(); + var x64 = bundleSymbol.Platform != Platform.X86; + var bundleId = bundleSymbol.BundleId; + if (bundleSymbol.PerMachine) + { + return BundleRegistration.TryGetPerMachineBundleRegistrationById(bundleId, x64, out registration); + } + else + { + return BundleRegistration.TryGetPerUserBundleRegistrationById(bundleId, out registration); + } + } + + public string VerifyRegisteredAndInPackageCache() + { + Assert.True(this.TryGetRegistration(out var registration)); + + Assert.NotNull(registration.CachePath); + Assert.True(File.Exists(registration.CachePath)); + + var expectedCachePath = this.GetExpectedCachedBundlePath(); + Assert.Equal(expectedCachePath, registration.CachePath, StringComparer.OrdinalIgnoreCase); + + return registration.CachePath; + } + + public void VerifyUnregisteredAndRemovedFromPackageCache() + { + var cachedBundlePath = this.GetExpectedCachedBundlePath(); + this.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath); + } + + public void VerifyUnregisteredAndRemovedFromPackageCache(string cachedBundlePath) + { + Assert.False(this.TryGetRegistration(out _)); + Assert.False(File.Exists(cachedBundlePath)); + } + + public void RemovePackageFromCache(string packageId) + { + using var wixOutput = WixOutput.Read(this.BundlePdb); + var intermediate = Intermediate.Load(wixOutput); + var section = intermediate.Sections.Single(); + var packageSymbol = section.Symbols.OfType().Single(p => p.Id.Id == packageId); + var cachePath = this.GetPackageCachePathForCacheId(packageSymbol.CacheId, packageSymbol.PerMachine == YesNoDefaultType.Yes); + if (Directory.Exists(cachePath)) + { + Directory.Delete(cachePath, true); + } + } + + public void VerifyPackageIsCached(string packageId) + { + using var wixOutput = WixOutput.Read(this.BundlePdb); + var intermediate = Intermediate.Load(wixOutput); + var section = intermediate.Sections.Single(); + var packageSymbol = section.Symbols.OfType().Single(p => p.Id.Id == packageId); + var cachePath = this.GetPackageCachePathForCacheId(packageSymbol.CacheId, packageSymbol.PerMachine == YesNoDefaultType.Yes); + Assert.True(Directory.Exists(cachePath)); + } + + public void VerifyExeTestRegistryRootDeleted(string name, bool x64 = false) + { + using var testRegistryRoot = this.TestContext.GetTestRegistryRoot(x64, name); + if (testRegistryRoot != null) + { + var actualValue = testRegistryRoot.GetValue("Version") as string; + Assert.Null(actualValue); + } + } + + public void VerifyExeTestRegistryValue(string name, string expectedValue, bool x64 = false) + { + using (var root = this.TestContext.GetTestRegistryRoot(x64, name)) + { + Assert.NotNull(root); + var actualValue = root.GetValue("Version") as string; + Assert.Equal(expectedValue, actualValue); + } + } + } +} diff --git a/src/test/burn/WixTestTools/LogVerifier.cs b/src/test/burn/WixTestTools/LogVerifier.cs new file mode 100644 index 00000000..0252a9f9 --- /dev/null +++ b/src/test/burn/WixTestTools/LogVerifier.cs @@ -0,0 +1,252 @@ +// 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. + +namespace WixTestTools +{ + using System; + using System.IO; + using System.Text; + using System.Text.RegularExpressions; + using Xunit; + + /// + /// The LogVerifier can verify a log file for given regular expressions. + /// + public class LogVerifier + { + // Member Variables + private string logFile; + + /// + /// Prevent creation of LogVerifier without log file + /// + private LogVerifier() + { } + + /// + /// Constructor for log files where the exact file name is known. + /// + /// The full path to the log file + public LogVerifier(string fileName) + { + if (null == fileName) + throw new ArgumentNullException("fileName"); + + if (!File.Exists(fileName)) + throw new ArgumentException(String.Format(@"File doesn't exist:{0}", fileName), "fileName"); + + logFile = fileName; + } + + /// + /// Constructor for log files where the exact file name is known. + /// + /// The directory in which the log file is located. + /// The name of the log file. + public LogVerifier(string directory, string fileName) + : this(Path.Combine(directory, fileName)) + { } + + /// + /// Scans a log file line by line until the regex pattern is matched or eof is reached. + /// This method would be used in the case where the log file is very large, the regex doesn't + /// span multiple lines, and only one match is required. + /// + /// A regular expression + /// True if a match is found, False otherwise. + public bool LineByLine(Regex regex) + { + string line = string.Empty; + StreamReader sr = new StreamReader(logFile); + + // Read from a file stream line by line. + while ((line = sr.ReadLine()) != null) + { + if (regex.Match(line).Success) + { + sr.Close(); + sr.Dispose(); + return true; + } + } + return false; + } + + + /// + /// Scans a log file line by line until the regex pattern is matched or eof is reached. + /// This method would be used in the case where the log file is very large, the regex doesn't + /// span multiple lines, and only one match is required. + /// No RegexOptions are used and matches are case sensitive. + /// + /// A regular expression string. + /// True if a match is found, False otherwise. + public bool LineByLine(string regex) + { + return LineByLine(new Regex(regex)); + } + + + /// + /// Scans a log file for matches to the regex. + /// + /// A regular expression + /// The number of matches + public int EntireFileAtOnce(Regex regex) + { + string logFileText = this.ReadLogFile(); + return regex.Matches(logFileText).Count; + } + + /// + /// Scans a log file for matches to the regex. + /// + /// A regular expression + /// The number of matches + public bool EntireFileAtOncestr(string regex) + { + string logFileText = this.ReadLogFile(); + return logFileText.Contains(regex); + } + /// + /// Scans a log file for matches to the regex string. + /// Only the Multiline RegexOption is used and matches are case sensitive. + /// + /// A regular expression + /// The number of matches + public int EntireFileAtOnce(string regex) + { + return EntireFileAtOnce(new Regex(regex, RegexOptions.Multiline)); + } + + /// + /// Scans a log file for matches to the regex string. + /// + /// A regular expression + /// Specify whether to perform case sensitive matches + /// The number of matches + public int EntireFileAtOnce(string regex, bool ignoreCase) + { + if (!ignoreCase) + return EntireFileAtOnce(new Regex(regex, RegexOptions.Multiline)); + else + return EntireFileAtOnce(new Regex(regex, RegexOptions.Multiline | RegexOptions.IgnoreCase)); + } + + /// + /// Search through the log and Assert.Fail() if a specified string is not found. + /// + /// Search expression + /// Perform case insensitive match + public void AssertTextInLog(string regex, bool ignoreCase) + { + Assert.True(EntireFileAtOncestr(regex), + String.Format("The log does not contain a match to the regular expression \"{0}\" ", regex)); + } + + /// + /// Search through the log and Assert.Fail() if a specified string is not found. + /// + /// Search expression + /// Perform case insensitive match + public void AssertTextInLog(Regex regex, bool ignoreCase) + { + Assert.True(EntireFileAtOnce(regex) >= 1, + String.Format("The log does not contain a match to the regular expression \"{0}\" ", regex.ToString())); + } + + /// + /// Search through the log and Assert.Fail() if a specified string is not found. + /// + /// Search expression + /// Perform case insensitive match + public void AssertTextInLog(string regex) + { + AssertTextInLog(regex, true); + } + + /// + /// Search through the log and Assert.Fail() if a specified string is not found. + /// + /// Search expression + /// Perform case insensitive match + public void AssertTextInLog(Regex regex) + { + AssertTextInLog(regex, true); + } + + + /// + /// Search through the log and Assert.Fail() if a specified string is found. + /// + /// Search expression + /// Perform case insensitive match + public void AssertTextNotInLog(Regex regex, bool ignoreCase) + { + Assert.True(EntireFileAtOnce(regex) < 1, + String.Format("The log contain a match to the regular expression \"{0}\" ", regex.ToString())); + } + + /// + /// Search through the log and Assert.Fail() if a specified string is not found. + /// + /// Search expression + /// Perform case insensitive match + public void AssertTextNotInLog(string regex, bool ignoreCase) + { + Assert.False(EntireFileAtOncestr(regex), + String.Format("The log does not contain a match to the regular expression \"{0}\" ", regex)); + } + + /// + /// Checks if a meesage is in a file + /// + /// The full path to the log file + /// Search expression + /// True if the message was found, false otherwise + public static bool MessageInLogFile(string logFileName, string message) + { + LogVerifier logVerifier = new LogVerifier(logFileName); + return logVerifier.EntireFileAtOncestr(message); + } + + /// + /// Checks if a meesage is in a file + /// + /// The full path to the log file + /// Search expression (regex) + /// True if the message was found, false otherwise + public static bool MessageInLogFileRegex(string logFileName, string regexMessage) + { + LogVerifier logVerifier = new LogVerifier(logFileName); + return logVerifier.EntireFileAtOnce(regexMessage) > 0; + } + + /// + /// Read in the entire log file at once. + /// + /// Contents of log file. + private string ReadLogFile() + { + // Retry a few times. + for (int retry = 0; ; ++retry) + { + try + { + using (StreamReader sr = new StreamReader(this.logFile)) + { + return sr.ReadToEnd(); + } + } + catch // we'll catch everything a few times until we give up. + { + if (retry > 4) + { + throw; + } + + System.Threading.Thread.Sleep(1000); + } + } + } + } +} diff --git a/src/test/burn/WixTestTools/MSIExec.cs b/src/test/burn/WixTestTools/MSIExec.cs new file mode 100644 index 00000000..8dce96cf --- /dev/null +++ b/src/test/burn/WixTestTools/MSIExec.cs @@ -0,0 +1,753 @@ +// 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. + +namespace WixTestTools +{ + using System; + using System.IO; + using System.Text; + using WixBuildTools.TestSupport; + + public class MSIExec : TestTool + { + /// + /// The expected exit code of the tool + /// + public new MSIExecReturnCode ExpectedExitCode + { + get { return (MSIExecReturnCode)base.ExpectedExitCode; } + set { base.ExpectedExitCode = (int?)value; } + } + + /// + /// Mode of execution (install, uninstall, or repair) + /// + public MSIExecMode ExecutionMode { get; set; } + + /// + /// Path to msi or ProductCode + /// + public string Product { get; set; } + + /// + /// Logging Options + /// + public MSIExecLoggingOptions LoggingOptions { get; set; } + + /// + /// Path to the log file + /// + public string LogFile { get; set; } + + /// + /// Unattended mode - progress bar only + /// + public bool Passive { get; set; } + + /// + /// Quiet mode, no user interaction + /// + public bool Quiet { get; set; } + + /// + /// Sets user interface level + /// + public MSIExecUserInterfaceLevel UserInterfaceLevel { get; set; } + + /// + /// Do not restart after the installation is complete + /// + public bool NoRestart { get; set; } + + /// + /// Prompts the user for restart if necessary + /// + public bool PromptRestart { get; set; } + + /// + /// Always restart the computer after installation + /// + public bool ForceRestart { get; set; } + + /// + /// Other arguments. + /// + public string OtherArguments { get; set; } + + /// + /// Constructor that uses the default location for MSIExec. + /// + public MSIExec() + : this(Environment.SystemDirectory) + { + } + + /// + /// Constructor that accepts a path to the MSIExec location. + /// + /// The directory of MSIExec.exe. + public MSIExec(string toolDirectory) + : base(Path.Combine(toolDirectory, "MSIExec.exe")) + { + this.SetDefaultArguments(); + } + + public override ExternalExecutableResult Run(bool assertOnError) + { + this.Arguments = this.GetArguments(); + return base.Run(assertOnError); + } + + /// + /// Clears all of the assigned arguments and resets them to the default values. + /// + public void SetDefaultArguments() + { + this.ExecutionMode = MSIExecMode.Install; + this.Product = String.Empty; + this.Quiet = true; + this.Passive = false; + this.UserInterfaceLevel = MSIExecUserInterfaceLevel.None; + this.NoRestart = true; + this.ForceRestart = false; + this.PromptRestart = false; + this.LogFile = string.Empty; + this.LoggingOptions = MSIExecLoggingOptions.VOICEWARMUP; + this.OtherArguments = String.Empty; + } + + public string GetArguments() + { + var arguments = new StringBuilder(); + + // quiet + if (this.Quiet) + { + arguments.Append(" /quiet "); + } + + // passive + if (this.Passive) + { + arguments.Append(" /passive "); + } + + // UserInterfaceLevel + switch (this.UserInterfaceLevel) + { + case MSIExecUserInterfaceLevel.None: + arguments.Append(" /qn "); + break; + case MSIExecUserInterfaceLevel.Basic: + arguments.Append(" /qb "); + break; + case MSIExecUserInterfaceLevel.Reduced: + arguments.Append(" /qr "); + break; + case MSIExecUserInterfaceLevel.Full: + arguments.Append(" /qf "); + break; + } + + // NoRestart + if (this.NoRestart) + { + arguments.Append(" /norestart "); + } + + // PromptRestart + if (this.PromptRestart) + { + arguments.Append(" /promptrestart "); + } + + // ForceRestart + if (this.ForceRestart) + { + arguments.Append(" /forcerestart "); + } + + // Logging options + var loggingOptionsString = new StringBuilder(); + if ((this.LoggingOptions & MSIExecLoggingOptions.Status_Messages) == MSIExecLoggingOptions.Status_Messages) + { + loggingOptionsString.Append("i"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.Nonfatal_Warnings) == MSIExecLoggingOptions.Nonfatal_Warnings) + { + loggingOptionsString.Append("w"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.All_Error_Messages) == MSIExecLoggingOptions.All_Error_Messages) + { + loggingOptionsString.Append("e"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.Start_Up_Of_Actions) == MSIExecLoggingOptions.Start_Up_Of_Actions) + { + loggingOptionsString.Append("a"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.Action_Specific_Records) == MSIExecLoggingOptions.Action_Specific_Records) + { + loggingOptionsString.Append("r"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.User_Requests) == MSIExecLoggingOptions.User_Requests) + { + loggingOptionsString.Append("u"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.Initial_UI_Parameters) == MSIExecLoggingOptions.Initial_UI_Parameters) + { + loggingOptionsString.Append("c"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.OutOfMemory_Or_Fatal_Exit_Information) == MSIExecLoggingOptions.OutOfMemory_Or_Fatal_Exit_Information) + { + loggingOptionsString.Append("m"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.OutOfDiskSpace_Messages) == MSIExecLoggingOptions.OutOfDiskSpace_Messages) + { + loggingOptionsString.Append("o"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.Terminal_Properties) == MSIExecLoggingOptions.Terminal_Properties) + { + loggingOptionsString.Append("p"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.Verbose_Output) == MSIExecLoggingOptions.Verbose_Output) + { + loggingOptionsString.Append("v"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.Extra_Debugging_Information) == MSIExecLoggingOptions.Extra_Debugging_Information) + { + loggingOptionsString.Append("x"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.Append_To_Existing_Log_File) == MSIExecLoggingOptions.Append_To_Existing_Log_File) + { + loggingOptionsString.Append("+"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.Flush_Each_line) == MSIExecLoggingOptions.Flush_Each_line) + { + loggingOptionsString.Append("!"); + } + if ((this.LoggingOptions & MSIExecLoggingOptions.Log_All_Information) == MSIExecLoggingOptions.Log_All_Information) + { + loggingOptionsString.Append("*"); + } + + // logfile and logging options + if (0 != loggingOptionsString.Length || !string.IsNullOrEmpty(this.LogFile)) + { + arguments.Append(" /l"); + if (0 != loggingOptionsString.Length) + { + arguments.AppendFormat("{0} ", loggingOptionsString); + } + if (!string.IsNullOrEmpty(this.LogFile)) + { + arguments.AppendFormat(" \"{0}\" ", this.LogFile); + } + } + + // OtherArguments + if (!String.IsNullOrEmpty(this.OtherArguments)) + { + arguments.AppendFormat(" {0} ", this.OtherArguments); + } + + // execution mode + switch (this.ExecutionMode) + { + case MSIExecMode.Install: + arguments.Append(" /package "); + break; + case MSIExecMode.AdministrativeInstall: + arguments.Append(" /a "); + break; + case MSIExecMode.Repair: + arguments.Append(" /f "); + break; + case MSIExecMode.Cleanup: + case MSIExecMode.Uninstall: + arguments.Append(" /uninstall "); + break; + }; + + // product + if (!string.IsNullOrEmpty(this.Product)) + { + arguments.AppendFormat(" \"{0}\" ", this.Product); + } + + return arguments.ToString(); + } + + /// + /// Return codes from an MSI install or uninstall + /// + /// + /// Error codes indicative of success are: + /// ERROR_SUCCESS, ERROR_SUCCESS_REBOOT_INITIATED, and ERROR_SUCCESS_REBOOT_REQUIRED + /// + public enum MSIExecReturnCode + { + /// + /// ERROR_SUCCESS 0 + /// Action completed successfully. + /// + SUCCESS = 0, + + /// + /// ERROR_INVALID_DATA 13 + /// The data is invalid. + /// + ERROR_INVALID_DATA = 13, + + /// + /// ERROR_INVALID_PARAMETER 87 + /// One of the parameters was invalid. + /// + ERROR_INVALID_PARAMETER = 87, + + /// + /// ERROR_CALL_NOT_IMPLEMENTED 120 + /// This value is returned when a custom action attempts to call a function that cannot be called from custom actions. + /// The function returns the value ERROR_CALL_NOT_IMPLEMENTED. Available beginning with Windows Installer version 3.0. + /// + ERROR_CALL_NOT_IMPLEMENTED = 120, + + /// + /// ERROR_APPHELP_BLOCK 1259 + /// If Windows Installer determines a product may be incompatible with the current operating system, + /// it displays a dialog box informing the user and asking whether to try to install anyway. + /// This error code is returned if the user chooses not to try the installation. + /// + ERROR_APPHELP_BLOCK = 1259, + + /// + /// ERROR_INSTALL_SERVICE_FAILURE 1601 + /// The Windows Installer service could not be accessed. + /// Contact your support personnel to verify that the Windows Installer service is properly registered. + /// + ERROR_INSTALL_SERVICE_FAILURE = 1601, + + + /// + /// ERROR_INSTALL_USEREXIT 1602 + /// The user cancels installation. + /// + ERROR_INSTALL_USEREXIT = 1602, + + /// + /// ERROR_INSTALL_FAILURE 1603 + /// A fatal error occurred during installation. + /// + ERROR_INSTALL_FAILURE = 1603, + + /// + /// ERROR_INSTALL_SUSPEND 1604 + /// Installation suspended, incomplete. + /// + ERROR_INSTALL_SUSPEND = 1604, + + /// + /// ERROR_UNKNOWN_PRODUCT 1605 + /// This action is only valid for products that are currently installed. + /// + ERROR_UNKNOWN_PRODUCT = 1605, + + /// + /// ERROR_UNKNOWN_FEATURE 1606 + /// The feature identifier is not registered. + /// + ERROR_UNKNOWN_FEATURE = 1606, + + /// + /// ERROR_UNKNOWN_COMPONENT 1607 + /// The component identifier is not registered. + /// + ERROR_UNKNOWN_COMPONENT = 1607, + + /// + /// ERROR_UNKNOWN_PROPERTY 1608 + /// This is an unknown property. + /// + ERROR_UNKNOWN_PROPERTY = 1608, + + /// + /// ERROR_INVALID_HANDLE_STATE 1609 + /// The handle is in an invalid state. + /// + ERROR_INVALID_HANDLE_STATE = 1609, + + /// + /// ERROR_BAD_CONFIGURATION 1610 + /// The configuration data for this product is corrupt. Contact your support personnel. + /// + ERROR_BAD_CONFIGURATION = 1610, + + /// + /// ERROR_INDEX_ABSENT 1611 + /// The component qualifier not present. + /// + ERROR_INDEX_ABSENT = 1611, + + /// ERROR_INSTALL_SOURCE_ABSENT 1612 + /// The installation source for this product is not available. + /// Verify that the source exists and that you can access it. + /// + ERROR_INSTALL_SOURCE_ABSENT = 1612, + + /// + /// ERROR_INSTALL_PACKAGE_VERSION 1613 + /// This installation package cannot be installed by the Windows Installer service. + /// You must install a Windows service pack that contains a newer version of the Windows Installer service. + /// + ERROR_INSTALL_PACKAGE_VERSION = 1613, + + /// + /// ERROR_PRODUCT_UNINSTALLED 1614 + /// The product is uninstalled. + /// + ERROR_PRODUCT_UNINSTALLED = 1614, + + /// + /// ERROR_BAD_QUERY_SYNTAX 1615 + /// The SQL query syntax is invalid or unsupported. + /// + ERROR_BAD_QUERY_SYNTAX = 1615, + + /// + /// ERROR_INVALID_FIELD 1616 + /// The record field does not exist. + /// + ERROR_INVALID_FIELD = 1616, + + /// + /// ERROR_INSTALL_ALREADY_RUNNING 1618 + /// Another installation is already in progress. Complete that installation before proceeding with this install. + /// For information about the mutex, see _MSIExecute Mutex. + /// + ERROR_INSTALL_ALREADY_RUNNING = 1618, + + /// + /// ERROR_INSTALL_PACKAGE_OPEN_FAILED 1619 + /// This installation package could not be opened. Verify that the package exists and is accessible, or contact the + /// application vendor to verify that this is a valid Windows Installer package. + /// + ERROR_INSTALL_PACKAGE_OPEN_FAILED = 1619, + + + /// + /// ERROR_INSTALL_PACKAGE_INVALID 1620 + /// This installation package could not be opened. + /// Contact the application vendor to verify that this is a valid Windows Installer package. + /// + ERROR_INSTALL_PACKAGE_INVALID = 1620, + + /// + /// ERROR_INSTALL_UI_FAILURE 1621 + /// There was an error starting the Windows Installer service user interface. + /// Contact your support personnel. + /// + ERROR_INSTALL_UI_FAILURE = 1621, + + /// + /// ERROR_INSTALL_LOG_FAILURE 1622 + /// There was an error opening installation log file. + /// Verify that the specified log file location exists and is writable. + /// + ERROR_INSTALL_LOG_FAILURE = 1622, + + /// + /// ERROR_INSTALL_LANGUAGE_UNSUPPORTED 1623 + /// This language of this installation package is not supported by your system. + /// + ERROR_INSTALL_LANGUAGE_UNSUPPORTED = 1623, + + /// + /// ERROR_INSTALL_TRANSFORM_FAILURE 1624 + /// There was an error applying transforms. + /// Verify that the specified transform paths are valid. + /// + ERROR_INSTALL_TRANSFORM_FAILURE = 1624, + + + /// + /// ERROR_INSTALL_PACKAGE_REJECTED 1625 + /// This installation is forbidden by system policy. + /// Contact your system administrator. + /// + ERROR_INSTALL_PACKAGE_REJECTED = 1625, + + /// + /// ERROR_FUNCTION_NOT_CALLED 1626 + /// The function could not be executed. + /// + ERROR_FUNCTION_NOT_CALLED = 1626, + + /// + /// ERROR_FUNCTION_FAILED 1627 + /// The function failed during execution. + /// + ERROR_FUNCTION_FAILED = 1627, + + /// + /// ERROR_INVALID_TABLE 1628 + /// An invalid or unknown table was specified. + /// + ERROR_INVALID_TABLE = 1628, + + /// + /// ERROR_DATATYPE_MISMATCH 1629 + /// The data supplied is the wrong type. + /// + ERROR_DATATYPE_MISMATCH = 1629, + + /// + /// ERROR_UNSUPPORTED_TYPE 1630 + /// Data of this type is not supported. + /// + ERROR_UNSUPPORTED_TYPE = 1630, + + /// + /// ERROR_CREATE_FAILED 1631 + /// The Windows Installer service failed to start. + /// Contact your support personnel. + /// + ERROR_CREATE_FAILED = 1631, + + /// + /// ERROR_INSTALL_TEMP_UNWRITABLE 1632 + /// The Temp folder is either full or inaccessible. + /// Verify that the Temp folder exists and that you can write to it. + /// + ERROR_INSTALL_TEMP_UNWRITABLE = 1632, + + /// + /// ERROR_INSTALL_PLATFORM_UNSUPPORTED 1633 + /// This installation package is not supported on this platform. Contact your application vendor. + ERROR_INSTALL_PLATFORM_UNSUPPORTED = 1633, + + /// + /// ERROR_INSTALL_NOTUSED 1634 + /// Component is not used on this machine. + /// + ERROR_INSTALL_NOTUSED = 1634, + + /// + /// ERROR_PATCH_PACKAGE_OPEN_FAILED 1635 + /// This patch package could not be opened. Verify that the patch package exists and is accessible, + /// or contact the application vendor to verify that this is a valid Windows Installer patch package. + /// + ERROR_PATCH_PACKAGE_OPEN_FAILED = 1635, + + /// + /// ERROR_PATCH_PACKAGE_INVALID 1636 + /// This patch package could not be opened. + /// Contact the application vendor to verify that this is a valid Windows Installer patch package. + /// + ERROR_PATCH_PACKAGE_INVALID = 1636, + + /// + /// ERROR_PATCH_PACKAGE_UNSUPPORTED 1637 + /// This patch package cannot be processed by the Windows Installer service. + /// You must install a Windows service pack that contains a newer version of the Windows Installer service. + /// + ERROR_PATCH_PACKAGE_UNSUPPORTED = 1637, + + /// + /// ERROR_PRODUCT_VERSION 1638 + /// Another version of this product is already installed. + /// Installation of this version cannot continue. To configure or remove the existing version of this product, + /// use Add/Remove Programs in Control Panel. + /// + ERROR_PRODUCT_VERSION = 1638, + + /// + /// ERROR_INVALID_COMMAND_LINE 1639 + /// Invalid command line argument. + /// Consult the Windows Installer SDK for detailed command-line help. + /// + ERROR_INVALID_COMMAND_LINE = 1639, + + /// + /// ERROR_INSTALL_REMOTE_DISALLOWED 1640 + /// The current user is not permitted to perform installations from a client session of a server running the + /// Terminal Server role service. + /// + ERROR_INSTALL_REMOTE_DISALLOWED = 1640, + + /// + /// ERROR_SUCCESS_REBOOT_INITIATED 1641 + /// The installer has initiated a restart. + /// This message is indicative of a success. + /// + ERROR_SUCCESS_REBOOT_INITIATED = 1641, + + /// + /// ERROR_PATCH_TARGET_NOT_FOUND 1642 + /// The installer cannot install the upgrade patch because the program being upgraded may be missing or the + /// upgrade patch updates a different version of the program. + /// Verify that the program to be upgraded exists on your computer and that you have the correct upgrade patch. + /// + ERROR_PATCH_TARGET_NOT_FOUND = 1642, + + /// + /// ERROR_PATCH_PACKAGE_REJECTED 1643 + /// The patch package is not permitted by system policy. + /// + ERROR_PATCH_PACKAGE_REJECTED = 1643, + + /// + /// ERROR_INSTALL_TRANSFORM_REJECTED 1644 + /// One or more customizations are not permitted by system policy. + /// + ERROR_INSTALL_TRANSFORM_REJECTED = 1644, + + /// + /// ERROR_INSTALL_REMOTE_PROHIBITED 1645 + /// Windows Installer does not permit installation from a Remote Desktop Connection. + /// + ERROR_INSTALL_REMOTE_PROHIBITED = 1645, + + /// + /// ERROR_PATCH_REMOVAL_UNSUPPORTED 1646 + /// The patch package is not a removable patch package. Available beginning with Windows Installer version 3.0. + /// + ERROR_PATCH_REMOVAL_UNSUPPORTED = 1646, + + /// + /// ERROR_UNKNOWN_PATCH 1647 + /// The patch is not applied to this product. Available beginning with Windows Installer version 3.0. + /// + ERROR_UNKNOWN_PATCH = 1647, + + /// + /// ERROR_PATCH_NO_SEQUENCE 1648 + /// No valid sequence could be found for the set of patches. Available beginning with Windows Installer version 3.0. + /// + ERROR_PATCH_NO_SEQUENCE = 1648, + + /// + /// ERROR_PATCH_REMOVAL_DISALLOWED 1649 + /// Patch removal was disallowed by policy. Available beginning with Windows Installer version 3.0. + ERROR_PATCH_REMOVAL_DISALLOWED = 1649, + + /// + /// ERROR_INVALID_PATCH_XML = 1650 + /// The XML patch data is invalid. Available beginning with Windows Installer version 3.0. + /// + ERROR_INVALID_PATCH_XML = 1650, + + /// + /// ERROR_PATCH_MANAGED_ADVERTISED_PRODUCT 1651 + /// Administrative user failed to apply patch for a per-user managed or a per-machine application that is in advertise state. + /// Available beginning with Windows Installer version 3.0. + ERROR_PATCH_MANAGED_ADVERTISED_PRODUCT = 1651, + + /// + /// ERROR_INSTALL_SERVICE_SAFEBOOT 1652 + /// Windows Installer is not accessible when the computer is in Safe Mode. + /// Exit Safe Mode and try again or try using System Restore to return your computer to a previous state. + /// Available beginning with Windows Installer version 4.0. + /// + ERROR_INSTALL_SERVICE_SAFEBOOT = 1652, + + /// + /// ERROR_ROLLBACK_DISABLED 1653 + /// Could not perform a multiple-package transaction because rollback has been disabled. + /// Multiple-Package Installations cannot run if rollback is disabled. Available beginning with Windows Installer version 4.5. + /// + ERROR_ROLLBACK_DISABLED = 1653, + + /// + /// ERROR_SUCCESS_REBOOT_REQUIRED 3010 + /// A restart is required to complete the install. This message is indicative of a success. + /// This does not include installs where the ForceReboot action is run. + /// + ERROR_SUCCESS_REBOOT_REQUIRED = 3010 + } + + /// + /// Modes of operations for MSIExec; install, administrator install, uninstall .. etc + /// + public enum MSIExecMode + { + /// + /// Installs or configures a product + /// + Install = 0, + + /// + /// Administrative install - Installs a product on the network + /// + AdministrativeInstall, + + /// + /// Uninstalls the product + /// + Uninstall, + + /// + /// Repairs a product + /// + Repair, + + /// + /// Modifies a product + /// + Modify, + + /// + /// Uninstalls the product as part of cleanup + /// + Cleanup, + } + + /// + /// User interfave levels + /// + public enum MSIExecUserInterfaceLevel + { + /// + /// No UI + /// + None = 0, + + /// + /// Basic UI + /// + Basic, + + /// + /// Reduced UI + /// + Reduced, + + /// + /// Full UI (default) + /// + Full + } + + /// + /// Logging options + /// + [Flags] + public enum MSIExecLoggingOptions + { + Status_Messages = 0x0001, + Nonfatal_Warnings = 0x0002, + All_Error_Messages = 0x0004, + Start_Up_Of_Actions = 0x0008, + Action_Specific_Records = 0x0010, + User_Requests = 0x0020, + Initial_UI_Parameters = 0x0040, + OutOfMemory_Or_Fatal_Exit_Information = 0x0080, + OutOfDiskSpace_Messages = 0x0100, + Terminal_Properties = 0x0200, + Verbose_Output = 0x0400, + Append_To_Existing_Log_File = 0x0800, + + Flush_Each_line = 0x1000, + Extra_Debugging_Information = 0x2000, + Log_All_Information = 0x4000, + VOICEWARMUP = 0x0FFF + } + } +} diff --git a/src/test/burn/WixTestTools/MsiUtilities.cs b/src/test/burn/WixTestTools/MsiUtilities.cs new file mode 100644 index 00000000..4c7d1601 --- /dev/null +++ b/src/test/burn/WixTestTools/MsiUtilities.cs @@ -0,0 +1,47 @@ +// 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. + +namespace WixTestTools +{ + using System; + using WixToolset.Dtf.WindowsInstaller; + + public class MsiUtilities + { + /// + /// Return true if it finds the given productcode in system otherwise it returns false + /// + /// + /// + public static bool IsProductInstalled(string prodCode) + { + //look in all user's products (both per-machine and per-user) + foreach (ProductInstallation product in ProductInstallation.GetProducts(null, "s-1-1-0", UserContexts.All)) + { + if (product.ProductCode == prodCode) + { + return true; + } + } + return false; + } + + /// + /// Return true if it finds the given productcode in system with the specified version otherwise it returns false + /// + /// + /// + /// + public static bool IsProductInstalledWithVersion(string prodCode, Version prodVersion) + { + //look in all user's products (both per-machine and per-user) + foreach (ProductInstallation product in ProductInstallation.GetProducts(null, "s-1-1-0", UserContexts.All)) + { + if (product.ProductCode == prodCode && product.ProductVersion == prodVersion) + { + return true; + } + } + return false; + } + } +} diff --git a/src/test/burn/WixTestTools/PackageInstaller.cs b/src/test/burn/WixTestTools/PackageInstaller.cs new file mode 100644 index 00000000..d32f499b --- /dev/null +++ b/src/test/burn/WixTestTools/PackageInstaller.cs @@ -0,0 +1,104 @@ +// 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. + +namespace WixTestTools +{ + using System; + using System.IO; + using System.Linq; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using WixToolset.Data.WindowsInstaller; + using static WixTestTools.MSIExec; + + public partial class PackageInstaller : IDisposable + { + public PackageInstaller(WixTestContext testContext, string filename) + { + this.Package = Path.Combine(testContext.TestDataFolder, $"{filename}.msi"); + this.PackagePdb = Path.Combine(testContext.TestDataFolder, $"{filename}.wixpdb"); + this.TestContext = testContext; + + using var wixOutput = WixOutput.Read(this.PackagePdb); + + var intermediate = Intermediate.Load(wixOutput); + var section = intermediate.Sections.Single(); + var platformSummary = section.Symbols.OfType().Single(s => s.PropertyId == SummaryInformationType.PlatformAndLanguage); + var platformString = platformSummary.Value.Split(new char[] { ';' }, 2)[0]; + this.IsX64 = platformString != "Intel"; + + this.WiData = WindowsInstallerData.Load(wixOutput); + } + + public string Package { get; } + + private WixTestContext TestContext { get; } + + public string TestGroupName => this.TestContext.TestGroupName; + + public string TestName => this.TestContext.TestName; + + /// + /// Installs a .msi file + /// + /// Expected exit code + /// Other arguments to pass to MSIExec. + /// MSIExec log File + public string InstallProduct(MSIExecReturnCode expectedExitCode = MSIExecReturnCode.SUCCESS, params string[] otherArguments) + { + return this.RunMSIExec(MSIExecMode.Install, otherArguments, expectedExitCode); + } + + /// + /// Uninstalls a .msi file + /// + /// Expected exit code + /// Other arguments to pass to MSIExec. + /// MSIExec log File + public string UninstallProduct(MSIExecReturnCode expectedExitCode = MSIExecReturnCode.SUCCESS, params string[] otherArguments) + { + return this.RunMSIExec(MSIExecMode.Uninstall, otherArguments, expectedExitCode); + } + + /// + /// Repairs a .msi file + /// + /// Expected exit code + /// Other arguments to pass to msiexe.exe. + /// MSIExec log File + public string RepairProduct(MSIExecReturnCode expectedExitCode = MSIExecReturnCode.SUCCESS, params string[] otherArguments) + { + return this.RunMSIExec(MSIExecMode.Repair, otherArguments, expectedExitCode); + } + + /// + /// Executes MSIExec on a .msi file + /// + /// Mode of execution for MSIExec + /// Other arguments to pass to MSIExec. + /// Expected exit code + /// MSIExec exit code + private string RunMSIExec(MSIExecMode mode, string[] otherArguments, MSIExecReturnCode expectedExitCode, bool assertOnError = true) + { + // Generate the log file name. + var logFile = Path.Combine(Path.GetTempPath(), String.Format("{0}_{1}_{2:yyyyMMddhhmmss}_{4}_{3}.log", this.TestGroupName, this.TestName, DateTime.UtcNow, Path.GetFileNameWithoutExtension(this.Package), mode)); + + var msiexec = new MSIExec + { + Product = this.Package, + ExecutionMode = mode, + OtherArguments = null != otherArguments ? String.Join(" ", otherArguments) : null, + ExpectedExitCode = expectedExitCode, + LogFile = logFile, + }; + + msiexec.Run(assertOnError); + return msiexec.LogFile; + } + + public void Dispose() + { + string[] args = { "IGNOREDEPENDENCIES=ALL", "WIXFAILWHENDEFERRED=0" }; + this.RunMSIExec(MSIExecMode.Cleanup, args, MSIExecReturnCode.SUCCESS, assertOnError: false); + } + } +} diff --git a/src/test/burn/WixTestTools/PackageVerifier.cs b/src/test/burn/WixTestTools/PackageVerifier.cs new file mode 100644 index 00000000..2f42dd21 --- /dev/null +++ b/src/test/burn/WixTestTools/PackageVerifier.cs @@ -0,0 +1,81 @@ +// 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. + +namespace WixTestTools +{ + using System; + using System.IO; + using System.Linq; + using WixToolset.Data.WindowsInstaller; + using WixToolset.Data.WindowsInstaller.Rows; + using Xunit; + + public partial class PackageInstaller + { + public string PackagePdb { get; } + + private bool IsX64 { get; } + + private WindowsInstallerData WiData { get; } + + public string GetInstalledFilePath(string filename) + { + return this.TestContext.GetTestInstallFolder(this.IsX64, Path.Combine(this.GetInstallFolderName(), filename)); + } + + public string GetInstallFolderName() + { + var row = this.WiData.Tables["Directory"].Rows.Single(r => r.FieldAsString(0) == "INSTALLFOLDER"); + var value = row.FieldAsString(2); + var longNameIndex = value.IndexOf('|') + 1; + if (longNameIndex > 0) + { + return value.Substring(longNameIndex); + } + return value; + } + + public string GetProperty(string name) + { + var row = this.WiData.Tables["Property"].Rows.Cast().Single(r => r.Property == name); + return row.Value; + } + + public void VerifyInstalled(bool installed) + { + var productCode = this.GetProperty("ProductCode"); + Assert.Equal(installed, MsiUtilities.IsProductInstalled(productCode)); + } + + public void VerifyInstalledWithVersion(bool installed) + { + var productCode = this.GetProperty("ProductCode"); + Version prodVersion = new Version(this.GetProperty("ProductVersion")); + Assert.Equal(installed, MsiUtilities.IsProductInstalledWithVersion(productCode, prodVersion)); + } + + public void DeleteTestRegistryValue(string name) + { + using (var root = this.TestContext.GetTestRegistryRoot(this.IsX64)) + { + Assert.NotNull(root); + root.DeleteValue(name); + } + } + + public void VerifyTestRegistryRootDeleted() + { + using var testRegistryRoot = this.TestContext.GetTestRegistryRoot(this.IsX64); + Assert.Null(testRegistryRoot); + } + + public void VerifyTestRegistryValue(string name, string expectedValue) + { + using (var root = this.TestContext.GetTestRegistryRoot(this.IsX64)) + { + Assert.NotNull(root); + var actualValue = root.GetValue(name) as string; + Assert.Equal(expectedValue, actualValue); + } + } + } +} diff --git a/src/test/burn/WixTestTools/TestTool.cs b/src/test/burn/WixTestTools/TestTool.cs new file mode 100644 index 00000000..be5fde42 --- /dev/null +++ b/src/test/burn/WixTestTools/TestTool.cs @@ -0,0 +1,245 @@ +// 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. + +namespace WixTestTools +{ + using System; + using System.Collections.Generic; + using System.Text; + using System.Text.RegularExpressions; + using WixBuildTools.TestSupport; + using Xunit; + + public class TestTool : ExternalExecutable + { + /// + /// Constructor for a TestTool + /// + public TestTool() + : this(null) + { + } + + /// + /// Constructor for a TestTool + /// + /// The full path to the tool. Eg. c:\bin\candle.exe + public TestTool(string toolFile) + : base(toolFile) + { + this.PrintOutputToConsole = true; + } + + /// + /// The arguments to pass to the tool + /// + public virtual string Arguments { get; set; } + + /// + /// Stores the errors that occurred when a run was checked against its expected results + /// + public List Errors { get; set; } + + /// + /// A list of Regex's that are expected to match stderr + /// + public List ExpectedErrorRegexs { get; set; } = new List(); + + /// + /// The expected error strings to stderr + /// + public List ExpectedErrorStrings { get; set; } = new List(); + + /// + /// The expected exit code of the tool + /// + public int? ExpectedExitCode { get; set; } + + /// + /// A list of Regex's that are expected to match stdout + /// + public List ExpectedOutputRegexs { get; set; } = new List(); + + /// + /// The expected output strings to stdout + /// + public List ExpectedOutputStrings { get; set; } = new List(); + + /// + /// Print output from the tool execution to the console + /// + public bool PrintOutputToConsole { get; set; } + + /// + /// The working directory of the tool + /// + public string WorkingDirectory { get; set; } + + /// + /// Print the errors from the last run + /// + public void PrintErrors() + { + if (null != this.Errors) + { + Console.WriteLine("Errors:"); + + foreach (string error in this.Errors) + { + Console.WriteLine(error); + } + } + } + + /// + /// Run the tool + /// + /// The results of the run + public ExternalExecutableResult Run() + { + return this.Run(true); + } + + /// + /// Run the tool + /// + /// Throw an exception if the expected results don't match the actual results + /// Thrown when the expected results don't match the actual results + /// The results of the run + public virtual ExternalExecutableResult Run(bool assertOnError) + { + var result = this.Run(this.Arguments, workingDirectory: this.WorkingDirectory ?? String.Empty); + + if (this.PrintOutputToConsole) + { + Console.WriteLine(FormatResult(result)); + } + + this.Errors = this.CheckResult(result); + + if (assertOnError && 0 < this.Errors.Count) + { + if (this.PrintOutputToConsole) + { + this.PrintErrors(); + } + + Assert.Empty(this.Errors); + } + + return result; + } + + /// + /// Checks that the result from a run matches the expected results + /// + /// A result from a run + /// A list of errors + public virtual List CheckResult(ExternalExecutableResult result) + { + List errors = new List(); + + // Verify that the expected return code matched the actual return code + if (null != this.ExpectedExitCode && this.ExpectedExitCode != result.ExitCode) + { + errors.Add(String.Format("Expected exit code {0} did not match actual exit code {1}", this.ExpectedExitCode, result.ExitCode)); + } + + var standardErrorString = string.Join(Environment.NewLine, result.StandardError); + + // Verify that the expected error string are in stderr + if (null != this.ExpectedErrorStrings) + { + foreach (string expectedString in this.ExpectedErrorStrings) + { + if (!standardErrorString.Contains(expectedString)) + { + errors.Add(String.Format("The text '{0}' was not found in stderr", expectedString)); + } + } + } + + var standardOutputString = string.Join(Environment.NewLine, result.StandardOutput); + + // Verify that the expected output string are in stdout + if (null != this.ExpectedOutputStrings) + { + foreach (string expectedString in this.ExpectedOutputStrings) + { + if (!standardOutputString.Contains(expectedString)) + { + errors.Add(String.Format("The text '{0}' was not found in stdout", expectedString)); + } + } + } + + // Verify that the expected regular expressions match stderr + if (null != this.ExpectedOutputRegexs) + { + foreach (Regex expectedRegex in this.ExpectedOutputRegexs) + { + if (!expectedRegex.IsMatch(standardOutputString)) + { + errors.Add(String.Format("Regex {0} did not match stdout", expectedRegex.ToString())); + } + } + } + + // Verify that the expected regular expressions match stdout + if (null != this.ExpectedErrorRegexs) + { + foreach (Regex expectedRegex in this.ExpectedErrorRegexs) + { + if (!expectedRegex.IsMatch(standardErrorString)) + { + errors.Add(String.Format("Regex {0} did not match stderr", expectedRegex.ToString())); + } + } + } + + return errors; + } + + /// + /// Clears all of the expected results and resets them to the default values + /// + public virtual void SetDefaultExpectedResults() + { + this.ExpectedErrorRegexs = new List(); + this.ExpectedErrorStrings = new List(); + this.ExpectedExitCode = null; + this.ExpectedOutputRegexs = new List(); + this.ExpectedOutputStrings = new List(); + } + + /// + /// Returns a string with data contained in the result. + /// + /// A string + private static string FormatResult(ExternalExecutableResult result) + { + var returnValue = new StringBuilder(); + returnValue.AppendLine(); + returnValue.AppendLine("----------------"); + returnValue.AppendLine("Tool run result:"); + returnValue.AppendLine("----------------"); + returnValue.AppendLine("Command:"); + returnValue.AppendLine($"\"{result.StartInfo.FileName}\" {result.StartInfo.Arguments}"); + returnValue.AppendLine(); + returnValue.AppendLine("Standard Output:"); + foreach (var line in result.StandardOutput ?? new string[0]) + { + returnValue.AppendLine(line); + } + returnValue.AppendLine("Standard Error:"); + foreach (var line in result.StandardError ?? new string[0]) + { + returnValue.AppendLine(line); + } + returnValue.AppendLine("Exit Code:"); + returnValue.AppendLine(Convert.ToString(result.ExitCode)); + returnValue.AppendLine("----------------"); + + return returnValue.ToString(); + } + } +} diff --git a/src/test/burn/WixTestTools/WixTestBase.cs b/src/test/burn/WixTestTools/WixTestBase.cs new file mode 100644 index 00000000..bc050135 --- /dev/null +++ b/src/test/burn/WixTestTools/WixTestBase.cs @@ -0,0 +1,19 @@ +// 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. + +namespace WixTestTools +{ + using Xunit.Abstractions; + + public abstract class WixTestBase + { + protected WixTestBase(ITestOutputHelper testOutputHelper) + { + this.TestContext = new WixTestContext(testOutputHelper); + } + + /// + /// The test context for the current test. + /// + public WixTestContext TestContext { get; } + } +} diff --git a/src/test/burn/WixTestTools/WixTestContext.cs b/src/test/burn/WixTestTools/WixTestContext.cs new file mode 100644 index 00000000..a4e666f1 --- /dev/null +++ b/src/test/burn/WixTestTools/WixTestContext.cs @@ -0,0 +1,75 @@ +// 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. + +namespace WixTestTools +{ + using System; + using System.IO; + using System.Linq; + using System.Reflection; + using Microsoft.Win32; + using WixBuildTools.TestSupport; + using Xunit.Abstractions; + + public class WixTestContext + { + static readonly string RootDataPath = Path.GetFullPath(TestData.Get("TestData")); + + public WixTestContext(ITestOutputHelper testOutputHelper) + { + var test = GetTest(testOutputHelper); + var splitClassName = test.TestCase.TestMethod.TestClass.Class.Name.Split('.'); + + this.TestGroupName = splitClassName.Last(); + this.TestName = test.TestCase.TestMethod.Method.Name; + + this.TestDataFolder = Path.Combine(RootDataPath, this.TestGroupName); + } + + public string TestDataFolder { get; } + + /// + /// Gets the name of the current test group. + /// + public string TestGroupName { get; } + + public string TestName { get; } + + /// + /// Gets the test install directory for the current test. + /// + /// Additional subdirectories under the test install directory. + /// Full path to the test install directory. + /// + /// The package or bundle must install into [ProgramFilesFolder]\~Test WiX\[TestGroupName]\([Additional]). + /// + public string GetTestInstallFolder(bool x64, string additionalPath = null) + { + var baseDirectory = x64 ? Environment.SpecialFolder.ProgramFiles : Environment.SpecialFolder.ProgramFilesX86; + return Path.Combine(Environment.GetFolderPath(baseDirectory), "~Test WiX", this.TestGroupName, additionalPath ?? String.Empty); + } + + /// + /// Gets the test registry key for the current test. + /// + /// Additional subkeys under the test registry key. + /// Full path to the test registry key. + /// + /// The package must write into HKLM\Software\WiX\Tests\[TestGroupName]\([Additional]). + /// + public RegistryKey GetTestRegistryRoot(bool x64, string additionalPath = null) + { + var baseKey = x64 ? "Software" : @"Software\WOW6432Node"; + var key = String.Format(@"{0}\WiX\Tests\{1}\{2}", baseKey, this.TestGroupName, additionalPath ?? String.Empty); + return Registry.LocalMachine.OpenSubKey(key, true); + } + + private static ITest GetTest(ITestOutputHelper output) + { + // https://github.com/xunit/xunit/issues/416#issuecomment-378512739 + var type = output.GetType(); + var testMember = type.GetField("test", BindingFlags.Instance | BindingFlags.NonPublic); + var test = (ITest)testMember.GetValue(output); + return test; + } + } +} diff --git a/src/test/burn/WixTestTools/WixTestTools.csproj b/src/test/burn/WixTestTools/WixTestTools.csproj new file mode 100644 index 00000000..58f02be7 --- /dev/null +++ b/src/test/burn/WixTestTools/WixTestTools.csproj @@ -0,0 +1,21 @@ + + + + + + netcoreapp3.1 + x64 + + + + + + + + + + + + + + diff --git a/src/test/burn/WixToolsetTest.BurnE2E/BasicFunctionalityTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/BasicFunctionalityTests.cs new file mode 100644 index 00000000..5df86fff --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/BasicFunctionalityTests.cs @@ -0,0 +1,176 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.IO; + using Xunit; + using Xunit.Abstractions; + + public class BasicFunctionalityTests : BurnE2ETests + { + public BasicFunctionalityTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void CanInstallAndUninstallSimpleBundle_x86_wixstdba() + { + var packageA = this.CreatePackageInstaller("PackageA"); + + var bundleA = this.CreateBundleInstaller("BundleA"); + + var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); + + bundleA.Install(); + + var cachedBundlePath = bundleA.VerifyRegisteredAndInPackageCache(); + + // Source file should be installed + Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled)); + + bundleA.Uninstall(cachedBundlePath); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A payload should have been removed by uninstall from: ", packageASourceCodeInstalled)); + + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath); + } + + [Fact] + public void CanInstallAndUninstallSimpleBundle_x86_testba() + { + var packageA = this.CreatePackageInstaller("PackageA"); + + var bundleB = this.CreateBundleInstaller("BundleB"); + + var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); + + bundleB.Install(); + + var cachedBundlePath = bundleB.VerifyRegisteredAndInPackageCache(); + + // Source file should be installed + Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled)); + + bundleB.Uninstall(cachedBundlePath); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A payload should have been removed by uninstall from: ", packageASourceCodeInstalled)); + + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath); + } + + [Fact] + public void CanInstallAndUninstallSimpleBundle_x86_dnctestba() + { + var packageA = this.CreatePackageInstaller("PackageA"); + + var bundleC = this.CreateBundleInstaller("BundleC"); + + var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); + + bundleC.Install(); + + var cachedBundlePath = bundleC.VerifyRegisteredAndInPackageCache(); + + // Source file should be installed + Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled)); + + bundleC.Uninstall(cachedBundlePath); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A payload should have been removed by uninstall from: ", packageASourceCodeInstalled)); + + bundleC.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath); + } + + [Fact] + public void CanInstallAndUninstallSimpleBundle_x64_wixstdba() + { + var packageA_x64 = this.CreatePackageInstaller("PackageA_x64"); + + var bundleA_x64 = this.CreateBundleInstaller("BundleA_x64"); + + var packageASourceCodeInstalled = packageA_x64.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A x64 payload should not be there on test start: {packageASourceCodeInstalled}"); + + bundleA_x64.Install(); + + var cachedBundlePath = bundleA_x64.VerifyRegisteredAndInPackageCache(); + + // Source file should be installed + Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A x64 payload installed at: ", packageASourceCodeInstalled)); + + bundleA_x64.Uninstall(cachedBundlePath); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A x64 payload should have been removed by uninstall from: ", packageASourceCodeInstalled)); + + bundleA_x64.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath); + } + + [Fact] + public void CanInstallAndUninstallSimpleBundle_x64_testba() + { + var packageA_x64 = this.CreatePackageInstaller("PackageA_x64"); + + var bundleB_x64 = this.CreateBundleInstaller("BundleB_x64"); + + var packageASourceCodeInstalled = packageA_x64.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A x64 payload should not be there on test start: {packageASourceCodeInstalled}"); + + bundleB_x64.Install(); + + var cachedBundlePath = bundleB_x64.VerifyRegisteredAndInPackageCache(); + + // Source file should be installed + Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A x64 payload installed at: ", packageASourceCodeInstalled)); + + bundleB_x64.Uninstall(cachedBundlePath); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A x64 payload should have been removed by uninstall from: ", packageASourceCodeInstalled)); + + bundleB_x64.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath); + } + + [Fact] + public void CanInstallAndUninstallSimpleBundle_x64_dnctestba() + { + var packageA_x64 = this.CreatePackageInstaller("PackageA_x64"); + + var bundleC_x64 = this.CreateBundleInstaller("BundleC_x64"); + + var packageASourceCodeInstalled = packageA_x64.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A x64 payload should not be there on test start: {packageASourceCodeInstalled}"); + + bundleC_x64.Install(); + + var cachedBundlePath = bundleC_x64.VerifyRegisteredAndInPackageCache(); + + // Source file should be installed + Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A x64 payload installed at: ", packageASourceCodeInstalled)); + + bundleC_x64.Uninstall(cachedBundlePath); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A x64 payload should have been removed by uninstall from: ", packageASourceCodeInstalled)); + + bundleC_x64.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/BurnE2EFixture.cs b/src/test/burn/WixToolsetTest.BurnE2E/BurnE2EFixture.cs new file mode 100644 index 00000000..babfcbc3 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/BurnE2EFixture.cs @@ -0,0 +1,28 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.Security.Principal; + + public class BurnE2EFixture + { + const string RequiredEnvironmentVariableName = "RuntimeTestsEnabled"; + + public BurnE2EFixture() + { + using var identity = WindowsIdentity.GetCurrent(); + var principal = new WindowsPrincipal(identity); + if (!principal.IsInRole(WindowsBuiltInRole.Administrator)) + { + throw new InvalidOperationException("These tests must run elevated."); + } + + var testsEnabledString = Environment.GetEnvironmentVariable(RequiredEnvironmentVariableName); + if (!bool.TryParse(testsEnabledString, out var testsEnabled) || !testsEnabled) + { + throw new InvalidOperationException($"These tests affect machine state. Set the {RequiredEnvironmentVariableName} environment variable to true to accept the consequences."); + } + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs b/src/test/burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs new file mode 100644 index 00000000..392b675d --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs @@ -0,0 +1,63 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.Collections.Generic; + using WixTestTools; + using Xunit; + using Xunit.Abstractions; + + [Collection("BurnE2E")] + public abstract class BurnE2ETests : WixTestBase, IDisposable + { + protected BurnE2ETests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + private Stack Installers { get; } = new Stack(); + + protected BundleInstaller CreateBundleInstaller(string name) + { + var installer = new BundleInstaller(this.TestContext, name); + this.Installers.Push(installer); + return installer; + } + + protected PackageInstaller CreatePackageInstaller(string filename) + { + var installer = new PackageInstaller(this.TestContext, filename); + this.Installers.Push(installer); + return installer; + } + + protected TestBAController CreateTestBAController() + { + var controller = new TestBAController(this.TestContext); + this.Installers.Push(controller); + return controller; + } + + protected IWebServer CreateWebServer() + { + var webServer = new CoreOwinWebServer(); + this.Installers.Push(webServer); + return webServer; + } + + public void Dispose() + { + while (this.Installers.TryPop(out var installer)) + { + try + { + installer.Dispose(); + } + catch { } + } + } + } + + [CollectionDefinition("BurnE2E", DisableParallelization = true)] + public class BurnE2ECollectionDefinition : ICollectionFixture + { + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs new file mode 100644 index 00000000..e8d37aef --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs @@ -0,0 +1,133 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System.Collections.Generic; + using System.IO; + using WixBuildTools.TestSupport; + using WixTestTools; + using WixToolset.Mba.Core; + using Xunit; + using Xunit.Abstractions; + + public class CacheTests : BurnE2ETests + { + public CacheTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void CanCache5GBFile() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var bundleC = this.CreateBundleInstaller("BundleC"); + + packageA.VerifyInstalled(false); + + // Recreate the 5GB payload to avoid having to copy it to the VM to run the tests. + var targetFilePath = Path.Combine(this.TestContext.TestDataFolder, "fivegb.file"); + if (!File.Exists(targetFilePath)) + { + var testTool = new TestTool(Path.Combine(TestData.Get(), "win-x86", "TestExe.exe")) + { + Arguments = "/lf \"" + targetFilePath + "|5368709120\"", + ExpectedExitCode = 0, + }; + testTool.Run(true); + } + + bundleC.Install(); + bundleC.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + } + + [Fact] + public void CanDownloadPayloadsFromMissingAttachedContainer() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleA = this.CreateBundleInstaller("BundleA"); + var testBAController = this.CreateTestBAController(); + var webServer = this.CreateWebServer(); + + webServer.AddFiles(new Dictionary + { + { "/BundleA/PackageA.msi", Path.Combine(this.TestContext.TestDataFolder, "PackageA.msi") }, + { "/BundleA/PackageB.msi", Path.Combine(this.TestContext.TestDataFolder, "PackageB.msi") }, + }); + webServer.Start(); + + // Don't install PackageB initially so it will be installed when run from the package cache. + testBAController.SetPackageRequestedState("PackageB", RequestState.Absent); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + + // Manually copy bundle to separate directory, install from there, and then delete it + // so that when run from the package cache, it can't find the attached container. + using (var dfs = new DisposableFileSystem()) + { + var tempDirectory = dfs.GetFolder(true); + + var bundleAFileInfo = new FileInfo(bundleA.Bundle); + var bundleACopiedPath = Path.Combine(tempDirectory, bundleAFileInfo.Name); + bundleAFileInfo.CopyTo(bundleACopiedPath); + + bundleA.Install(bundleACopiedPath); + } + + var bundlePackageCachePath = bundleA.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageB.VerifyInstalled(false); + + testBAController.SetPackageRequestedState("PackageB", RequestState.Present); + + bundleA.Modify(bundlePackageCachePath); + bundleA.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageB.VerifyInstalled(true); + } + + [Fact] + public void CanFindAttachedContainerFromRenamedBundle() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleB = this.CreateBundleInstaller("BundleB"); + var testBAController = this.CreateTestBAController(); + + // Don't install PackageB initially so it will be installed when run from the package cache. + testBAController.SetPackageRequestedState("PackageB", RequestState.Absent); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + + // Manually copy bundle to separate directory with new name and install from there + // so that when run from the package cache, it has to get the attached container from the renamed bundle. + using (var dfs = new DisposableFileSystem()) + { + var tempDirectory = dfs.GetFolder(true); + + var bundleBFileInfo = new FileInfo(bundleB.Bundle); + var bundleBCopiedPath = Path.Combine(tempDirectory, "RenamedBundle.exe"); + bundleBFileInfo.CopyTo(bundleBCopiedPath); + + bundleB.Install(bundleBCopiedPath); + + var bundlePackageCachePath = bundleB.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageB.VerifyInstalled(false); + + testBAController.SetPackageRequestedState("PackageB", RequestState.Present); + + bundleB.Modify(bundlePackageCachePath); + bundleB.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageB.VerifyInstalled(true); + } + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs new file mode 100644 index 00000000..d563bbe7 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs @@ -0,0 +1,611 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using WixTestTools; + using WixToolset.Mba.Core; + using Xunit; + using Xunit.Abstractions; + + public class DependencyTests : BurnE2ETests + { + public DependencyTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void CanKeepSameExactPackageAfterUpgradingBundle() + { + var packageF = this.CreatePackageInstaller("PackageF"); + var bundleKv1 = this.CreateBundleInstaller("BundleKv1"); + var bundleKv2 = this.CreateBundleInstaller("BundleKv2"); + + packageF.VerifyInstalled(false); + + bundleKv1.Install(); + bundleKv1.VerifyRegisteredAndInPackageCache(); + + packageF.VerifyInstalled(true); + + bundleKv2.Install(); + bundleKv2.VerifyRegisteredAndInPackageCache(); + bundleKv1.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageF.VerifyInstalled(true); + + bundleKv2.VerifyPackageIsCached("PackageF"); + + bundleKv2.Uninstall(); + bundleKv2.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageF.VerifyInstalled(false); + } + + [Fact (Skip = "https://github.com/wixtoolset/issues/issues/6387")] + public void CanKeepSameExactPackageAfterUpgradingBundleWithSlipstreamedPatch() + { + var originalVersion = "1.0.0.0"; + var patchedVersion = "1.0.1.0"; + var testRegistryValue = "PackageA"; + var testRegistryValueExe = "ExeA"; + + var packageA = this.CreatePackageInstaller("PackageAv1"); + var bundleA = this.CreateBundleInstaller("BundleAv1"); + var bundleC = this.CreateBundleInstaller("BundleC"); + + packageA.VerifyInstalled(false); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageA.VerifyTestRegistryValue(testRegistryValue, originalVersion); + bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, originalVersion); + + // Verify https://github.com/wixtoolset/issues/issues/3294 - Uninstalling bundle registers a dependency on a package + bundleC.Install(); + bundleC.VerifyRegisteredAndInPackageCache(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(true); + packageA.VerifyTestRegistryValue(testRegistryValue, patchedVersion); + bundleA.VerifyExeTestRegistryRootDeleted(testRegistryValueExe); + + // Verify https://github.com/wixtoolset/issues/issues/2915 - Update bundle removes previously cached MSIs + bundleC.Repair(); + + bundleC.Uninstall(); + bundleC.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + } + + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/exea")] + public void CanKeepUpgradedPackageAfterUninstallUpgradedBundle() + { + var testRegistryValueExe = "ExeA"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv101 = this.CreatePackageInstaller("PackageAv1_0_1"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv101 = this.CreateBundleInstaller("BundleAv1_0_1"); + var bundleB = this.CreateBundleInstaller("BundleB"); + + packageAv1.VerifyInstalledWithVersion(false); + packageAv101.VerifyInstalledWithVersion(false); + packageB.VerifyInstalled(false); + + bundleAv1.Install(); + bundleAv1.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalledWithVersion(true); + bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + + bundleB.Install(); + bundleB.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalledWithVersion(true); + bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + packageB.VerifyInstalled(true); + + bundleAv101.Install(); + bundleAv101.VerifyRegisteredAndInPackageCache(); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalledWithVersion(false); + packageAv101.VerifyInstalledWithVersion(true); + bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.1.0"); + + bundleAv101.Uninstall(); + bundleAv101.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv101.VerifyInstalledWithVersion(true); + bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.1.0"); + } + +#if SUPPORT_ADDON_AND_PATCH_RELATED_BUNDLES + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6387")] +#else + [Fact(Skip = "addon/patch related bundle")] +#endif + public void CanMinorUpgradeDependencyPackageFromPatchBundle() + { + var originalVersion = "1.0.0.0"; + var patchedVersion = "1.0.1.0"; + var testRegistryValue = "PackageA"; + + var packageA = this.CreatePackageInstaller("PackageAv1"); + var packageBv1 = this.CreatePackageInstaller("PackageBv1"); + var packageBv101 = this.CreatePackageInstaller("PackageBv1_0_1"); + var bundleJ = this.CreateBundleInstaller("BundleJ"); + var bundleJ_Patch = this.CreateBundleInstaller("BundleJ_Patch"); + + packageA.VerifyInstalled(false); + packageBv1.VerifyInstalled(false); + packageBv101.VerifyInstalled(false); + + bundleJ.Install(); + bundleJ.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageA.VerifyTestRegistryValue(testRegistryValue, originalVersion); + packageBv1.VerifyInstalled(true); + + bundleJ_Patch.Install(); + bundleJ_Patch.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageA.VerifyTestRegistryValue(testRegistryValue, patchedVersion); + packageBv1.VerifyInstalled(false); + packageBv101.VerifyInstalled(true); + + bundleJ.Uninstall(); + bundleJ.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleJ_Patch.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageBv1.VerifyInstalled(false); + packageBv101.VerifyInstalled(false); + } + +#if SUPPORT_ADDON_AND_PATCH_RELATED_BUNDLES + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6387")] +#else + [Fact(Skip = "addon/patch related bundle")] +#endif + public void CanMinorUpgradeDependencyPackageFromPatchBundleThenUninstallToRestoreBase() + { + var originalVersion = "1.0.0.0"; + var patchedVersion = "1.0.1.0"; + var testRegistryValue = "PackageA"; + + var packageA = this.CreatePackageInstaller("PackageAv1"); + var packageBv1 = this.CreatePackageInstaller("PackageBv1"); + var packageBv101 = this.CreatePackageInstaller("PackageBv1_0_1"); + var bundleJ = this.CreateBundleInstaller("BundleJ"); + var bundleJ_Patch = this.CreateBundleInstaller("BundleJ_Patch"); + + packageA.VerifyInstalled(false); + packageBv1.VerifyInstalled(false); + packageBv101.VerifyInstalled(false); + + bundleJ.Install(); + bundleJ.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageA.VerifyTestRegistryValue(testRegistryValue, originalVersion); + packageBv1.VerifyInstalled(true); + + bundleJ_Patch.Install(); + bundleJ_Patch.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageA.VerifyTestRegistryValue(testRegistryValue, patchedVersion); + packageBv1.VerifyInstalled(false); + packageBv101.VerifyInstalled(true); + + bundleJ_Patch.Uninstall(); + bundleJ_Patch.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(true); + packageA.VerifyTestRegistryValue(testRegistryValue, originalVersion); + packageBv1.VerifyInstalled(true); + packageBv101.VerifyInstalled(false); + + bundleJ.Uninstall(); + bundleJ.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageBv1.VerifyInstalled(false); + packageBv101.VerifyInstalled(false); + } + +#if SUPPORT_ADDON_AND_PATCH_RELATED_BUNDLES + [Fact] +#else + [Fact(Skip = "addon/patch related bundle")] +#endif + public void CanUninstallBaseWithAddOnsWhenAllSharePackages() + { + var testRegistryValueExe = "ExeA"; + + var packageA = this.CreatePackageInstaller("PackageAv1"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleF = this.CreateBundleInstaller("BundleF"); + var bundleF_AddOnA = this.CreateBundleInstaller("BundleF_AddOnA"); + var bundleF_AddOnB = this.CreateBundleInstaller("BundleF_AddOnB"); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + + bundleF.Install(); + bundleF.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageB.VerifyInstalled(true); + + bundleF_AddOnA.Install(); + bundleF_AddOnA.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + bundleF.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + packageB.VerifyInstalled(true); + + bundleF_AddOnB.Install(); + bundleF_AddOnB.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + bundleF.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + packageB.VerifyInstalled(true); + + bundleF.Uninstall(); + bundleF.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleF_AddOnA.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleF_AddOnB.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + bundleF.VerifyExeTestRegistryRootDeleted(testRegistryValueExe); + packageB.VerifyInstalled(false); + } + + [Fact] + public void CanUninstallDependencyPackagesWithBundlesUninstalledInFifoOrder() + { + var testRegistryValueExe = "ExeA"; + + var packageA = this.CreatePackageInstaller("PackageAv1"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleA = this.CreateBundleInstaller("BundleAv1"); + var bundleB = this.CreateBundleInstaller("BundleB"); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + + bundleB.Install(); + bundleB.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + packageB.VerifyInstalled(true); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(true); + bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + packageB.VerifyInstalled(true); + + bundleB.Uninstall(); + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + bundleA.VerifyExeTestRegistryRootDeleted(testRegistryValueExe); + packageB.VerifyInstalled(false); + } + + [Fact] + public void CanUninstallDependencyPackagesWithBundlesUninstalledInReverseOrder() + { + var packageA = this.CreatePackageInstaller("PackageAv1"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleA = this.CreateBundleInstaller("BundleAv1"); + var bundleB = this.CreateBundleInstaller("BundleB"); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + + bundleB.Install(); + bundleB.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageB.VerifyInstalled(true); + + bundleB.Uninstall(); + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(true); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + } + +#if SUPPORT_ADDON_AND_PATCH_RELATED_BUNDLES + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6387")] +#else + [Fact(Skip = "addon/patch related bundle")] +#endif + public void CanUpgradePatchBundleWithAdditionalPatch() + { + var originalVersion = "1.0.0.0"; + var patchedVersion = "1.0.1.0"; + var patchedVersion2 = "1.0.2.0"; + var testRegistryValue = "PackageA"; + + var packageA = this.CreatePackageInstaller("PackageAv1"); + var packageB = this.CreatePackageInstaller("PackageBv1"); + var bundleF = this.CreateBundleInstaller("BundleJ"); + var bundleF_PatchAv101 = this.CreateBundleInstaller("BundleF_PatchAv1_0_1"); + var bundleF_PatchAv102 = this.CreateBundleInstaller("BundleF_PatchAv1_0_2"); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + + bundleF.Install(); + bundleF.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageA.VerifyTestRegistryValue(testRegistryValue, originalVersion); + packageB.VerifyInstalled(true); + + bundleF_PatchAv101.Install(); + bundleF_PatchAv101.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageA.VerifyTestRegistryValue(testRegistryValue, patchedVersion); + packageB.VerifyInstalled(false); + + bundleF_PatchAv102.Install(); + bundleF_PatchAv102.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageA.VerifyTestRegistryValue(testRegistryValue, patchedVersion2); + packageB.VerifyInstalled(false); + + bundleF.Uninstall(); + bundleF.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleF_PatchAv101.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleF_PatchAv102.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + } + + [Fact] + public void DoesntRegisterDependencyOnPackageNotSelectedForInstall() + { + var testRegistryValueExe = "ExeA"; + + var packageA = this.CreatePackageInstaller("PackageAv1"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleA = this.CreateBundleInstaller("BundleAv1"); + var bundleB = this.CreateBundleInstaller("BundleB"); + var testBAController = this.CreateTestBAController(); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + + // Verify https://github.com/wixtoolset/issues/issues/3456 - Dependency registered on package though unselected to instal + testBAController.SetPackageRequestedState("PackageA", RequestState.None); + testBAController.SetPackageRequestedState("PackageB", RequestState.None); + + bundleB.Install(); + bundleB.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + packageB.VerifyInstalled(false); + + testBAController.ResetPackageStates("PackageA"); + testBAController.ResetPackageStates("PackageB"); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + packageB.VerifyInstalled(false); + + bundleB.Uninstall(); + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + bundleA.VerifyExeTestRegistryRootDeleted(testRegistryValueExe); + packageB.VerifyInstalled(false); + } + + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/3516")] + public void DoesntRollbackPackageInstallIfPreexistingDependents() + { + var packageA = this.CreatePackageInstaller("PackageAv1"); + var packageC = this.CreatePackageInstaller("PackageC"); + var bundleE = this.CreateBundleInstaller("BundleE"); + var bundleL = this.CreateBundleInstaller("BundleL"); + var testBAController = this.CreateTestBAController(); + + packageA.VerifyInstalled(false); + packageC.VerifyInstalled(false); + + // Make PackageC fail. + testBAController.SetPackageCancelExecuteAtProgress("PackageC", 10); + + bundleE.Install(); + bundleE.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageC.VerifyInstalled(false); + + // Make PackageC install then rollback. + testBAController.SetPackageCancelExecuteAtProgress("PackageC", null); + testBAController.SetPackageCancelOnProgressAtProgress("PackageC", 10); + + bundleL.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); + bundleL.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(true); + packageC.VerifyInstalled(true); + + testBAController.SetPackageCancelOnProgressAtProgress("PackageC", null); + + bundleE.Uninstall(); + bundleE.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageC.VerifyInstalled(false); + } + + [Fact] + public void RegistersDependencyOnFailedNonVitalPackages() + { + var packageA = this.CreatePackageInstaller("PackageAv1"); + var packageC = this.CreatePackageInstaller("PackageC"); + var bundleE = this.CreateBundleInstaller("BundleE"); + var bundleL = this.CreateBundleInstaller("BundleL"); + var testBAController = this.CreateTestBAController(); + + packageA.VerifyInstalled(false); + packageC.VerifyInstalled(false); + + // Make PackageC fail. + testBAController.SetPackageCancelExecuteAtProgress("PackageC", 10); + + // Verify https://github.com/wixtoolset/issues/issues/3406 - Non-vital failure result in bundle failure (install) + bundleE.Install(); + bundleE.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageC.VerifyInstalled(false); + + // Verify https://github.com/wixtoolset/issues/issues/3406 - Non-vital failure result in bundle failure (repair) + bundleE.Repair(); + bundleE.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageC.VerifyInstalled(false); + + testBAController.SetPackageCancelExecuteAtProgress("PackageC", null); + + bundleL.Install(); + bundleL.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageC.VerifyInstalled(true); + + // Verify https://github.com/wixtoolset/issues/issues/3516 - Burn registers dependency on failed packages + bundleL.Uninstall(); + bundleL.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(true); + packageC.VerifyInstalled(true); + + bundleE.Uninstall(); + bundleE.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageC.VerifyInstalled(false); + } + + [Fact] + public void RemovesDependencyDuringUpgradeRollback() + { + var testRegistryValueExe = "ExeA"; + + var packageA = this.CreatePackageInstaller("PackageAv1"); + var bundleA = this.CreateBundleInstaller("BundleAv1"); + var bundleD = this.CreateBundleInstaller("BundleD"); + + packageA.VerifyInstalled(false); + bundleA.VerifyExeTestRegistryRootDeleted(testRegistryValueExe); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + + // Verify https://github.com/wixtoolset/issues/issues/3341 - pkg dependecy not removed in rollback if pkg already present + bundleD.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE); + bundleD.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(true); + bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0"); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + bundleA.VerifyExeTestRegistryRootDeleted(testRegistryValueExe); + } + + [Fact] + public void SkipsCrossScopeDependencyRegistration() + { + var packageA = this.CreatePackageInstaller("PackageAv1"); + var packageDv1 = this.CreatePackageInstaller("PackageDv1"); + var packageDv2 = this.CreatePackageInstaller("PackageDv2"); + var bundleHv1 = this.CreateBundleInstaller("BundleHv1"); + var bundleHv2 = this.CreateBundleInstaller("BundleHv2"); + + packageA.VerifyInstalled(false); + packageDv1.VerifyInstalled(false); + packageDv2.VerifyInstalled(false); + + var bundleHv1InstallLogFilePath = bundleHv1.Install(); + bundleHv1.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageDv1.VerifyInstalled(true); + + Assert.True(LogVerifier.MessageInLogFileRegex(bundleHv1InstallLogFilePath, @"Skipping cross-scope dependency registration on package: PackageA, bundle scope: PerUser, package scope: PerMachine")); + + var bundleHv2InstallLogFilePath = bundleHv2.Install(); + bundleHv2.VerifyRegisteredAndInPackageCache(); + bundleHv1.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(true); + packageDv1.VerifyInstalled(false); + packageDv2.VerifyInstalled(true); + + Assert.True(LogVerifier.MessageInLogFileRegex(bundleHv2InstallLogFilePath, @"Skipping cross-scope dependency registration on package: PackageA, bundle scope: PerUser, package scope: PerMachine")); + Assert.True(LogVerifier.MessageInLogFileRegex(bundleHv2InstallLogFilePath, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Upgrade, scope: PerUser, version: 1\.0\.0\.0, operation: MajorUpgrade, cached: Yes")); + + bundleHv2.Uninstall(); + bundleHv2.VerifyUnregisteredAndRemovedFromPackageCache(); + + // Verify that permanent packageA is still installed and then remove. + packageA.VerifyInstalled(true); + packageDv2.VerifyInstalled(false); + packageA.UninstallProduct(); + packageA.VerifyInstalled(false); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs new file mode 100644 index 00000000..54a89469 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs @@ -0,0 +1,30 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using Xunit; + using Xunit.Abstractions; + + public class ElevationTests : BurnE2ETests + { + public ElevationTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + /// + /// This test calls Elevate after Detect, and then calls Plan in OnElevateBegin. + /// After calling Plan, it pumps some messages to simulate UI like the UAC callback. + /// + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6349")] // CAUTION: this test currently hangs because the Plan request gets dropped. + public void CanExplicitlyElevateAndPlanFromOnElevateBegin() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var bundleA = this.CreateBundleInstaller("BundleA"); + var testBAController = this.CreateTestBAController(); + + testBAController.SetExplicitlyElevateAndPlanFromOnElevateBegin(); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + packageA.VerifyInstalled(true); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/FailureTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/FailureTests.cs new file mode 100644 index 00000000..a11a5eb6 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/FailureTests.cs @@ -0,0 +1,112 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using WixTestTools; + using Xunit; + using Xunit.Abstractions; + + public class FailureTests : BurnE2ETests + { + public FailureTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void CanCancelMsiPackageVeryEarly() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleA = this.CreateBundleInstaller("BundleA"); + var testBAController = this.CreateTestBAController(); + + // Cancel package B right away. + testBAController.SetPackageCancelExecuteAtProgress("PackageB", 1); + + bundleA.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + } + + [Fact] + public void CanCancelMsiPackageVeryLate() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleA = this.CreateBundleInstaller("BundleA"); + var testBAController = this.CreateTestBAController(); + + // Cancel package B at the last moment possible. + testBAController.SetPackageCancelExecuteAtProgress("PackageB", 100); + + bundleA.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + } + + [Fact] + public void CanCancelMsiPackageInOnProgress() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleA = this.CreateBundleInstaller("BundleA"); + var testBAController = this.CreateTestBAController(); + + // Cancel package B during its OnProgress message. + testBAController.SetPackageCancelOnProgressAtProgress("PackageB", 100); + + bundleA.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + } + + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/5750")] + public void CanCancelExecuteWhileCaching() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleB = this.CreateBundleInstaller("BundleB"); + var testBAController = this.CreateTestBAController(); + + // Slow the caching of package B to ensure that package A starts installing and cancels. + testBAController.SetPackageCancelExecuteAtProgress("PackageA", 50); + testBAController.SetPackageSlowCache("PackageB", 2000); + + bundleB.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + } + + /// + /// BundleC has non-vital PackageA and vital PackageB. + /// PackageA is not compressed in the bundle and has a Name different from the source file. The Name points to a file that does not exist. + /// BundleC should be able to install successfully by ignoring the missing PackageA and installing PackageB. + /// + [Fact] + public void CanInstallWhenMissingNonVitalPackage() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleC = this.CreateBundleInstaller("BundleC"); + + var bundleCInstallLogFilePath = bundleC.Install(); + bundleC.VerifyRegisteredAndInPackageCache(); + Assert.True(LogVerifier.MessageInLogFileRegex(bundleCInstallLogFilePath, "Skipping apply of package: PackageA due to cache error: 0x80070002. Continuing...")); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(true); + + bundleC.Uninstall(); + bundleC.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/ForwardCompatibleBundleTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/ForwardCompatibleBundleTests.cs new file mode 100644 index 00000000..eb649c86 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/ForwardCompatibleBundleTests.cs @@ -0,0 +1,469 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.IO; + using WixTestTools; + using Xunit; + using Xunit.Abstractions; + + public class ForwardCompatibleBundleTests : BurnE2ETests + { + public ForwardCompatibleBundleTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + private const string BundleAProviderId = "~" + nameof(ForwardCompatibleBundleTests) + "_BundleA"; + private const string BundleCProviderId = "~" + nameof(ForwardCompatibleBundleTests) + "_BundleC"; + private const string V100 = "1.0.0.0"; + private const string V200 = "2.0.0.0"; + + [Fact] + public void CanTrack1ForwardCompatibleDependentThroughMajorUpgrade() + { + string providerId = BundleAProviderId; + string parent = "~BundleAv1"; + string parentSwitch = String.Concat("-parent ", parent); + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv2 = this.CreatePackageInstaller("PackageAv2"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + + // Install the v1 bundle with a parent. + bundleAv1.Install(arguments: parentSwitch); + bundleAv1.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(true); + packageAv2.VerifyInstalled(false); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion)); + Assert.Equal(V100, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Upgrade with the v2 bundle. + bundleAv2.Install(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Uninstall the v2 bundle and nothing should happen because there is still a parent. + bundleAv2.Uninstall(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Uninstall the v1 bundle with passthrough and all should be removed. + bundleAv1.Uninstall(arguments: parentSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + } + + [Fact] + public void CanTrack1ForwardCompatibleDependentThroughMajorUpgradeWithParentNone() + { + string providerId = BundleAProviderId; + string parent = "~BundleAv1"; + string parentSwitch = String.Concat("-parent ", parent); + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv2 = this.CreatePackageInstaller("PackageAv2"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + + // Install the v1 bundle with a parent. + bundleAv1.Install(arguments: parentSwitch); + bundleAv1.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(true); + packageAv2.VerifyInstalled(false); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion)); + Assert.Equal(V100, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Upgrade with the v2 bundle but prevent self parent being registered. + bundleAv2.Install(arguments: "-parent:none"); + bundleAv2.VerifyRegisteredAndInPackageCache(); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Uninstall the v1 bundle with passthrough and all should be removed. + bundleAv1.Uninstall(arguments: parentSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + } + + [Fact] + public void CanTrack2ForwardCompatibleDependentsThroughMajorUpgrade() + { + string providerId = BundleAProviderId; + string parent = "~BundleAv1"; + string parent2 = "~BundleAv1_Parent2"; + string parentSwitch = String.Concat("-parent ", parent); + string parent2Switch = String.Concat("-parent ", parent2); + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv2 = this.CreatePackageInstaller("PackageAv2"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + + // Install the v1 bundle with a parent. + bundleAv1.Install(arguments: parentSwitch); + bundleAv1.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(true); + packageAv2.VerifyInstalled(false); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion)); + Assert.Equal(V100, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Install the v1 bundle with a second parent. + bundleAv1.Install(arguments: parent2Switch); + bundleAv1.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(true); + packageAv2.VerifyInstalled(false); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V100, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + + // Upgrade with the v2 bundle. + bundleAv2.Install(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + + // Uninstall the v2 bundle and nothing should happen because there is still a parent. + bundleAv2.Uninstall(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + + // Uninstall one parent of the v1 bundle and nothing should happen because there is still a parent. + bundleAv1.Uninstall(arguments: parentSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.False(BundleRegistration.DependencyDependentExists(providerId, parent)); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + + // Uninstall the v1 bundle with passthrough with second parent and all should be removed. + bundleAv1.Uninstall(arguments: parent2Switch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + } + + [Fact] + public void CanTrack2ForwardCompatibleDependentsThroughMajorUpgradePerUser() + { + string providerId = BundleCProviderId; + string parent = "~BundleCv1"; + string parent2 = "~BundleCv1_Parent2"; + string parentSwitch = String.Concat("-parent ", parent); + string parent2Switch = String.Concat("-parent ", parent2); + + var packageCv1 = this.CreatePackageInstaller("PackageCv1"); + var packageCv2 = this.CreatePackageInstaller("PackageCv2"); + var bundleCv1 = this.CreateBundleInstaller("BundleCv1"); + var bundleCv2 = this.CreateBundleInstaller("BundleCv2"); + + packageCv1.VerifyInstalled(false); + packageCv2.VerifyInstalled(false); + + // Install the v1 bundle with a parent. + bundleCv1.Install(arguments: parentSwitch); + bundleCv1.VerifyRegisteredAndInPackageCache(); + + packageCv1.VerifyInstalled(true); + packageCv2.VerifyInstalled(false); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion)); + Assert.Equal(V100, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Install the v1 bundle with a second parent. + bundleCv1.Install(arguments: parent2Switch); + bundleCv1.VerifyRegisteredAndInPackageCache(); + + packageCv1.VerifyInstalled(true); + packageCv2.VerifyInstalled(false); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V100, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + + // Upgrade with the v2 bundle. + bundleCv2.Install(); + bundleCv2.VerifyRegisteredAndInPackageCache(); + bundleCv1.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageCv1.VerifyInstalled(false); + packageCv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + + // Uninstall the v2 bundle and nothing should happen because there is still a parent. + bundleCv2.Uninstall(); + bundleCv2.VerifyRegisteredAndInPackageCache(); + + packageCv1.VerifyInstalled(false); + packageCv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + + // Uninstall one parent of the v1 bundle and nothing should happen because there is still a parent. + bundleCv1.Uninstall(arguments: parentSwitch); + bundleCv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleCv2.VerifyRegisteredAndInPackageCache(); + + packageCv1.VerifyInstalled(false); + packageCv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.False(BundleRegistration.DependencyDependentExists(providerId, parent)); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + + // Uninstall the v1 bundle with passthrough with second parent and all should be removed. + bundleCv1.Uninstall(arguments: parent2Switch); + bundleCv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleCv2.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageCv1.VerifyInstalled(false); + packageCv2.VerifyInstalled(false); + Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + } + + [Fact] + public void CanTrack2ForwardCompatibleDependentsThroughMajorUpgradeWithParent() + { + string providerId = BundleAProviderId; + string parent = "~BundleAv1"; + string parent2 = "~BundleAv1_Parent2"; + string parent3 = "~BundleAv1_Parent3"; + string parentSwitch = String.Concat("-parent ", parent); + string parent2Switch = String.Concat("-parent ", parent2); + string parent3Switch = String.Concat("-parent ", parent3); + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv2 = this.CreatePackageInstaller("PackageAv2"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + + // Install the v1 bundle with a parent. + bundleAv1.Install(arguments: parentSwitch); + bundleAv1.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(true); + packageAv2.VerifyInstalled(false); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion)); + Assert.Equal(V100, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Install the v1 bundle with a second parent. + bundleAv1.Install(arguments: parent2Switch); + bundleAv1.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(true); + packageAv2.VerifyInstalled(false); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V100, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + + // Upgrade with the v2 bundle. + bundleAv2.Install(arguments: parent3Switch); + bundleAv2.VerifyRegisteredAndInPackageCache(); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent3)); + + // Uninstall the v2 bundle and nothing should happen because there is still a parent. + bundleAv2.Uninstall(arguments: parent3Switch); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + Assert.False(BundleRegistration.DependencyDependentExists(providerId, parent3)); + + // Uninstall one parent of the v1 bundle and nothing should happen because there is still a parent. + bundleAv1.Uninstall(arguments: parentSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + Assert.False(BundleRegistration.DependencyDependentExists(providerId, parent)); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2)); + + // Uninstall the v1 bundle with passthrough with second parent and all should be removed. + bundleAv1.Uninstall(arguments: parent2Switch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + } + + [Fact] + public void CanUninstallForwardCompatibleWithBundlesUninstalledInFifoOrder() + { + string providerId = BundleAProviderId; + string parent = "~BundleAv1"; + string parentSwitch = String.Concat("-parent ", parent); + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv2 = this.CreatePackageInstaller("PackageAv2"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + + bundleAv2.Install(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + + // Install the v1 bundle with a parent which should passthrough to v2. + bundleAv1.Install(arguments: parentSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + bundleAv2.Uninstall(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Uninstall the v1 bundle with passthrough and all should be removed. + bundleAv1.Uninstall(arguments: parentSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + } + + [Fact] + public void CanUninstallForwardCompatibleWithBundlesUninstalledInReverseOrder() + { + string providerId = BundleAProviderId; + string parent = "~BundleAv1"; + string parentSwitch = String.Concat("-parent ", parent); + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv2 = this.CreatePackageInstaller("PackageAv2"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + + bundleAv2.Install(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion)); + Assert.Equal(V200, actualProviderVersion); + + // Install the v1 bundle with a parent which should passthrough to v2. + bundleAv1.Install(arguments: parentSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Uninstall the v1 bundle with the same parent which should passthrough to v2 and remove parent. + bundleAv1.Uninstall(arguments: parentSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + Assert.False(BundleRegistration.DependencyDependentExists(providerId, parent)); + + // Uninstall the v2 bundle and all should be removed. + bundleAv2.Uninstall(); + bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/IWebServer.cs b/src/test/burn/WixToolsetTest.BurnE2E/IWebServer.cs new file mode 100644 index 00000000..3bb8a23e --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/IWebServer.cs @@ -0,0 +1,20 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.Collections.Generic; + + public interface IWebServer : IDisposable + { + /// + /// Registers a collection of relative URLs (the key) with its absolute path to the file (the value). + /// + void AddFiles(Dictionary physicalPathsByRelativeUrl); + + /// + /// Starts the web server on a new thread. + /// + void Start(); + } +} \ No newline at end of file diff --git a/src/test/burn/WixToolsetTest.BurnE2E/LayoutTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/LayoutTests.cs new file mode 100644 index 00000000..1e36e2a5 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/LayoutTests.cs @@ -0,0 +1,68 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System.Collections.Generic; + using System.IO; + using WixBuildTools.TestSupport; + using Xunit; + using Xunit.Abstractions; + + public class LayoutTests : BurnE2ETests + { + public LayoutTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void CanLayoutBundleInPlaceWithMissingPayloads() + { + var bundleA = this.CreateBundleInstaller("BundleA"); + var webServer = this.CreateWebServer(); + + webServer.AddFiles(new Dictionary + { + { "/BundleA/LayoutOnlyPayload", Path.Combine(this.TestContext.TestDataFolder, "BundleA.wxs") }, + { "/BundleA/packages.cab", Path.Combine(this.TestContext.TestDataFolder, "packages.cab") }, + }); + webServer.Start(); + + using var dfs = new DisposableFileSystem(); + var layoutDirectory = dfs.GetFolder(true); + + // Manually copy bundle to layout directory and then run from there so the non-compressed payloads have to be resolved. + var bundleAFileInfo = new FileInfo(bundleA.Bundle); + var bundleACopiedPath = Path.Combine(layoutDirectory, bundleAFileInfo.Name); + bundleAFileInfo.CopyTo(bundleACopiedPath); + + bundleA.Layout(bundleACopiedPath, layoutDirectory); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + Assert.True(File.Exists(bundleACopiedPath)); + Assert.True(File.Exists(Path.Combine(layoutDirectory, "packages.cab"))); + Assert.True(File.Exists(Path.Combine(layoutDirectory, "BundleA.wxs"))); + } + + [Fact] + public void CanLayoutBundleToNewDirectory() + { + var bundleA = this.CreateBundleInstaller("BundleA"); + var webServer = this.CreateWebServer(); + + webServer.AddFiles(new Dictionary + { + { "/BundleA/LayoutOnlyPayload", Path.Combine(this.TestContext.TestDataFolder, "BundleA.wxs") }, + { "/BundleA/packages.cab", Path.Combine(this.TestContext.TestDataFolder, "packages.cab") }, + }); + webServer.Start(); + + using var dfs = new DisposableFileSystem(); + var layoutDirectory = dfs.GetFolder(); + + bundleA.Layout(layoutDirectory); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + Assert.True(File.Exists(Path.Combine(layoutDirectory, "BundleA.exe"))); + Assert.True(File.Exists(Path.Combine(layoutDirectory, "packages.cab"))); + Assert.True(File.Exists(Path.Combine(layoutDirectory, "BundleA.wxs"))); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/MsiTransactionTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/MsiTransactionTests.cs new file mode 100644 index 00000000..3d9748bb --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/MsiTransactionTests.cs @@ -0,0 +1,128 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.IO; + using WixTestTools; + using Xunit; + using Xunit.Abstractions; + + public class MsiTransactionTests : BurnE2ETests + { + public MsiTransactionTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void CanUpgradeBundleWithMsiTransaction() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageBv1 = this.CreatePackageInstaller("PackageBv1"); + var packageBv2 = this.CreatePackageInstaller("PackageBv2"); + var packageCv1 = this.CreatePackageInstaller("PackageCv1"); + var packageCv2 = this.CreatePackageInstaller("PackageCv2"); + var packageD = this.CreatePackageInstaller("PackageD"); + + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + + var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs"); + var packageBv1SourceCodeInstalled = packageBv1.GetInstalledFilePath("Package.wxs"); + var packageBv2SourceCodeInstalled = packageBv2.GetInstalledFilePath("Package.wxs"); + var packageCv1SourceCodeInstalled = packageCv1.GetInstalledFilePath("Package.wxs"); + var packageCv2SourceCodeInstalled = packageCv2.GetInstalledFilePath("Package.wxs"); + var packageDSourceCodeInstalled = packageD.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); + Assert.False(File.Exists(packageBv1SourceCodeInstalled), $"Package Bv1 payload should not be there on test start: {packageBv1SourceCodeInstalled}"); + Assert.False(File.Exists(packageBv2SourceCodeInstalled), $"Package Bv2 payload should not be there on test start: {packageBv2SourceCodeInstalled}"); + Assert.False(File.Exists(packageCv1SourceCodeInstalled), $"Package Cv1 payload should not be there on test start: {packageCv1SourceCodeInstalled}"); + Assert.False(File.Exists(packageCv2SourceCodeInstalled), $"Package Cv2 payload should not be there on test start: {packageCv2SourceCodeInstalled}"); + Assert.False(File.Exists(packageDSourceCodeInstalled), $"Package D payload should not be there on test start: {packageDSourceCodeInstalled}"); + + bundleAv1.Install(); + + var bundleAv1CachedPath = bundleAv1.VerifyRegisteredAndInPackageCache(); + + // Source file should be installed + Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled)); + Assert.True(File.Exists(packageBv1SourceCodeInstalled), String.Concat("Should have found Package Bv1 payload installed at: ", packageBv1SourceCodeInstalled)); + Assert.True(File.Exists(packageCv1SourceCodeInstalled), String.Concat("Should have found Package Cv1 payload installed at: ", packageCv1SourceCodeInstalled)); + + bundleAv2.Install(); + + var bundleAv2CachedPath = bundleAv2.VerifyRegisteredAndInPackageCache(); + + // Source file should be upgraded + Assert.True(File.Exists(packageDSourceCodeInstalled), String.Concat("Should have found Package D payload installed at: ", packageDSourceCodeInstalled)); + Assert.True(File.Exists(packageBv2SourceCodeInstalled), String.Concat("Should have found Package Bv2 payload installed at: ", packageBv2SourceCodeInstalled)); + Assert.True(File.Exists(packageCv2SourceCodeInstalled), String.Concat("Should have found Package Cv2 payload installed at: ", packageCv2SourceCodeInstalled)); + Assert.False(File.Exists(packageCv1SourceCodeInstalled), String.Concat("Package Cv1 payload should have been removed by upgrade uninstall from: ", packageCv1SourceCodeInstalled)); + Assert.False(File.Exists(packageBv1SourceCodeInstalled), String.Concat("Package Bv1 payload should have been removed by upgrade uninstall from: ", packageBv1SourceCodeInstalled)); + Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A payload should have been removed by upgrade uninstall from: ", packageASourceCodeInstalled)); + + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(bundleAv1CachedPath); + + // Uninstall everything. + bundleAv2.Uninstall(); + + // Source file should *not* be installed + Assert.False(File.Exists(packageDSourceCodeInstalled), String.Concat("Package D payload should have been removed by uninstall from: ", packageDSourceCodeInstalled)); + Assert.False(File.Exists(packageBv2SourceCodeInstalled), String.Concat("Package Bv2 payload should have been removed by uninstall from: ", packageBv2SourceCodeInstalled)); + Assert.False(File.Exists(packageCv2SourceCodeInstalled), String.Concat("Package Cv2 payload should have been removed by uninstall from: ", packageCv2SourceCodeInstalled)); + + bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(bundleAv2CachedPath); + } + + /// + /// Installs 2 bundles: + /// BundleBv1- installs package Bv1 + /// BundleBv2- installs packages A, Bv2, F + /// package Bv2 performs a major upgrade of package Bv1 + /// package F fails + /// Thus, rolling back the transaction should reinstall package Bv1 + /// + [Fact] + public void CanRelyOnMsiTransactionRollback() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageBv1 = this.CreatePackageInstaller("PackageBv1"); + var packageBv2 = this.CreatePackageInstaller("PackageBv2"); + this.CreatePackageInstaller("PackageF"); + + var bundleBv1 = this.CreateBundleInstaller("BundleBv1"); + var bundleBv2 = this.CreateBundleInstaller("BundleBv2"); + + var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs"); + var packageBv1SourceCodeInstalled = packageBv1.GetInstalledFilePath("Package.wxs"); + var packageBv2SourceCodeInstalled = packageBv2.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); + Assert.False(File.Exists(packageBv1SourceCodeInstalled), $"Package Bv1 payload should not be there on test start: {packageBv1SourceCodeInstalled}"); + Assert.False(File.Exists(packageBv2SourceCodeInstalled), $"Package Bv2 payload should not be there on test start: {packageBv2SourceCodeInstalled}"); + + bundleBv1.Install(); + + bundleBv1.VerifyRegisteredAndInPackageCache(); + + // Source file should be installed + Assert.True(File.Exists(packageBv1SourceCodeInstalled), String.Concat("Should have found Package Bv1 payload installed at: ", packageBv1SourceCodeInstalled)); + + bundleBv2.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE); + + // Bundle v2 should be registered since it installed a non-permanent package. + bundleBv2.VerifyRegisteredAndInPackageCache(); + + // Bundle v1 should not have been removed since the install of v2 failed in the middle of the chain. + bundleBv1.VerifyRegisteredAndInPackageCache(); + + // Source file should be installed + Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled)); + + // Previous source file should be installed + Assert.True(File.Exists(packageBv1SourceCodeInstalled), String.Concat("Should have found Package Bv1 payload installed at: ", packageBv1SourceCodeInstalled)); + Assert.False(File.Exists(packageBv2SourceCodeInstalled), String.Concat("Should not have found Package Bv2 payload installed at: ", packageBv2SourceCodeInstalled)); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/PatchTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/PatchTests.cs new file mode 100644 index 00000000..0c7fdc98 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/PatchTests.cs @@ -0,0 +1,137 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.IO; + using System.Xml; + using Xunit; + using Xunit.Abstractions; + + public class PatchTests : BurnE2ETests + { + public PatchTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void CanRunDetectMultipleTimesWithPatches() + { + var testBAController = this.CreateTestBAController(); + testBAController.SetRedetectCount(1); + + this.CanInstallBundleWithPatchThenRemoveIt(); + } + + [Fact] + public void CanInstallBundleWithPatchThenRemoveIt() + { + var originalVersion = "1.0.0.0"; + var patchedVersion = "1.0.1.0"; + var testRegistryValue = "PackageA"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var bundleA = this.CreateBundleInstaller("BundleA"); + var bundlePatchA = this.CreateBundleInstaller("BundlePatchA"); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(true); + packageAv1.VerifyTestRegistryValue(testRegistryValue, originalVersion); + + bundlePatchA.Install(); + bundlePatchA.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyTestRegistryValue(testRegistryValue, patchedVersion); + + bundlePatchA.Uninstall(); + bundlePatchA.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyTestRegistryValue(testRegistryValue, originalVersion); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv1.VerifyTestRegistryRootDeleted(); + } + + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6380")] + public void CanPatchSwidTag() + { + var originalVersion = "1.0.0.0"; + var patchedVersion = "1.0.1.0"; + var packageTagName = "~PatchTests - PackageA"; + var bundleTagName = "~PatchTests - BundleA"; + var bundlePatchTagName = "~PatchTests - BundlePatchA"; + + this.CreatePackageInstaller("PackageAv1"); + var bundleA = this.CreateBundleInstaller("BundleA"); + var bundlePatchA = this.CreateBundleInstaller("BundlePatchA"); + + bundleA.Install(); + VerifySwidTagVersion(bundleTagName, originalVersion); + VerifySwidTagVersion(packageTagName, originalVersion); + + bundlePatchA.Install(); + VerifySwidTagVersion(bundlePatchTagName, patchedVersion); + VerifySwidTagVersion(packageTagName, patchedVersion); + + bundlePatchA.Uninstall(); + VerifySwidTagVersion(packageTagName, originalVersion); + + bundleA.Uninstall(); + VerifySwidTagVersion(bundleTagName, null); + VerifySwidTagVersion(packageTagName, null); + } + + [Fact] + public void CanInstallBundleWithPatchesTargetingSingleProductThenRemoveIt() + { + var originalVersion = "1.0.0.0"; + var patchedVersion = "1.0.1.0"; + var testRegistryValue = "PackageA"; + var testRegistryValue2 = "PackageA2"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var bundlePatchA2 = this.CreateBundleInstaller("BundlePatchA2"); + + packageAv1.InstallProduct(); + packageAv1.VerifyInstalled(true); + packageAv1.VerifyTestRegistryValue(testRegistryValue, originalVersion); + packageAv1.VerifyTestRegistryValue(testRegistryValue2, originalVersion); + + bundlePatchA2.Install(); + bundlePatchA2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyTestRegistryValue(testRegistryValue, patchedVersion); + packageAv1.VerifyTestRegistryValue(testRegistryValue2, patchedVersion); + + bundlePatchA2.Uninstall(); + bundlePatchA2.VerifyUnregisteredAndRemovedFromPackageCache(); + + packageAv1.VerifyTestRegistryValue(testRegistryValue, originalVersion); + packageAv1.VerifyTestRegistryValue(testRegistryValue2, originalVersion); + } + + private static void VerifySwidTagVersion(string tagName, string expectedVersion) + { + var regidFolder = Environment.ExpandEnvironmentVariables(@"%ProgramData%\regid.1995-08.com.example"); + var tagPath = Path.Combine(regidFolder, "regid.1995-08.com.example " + tagName + ".swidtag"); + string version = null; + + if (File.Exists(tagPath)) + { + var doc = new XmlDocument(); + doc.Load(tagPath); + + var ns = new XmlNamespaceManager(doc.NameTable); + ns.AddNamespace("s", "http://standards.iso.org/iso/19770/-2/2009/schema.xsd"); + + var versionNode = doc.SelectSingleNode("/s:software_identification_tag/s:product_version/s:name", ns); + version = versionNode?.InnerText ?? String.Empty; + } + + Assert.Equal(expectedVersion, version); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs new file mode 100644 index 00000000..ced2e08e --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs @@ -0,0 +1,76 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.IO; + using Xunit; + using Xunit.Abstractions; + + public class PrereqBaTests : BurnE2ETests + { + public PrereqBaTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + /// + /// This bundle purposely provides a .runtimeconfig.json file that requires a version of .NET Core that doesn't exist, + /// with an MSI package to represent the prerequisite package. + /// This verifies that: + /// The preqba doesn't infinitely reload itself after failing to load the managed BA. + /// The engine automatically uninstalls the bundle since only permanent packages were installed. + /// + [Fact] + public void DncPreqBaDetectsInfiniteLoop() + { + var packageA = this.CreatePackageInstaller("PackageA"); + this.CreatePackageInstaller("PackageF"); + + var bundleA = this.CreateBundleInstaller("BundleA"); + + var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); + + bundleA.Install(); + + // Part of the test is Install actually completing. + + // Source file should be installed + Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled)); + + // No non-permanent packages should have ended up installed or cached so it should have unregistered. + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + } + + /// + /// This bundle purposely provides a WixToolset.Mba.Host.config file that requires a version of .NET Framework that doesn't exist, + /// with an MSI package to represent the prerequisite package. + /// This verifies that: + /// The preqba doesn't infinitely reload itself after failing to load the managed BA. + /// The engine automatically uninstalls the bundle since only permanent packages were installed. + /// + [Fact] + public void MbaPreqBaDetectsInfiniteLoop() + { + var packageB = this.CreatePackageInstaller("PackageB"); + this.CreatePackageInstaller("PackageF"); + + var bundleB = this.CreateBundleInstaller("BundleB"); + + var packageBSourceCodeInstalled = packageB.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}"); + + bundleB.Install(); + + // Part of the test is Install actually completing. + + // Source file should be installed + Assert.True(File.Exists(packageBSourceCodeInstalled), String.Concat("Should have found Package B payload installed at: ", packageBSourceCodeInstalled)); + + // No non-permanent packages should have ended up installed or cached so it should have unregistered. + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/RegistrationTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/RegistrationTests.cs new file mode 100644 index 00000000..51122c28 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/RegistrationTests.cs @@ -0,0 +1,78 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using Xunit; + using Xunit.Abstractions; + + public class RegistrationTests : BurnE2ETests + { + public RegistrationTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void AutomaticallyUncachesBundleWhenNotInstalled() + { + var bundleA = this.CreateBundleInstaller("BundleA"); + var testBAController = this.CreateTestBAController(); + + var cachedBundlePath = bundleA.ManuallyCache(); + + testBAController.SetQuitAfterDetect(); + + bundleA.Install(cachedBundlePath); + + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + } + + [Fact] + public void AutomaticallyUninstallsBundleWithoutBADoingApply() + { + this.InstallBundleThenManuallyUninstallPackageAndRemovePackageFromCacheThenRunAndQuitWithoutApply(true); + } + + [Fact] + public void AutomaticallyUninstallsBundleWithoutBADoingDetect() + { + this.InstallBundleThenManuallyUninstallPackageAndRemovePackageFromCacheThenRunAndQuitWithoutApply(false); + } + + [Fact] + public void RegistersInARPIfPrecached() + { + var bundleA = this.CreateBundleInstaller("BundleA"); + + bundleA.ManuallyCache(); + + // Verifies https://github.com/wixtoolset/issues/issues/5702 + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + } + + private void InstallBundleThenManuallyUninstallPackageAndRemovePackageFromCacheThenRunAndQuitWithoutApply(bool detect) + { + var packageA = this.CreatePackageInstaller("PackageA"); + var bundleA = this.CreateBundleInstaller("BundleA"); + var testBAController = this.CreateTestBAController(); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + packageA.VerifyInstalled(true); + + packageA.UninstallProduct(); + bundleA.RemovePackageFromCache("PackageA"); + + if (detect) + { + testBAController.SetQuitAfterDetect(); + } + else + { + testBAController.SetImmediatelyQuit(); + } + bundleA.Install(); + packageA.VerifyInstalled(false); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/RollbackBoundaryTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/RollbackBoundaryTests.cs new file mode 100644 index 00000000..6539db34 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/RollbackBoundaryTests.cs @@ -0,0 +1,52 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.IO; + using Xunit; + using Xunit.Abstractions; + + public class RollbackBoundaryTests : BurnE2ETests + { + public RollbackBoundaryTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + /// + /// Installs 1 bundle: + /// chain - non-vital rollback boundary, package F, package A, vital rollback boundary, package B + /// package F fails + /// package A and B are permanent + /// Execution is supposed to be: + /// package F (fails) + /// rollback to non-vital rollback boundary which ignores the error and skips over package A + /// install package B + /// unregister since no non-permanent packages should be installed or cached. + /// + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6309")] + public void NonVitalRollbackBoundarySkipsToNextRollbackBoundary() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageB = this.CreatePackageInstaller("PackageB"); + this.CreatePackageInstaller("PackageC"); + this.CreatePackageInstaller("PackageF"); + + var bundleA = this.CreateBundleInstaller("BundleA"); + + var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs"); + var packageBSourceCodeInstalled = packageB.GetInstalledFilePath("Package.wxs"); + + // Source file should *not* be installed + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); + Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}"); + + bundleA.Install(); + + // No non-permanent packages should have ended up installed or cached so it should have unregistered. + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + + // Only PackageB source file should be installed + Assert.True(File.Exists(packageBSourceCodeInstalled), String.Concat("Should have found Package B payload installed at: ", packageBSourceCodeInstalled)); + Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Should not have found Package A payload installed at: ", packageASourceCodeInstalled)); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/SlipstreamTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/SlipstreamTests.cs new file mode 100644 index 00000000..29632e2e --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/SlipstreamTests.cs @@ -0,0 +1,353 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.IO; + using WixTestTools; + using WixToolset.Mba.Core; + using Xunit; + using Xunit.Abstractions; + + public class SlipstreamTests : BurnE2ETests + { + public SlipstreamTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + private const string V090 = "0.9.0.0"; + private const string V100 = "1.0.0.0"; + private const string V101 = "1.0.1.0"; + + [Fact] + public void CanInstallBundleWithSlipstreamedPatchThenRemoveIt() + { + var testRegistryValue = "PackageA"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var bundleA = this.CreateBundleInstaller("BundleA"); + + var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs"); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}"); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V101); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryRootDeleted(); + } + + /// + /// BundleA installs PackageA with slipstreamed PatchA. + /// BundleOnlyPatchA is installed which contains PatchA (which should be a no-op). + /// BundleOnlyPatchA in uninstalled which should do nothing since BundleA has a dependency on it. + /// Bundle is installed which should remove everything. + /// + [Fact] + public void ReferenceCountsSlipstreamedPatch() + { + var testRegistryValue = "PackageA"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var bundleOnlyPatchA = this.CreateBundleInstaller("BundleOnlyPatchA"); + var bundleA = this.CreateBundleInstaller("BundleA"); + + var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs"); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}"); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V101); + + bundleOnlyPatchA.Install(); + bundleOnlyPatchA.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V101); + + bundleOnlyPatchA.Uninstall(); + bundleOnlyPatchA.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V101); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryRootDeleted(); + } + + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6350")] + public void CanInstallBundleWithSlipstreamedPatchThenRepairIt() + { + this.InstallBundleWithSlipstreamedPatchThenRepairIt(false); + } + + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6350")] + public void CanInstallReversedBundleWithSlipstreamedPatchThenRepairIt() + { + this.InstallBundleWithSlipstreamedPatchThenRepairIt(true); + } + + private void InstallBundleWithSlipstreamedPatchThenRepairIt(bool isReversed) + { + var bundleName = isReversed ? "BundleAReverse" : "BundleA"; + var testRegistryValue = "PackageA"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var bundleA = this.CreateBundleInstaller(bundleName); + + var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs"); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}"); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V101); + + // Delete the installed file and registry key so we have something to repair. + File.Delete(packageAv1SourceCodeInstalled); + packageAv1.DeleteTestRegistryValue(testRegistryValue); + + bundleA.Repair(); + bundleA.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V101); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryRootDeleted(); + } + + [Fact] + public void CanInstallSlipstreamedPatchThroughForcedRepair() + { + this.InstallSlipstreamedPatchThroughForcedRepair(false); + } + + [Fact] + public void CanInstallSlipstreamedPatchThroughReversedForcedRepair() + { + this.InstallSlipstreamedPatchThroughForcedRepair(true); + } + + private void InstallSlipstreamedPatchThroughForcedRepair(bool isReversed) + { + var bundleName = isReversed ? "BundleAReverse" : "BundleA"; + var testRegistryValue = "PackageA"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var bundleA = this.CreateBundleInstaller(bundleName); + var bundleOnlyA = this.CreateBundleInstaller("BundleOnlyA"); + var testBAController = this.CreateTestBAController(); + + var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs"); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}"); + + bundleOnlyA.Install(); + bundleOnlyA.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V100); + + // Delete the installed file and registry key so we have something to repair. + File.Delete(packageAv1SourceCodeInstalled); + packageAv1.DeleteTestRegistryValue(testRegistryValue); + + testBAController.SetPackageRequestedState("PackageA", RequestState.Repair); + testBAController.SetPackageRequestedState("PatchA", RequestState.Repair); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V101); + + testBAController.ResetPackageStates("PackageA"); + testBAController.ResetPackageStates("PatchA"); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V100); + + bundleOnlyA.Uninstall(); + bundleOnlyA.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryRootDeleted(); + } + + [Fact] + public void CanUninstallSlipstreamedPatchAlone() + { + var testRegistryValue = "PackageA"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var bundleA = this.CreateBundleInstaller("BundleA"); + var testBAController = this.CreateTestBAController(); + + var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs"); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}"); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V101); + + testBAController.SetPackageRequestedState("PatchA", RequestState.Absent); + + bundleA.Modify(); + bundleA.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V100); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryRootDeleted(); + } + + [Fact] + public void CanModifyToUninstallPackageWithSlipstreamedPatch() + { + var testRegistryValue = "PackageA"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageBv1 = this.CreatePackageInstaller("PackageBv1"); + var bundleB = this.CreateBundleInstaller("BundleB"); + var testBAController = this.CreateTestBAController(); + + var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs"); + var packageBv1SourceCodeInstalled = packageBv1.GetInstalledFilePath("Package.wxs"); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}"); + Assert.False(File.Exists(packageBv1SourceCodeInstalled), $"PackageBv1 payload should not be there on test start: {packageBv1SourceCodeInstalled}"); + + bundleB.Install(); + bundleB.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V101); + Assert.True(File.Exists(packageBv1SourceCodeInstalled), String.Concat("Should have found PackageBv1 payload installed at: ", packageBv1SourceCodeInstalled)); + + testBAController.SetPackageRequestedState("PackageA", RequestState.Absent); + testBAController.SetPackageRequestedState("PatchA", RequestState.Absent); + + bundleB.Modify(); + bundleB.VerifyRegisteredAndInPackageCache(); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should have been removed by modify from: {packageAv1SourceCodeInstalled}"); + + testBAController.ResetPackageStates("PackageA"); + testBAController.ResetPackageStates("PatchA"); + + bundleB.Uninstall(); + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.False(File.Exists(packageBv1SourceCodeInstalled), String.Concat("PackageBv1 payload should have been removed by uninstall from: ", packageBv1SourceCodeInstalled)); + packageBv1.VerifyTestRegistryRootDeleted(); + } + + [Fact] + public void UninstallsPackageWithSlipstreamedPatchDuringRollback() + { + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageBv1 = this.CreatePackageInstaller("PackageBv1"); + var bundleB = this.CreateBundleInstaller("BundleB"); + var testBAController = this.CreateTestBAController(); + + var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs"); + var packageBv1SourceCodeInstalled = packageBv1.GetInstalledFilePath("Package.wxs"); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}"); + Assert.False(File.Exists(packageBv1SourceCodeInstalled), $"PackageBv1 payload should not be there on test start: {packageBv1SourceCodeInstalled}"); + + testBAController.SetPackageCancelExecuteAtProgress("PackageB", 50); + + bundleB.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should have been removed by rollback from: {packageAv1SourceCodeInstalled}"); + Assert.False(File.Exists(packageBv1SourceCodeInstalled), String.Concat("PackageBv1 payload should not have been installed from: ", packageBv1SourceCodeInstalled)); + packageBv1.VerifyTestRegistryRootDeleted(); + } + + [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6359")] + public void CanAutomaticallyPredetermineSlipstreamPatchesAtBuildTime() + { + var testRegistryValueA = "PackageA"; + var testRegistryValueA2 = "PackageA2"; + var testRegistryValueB = "PackageB"; + var testRegistryValueB2 = "PackageB2"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageBv1 = this.CreatePackageInstaller("PackageBv1"); + var bundleC = this.CreateBundleInstaller("BundleC"); + + var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs"); + var packageBv1SourceCodeInstalled = packageBv1.GetInstalledFilePath("Package.wxs"); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}"); + Assert.False(File.Exists(packageBv1SourceCodeInstalled), $"PackageBv1 payload should not be there on test start: {packageBv1SourceCodeInstalled}"); + + bundleC.Install(); + bundleC.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + // Product A should've slipstreamed both patches. + packageAv1.VerifyTestRegistryValue(testRegistryValueA, V101); + packageAv1.VerifyTestRegistryValue(testRegistryValueA2, V101); + // Product B should've only slipstreamed patch AB2. + packageBv1.VerifyTestRegistryValue(testRegistryValueB, V100); + packageBv1.VerifyTestRegistryValue(testRegistryValueB2, V101); + + bundleC.Uninstall(); + bundleC.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled)); + Assert.False(File.Exists(packageBv1SourceCodeInstalled), String.Concat("PackageBv1 payload should have been removed by uninstall from: ", packageBv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryRootDeleted(); + } + + [Fact] + public void CanInstallSlipstreamedPatchWithPackageDuringMajorUpgrade() + { + var testRegistryValue = "PackageA"; + + var packageAv0 = this.CreatePackageInstaller("PackageAv0_9_0"); + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var bundleA = this.CreateBundleInstaller("BundleA"); + + packageAv1.VerifyInstalled(false); + + packageAv0.InstallProduct(); + packageAv0.VerifyInstalled(true); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V090); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + packageAv0.VerifyInstalled(false); + packageAv1.VerifyInstalled(true); + packageAv1.VerifyTestRegistryValue(testRegistryValue, V101); + + bundleA.Uninstall(); + bundleA.VerifyUnregisteredAndRemovedFromPackageCache(); + packageAv1.VerifyInstalled(false); + packageAv1.VerifyTestRegistryRootDeleted(); + } + + [Fact] + public void RespectsSlipstreamedPatchInstallCondition() + { + var testRegistryValue = "PackageA"; + + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var bundleD = this.CreateBundleInstaller("BundleD"); + + var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs"); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}"); + + bundleD.Install(); + bundleD.VerifyRegisteredAndInPackageCache(); + Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled)); + // The patch was not supposed to be installed. + packageAv1.VerifyTestRegistryValue(testRegistryValue, V100); + + bundleD.Uninstall(); + bundleD.VerifyUnregisteredAndRemovedFromPackageCache(); + Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled)); + packageAv1.VerifyTestRegistryRootDeleted(); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs b/src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs new file mode 100644 index 00000000..6e4fe6c6 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs @@ -0,0 +1,187 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using Microsoft.Win32; + using WixTestTools; + using WixToolset.Mba.Core; + + public class TestBAController : IDisposable + { + public TestBAController(WixTestContext testContext, bool x64 = false) + { + this.TestGroupName = testContext.TestGroupName; + this.BaseRegKeyPath = x64 ? @"Software\WiX\Tests" : @"Software\WOW6432Node\WiX\Tests"; + this.TestBaseRegKeyPath = String.Format(@"{0}\TestBAControl\{1}", this.BaseRegKeyPath, this.TestGroupName); + } + + private string BaseRegKeyPath { get; } + + private string TestBaseRegKeyPath { get; } + + public string TestGroupName { get; } + + /// + /// Sets a test value in the registry to communicate with the TestBA. + /// + /// Name of the value to set. + /// Value to set. If this is null, the value is removed. + public void SetBurnTestValue(string name, string value) + { + using (var testKey = Registry.LocalMachine.CreateSubKey(this.TestBaseRegKeyPath)) + { + if (String.IsNullOrEmpty(value)) + { + testKey.DeleteValue(name, false); + } + else + { + testKey.SetValue(name, value); + } + } + } + + public void SetExplicitlyElevateAndPlanFromOnElevateBegin(string value = "true") + { + this.SetBurnTestValue("ExplicitlyElevateAndPlanFromOnElevateBegin", value); + } + + public void SetImmediatelyQuit(string value = "true") + { + this.SetBurnTestValue("ImmediatelyQuit", value); + } + + public void SetQuitAfterDetect(string value = "true") + { + this.SetBurnTestValue("QuitAfterDetect", value); + } + + /// + /// Slows the cache progress of a package. + /// + /// Package identity. + /// Sets or removes the delay on a package being cached. + public void SetPackageSlowCache(string packageId, int? delay) + { + this.SetPackageState(packageId, "SlowCache", delay.HasValue ? delay.ToString() : null); + } + + /// + /// Cancels the cache of a package at a particular progress point. + /// + /// Package identity. + /// Sets or removes the cancel progress on a package being cached. + public void SetPackageCancelCacheAtProgress(string packageId, int? cancelPoint) + { + this.SetPackageState(packageId, "CancelCacheAtProgress", cancelPoint.HasValue ? cancelPoint.ToString() : null); + } + + /// + /// Slows the execute progress of a package. + /// + /// Package identity. + /// Sets or removes the delay on a package being executed. + public void SetPackageSlowExecute(string packageId, int? delay) + { + this.SetPackageState(packageId, "SlowExecute", delay.HasValue ? delay.ToString() : null); + } + + /// + /// Cancels the execute of a package at a particular progress point. + /// + /// Package identity. + /// Sets or removes the cancel progress on a package being executed. + public void SetPackageCancelExecuteAtProgress(string packageId, int? cancelPoint) + { + this.SetPackageState(packageId, "CancelExecuteAtProgress", cancelPoint.HasValue ? cancelPoint.ToString() : null); + } + + /// + /// Cancels the execute of a package at the next progess after the specified MSI action start. + /// + /// Package identity. + /// Sets or removes the cancel progress on a package being executed. + public void SetPackageCancelExecuteAtActionStart(string packageId, string actionName) + { + this.SetPackageState(packageId, "CancelExecuteAtActionStart", actionName); + } + + /// + /// Cancels the execute of a package at a particular OnProgress point. + /// + /// Package identity. + /// Sets or removes the cancel OnProgress point on a package being executed. + public void SetPackageCancelOnProgressAtProgress(string packageId, int? cancelPoint) + { + this.SetPackageState(packageId, "CancelOnProgressAtProgress", cancelPoint.HasValue ? cancelPoint.ToString() : null); + } + + /// + /// Sets the requested state for a package that the TestBA will return to the engine during plan. + /// + /// Package identity. + /// State to request. + public void SetPackageRequestedState(string packageId, RequestState state) + { + this.SetPackageState(packageId, "Requested", state.ToString()); + } + + /// + /// Sets the requested state for a package that the TestBA will return to the engine during plan. + /// + /// Package identity. + /// State to request. + public void SetPackageFeatureState(string packageId, string featureId, FeatureState state) + { + this.SetPackageState(packageId, String.Concat(featureId, "Requested"), state.ToString()); + } + + /// + /// Sets the number of times to re-run the Detect phase. + /// + /// Number of times to run Detect (after the first, normal, Detect). + public void SetRedetectCount(int redetectCount) + { + this.SetPackageState(null, "RedetectCount", redetectCount.ToString()); + } + + /// + /// Resets the state for a package that the TestBA will return to the engine during plan. + /// + /// Package identity. + public void ResetPackageStates(string packageId) + { + var key = String.Format(@"{0}\{1}", this.TestBaseRegKeyPath, packageId ?? String.Empty); + Registry.LocalMachine.DeleteSubKey(key); + } + + public void SetVerifyArguments(string verifyArguments) + { + this.SetBurnTestValue("VerifyArguments", verifyArguments); + + } + + private void SetPackageState(string packageId, string name, string value) + { + var key = String.Format(@"{0}\{1}", this.TestBaseRegKeyPath, packageId ?? String.Empty); + using (var packageKey = Registry.LocalMachine.CreateSubKey(key)) + { + if (String.IsNullOrEmpty(value)) + { + packageKey.DeleteValue(name, false); + } + else + { + packageKey.SetValue(name, value); + } + } + } + + public void Dispose() + { + Registry.LocalMachine.DeleteSubKeyTree($@"{this.BaseRegKeyPath}\{this.TestGroupName}", false); + Registry.LocalMachine.DeleteSubKeyTree($@"{this.BaseRegKeyPath}\TestBAControl", false); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/UpdateBundleTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/UpdateBundleTests.cs new file mode 100644 index 00000000..9fcd428b --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/UpdateBundleTests.cs @@ -0,0 +1,245 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using Xunit; + using Xunit.Abstractions; + + public class UpdateBundleTests : BurnE2ETests + { + public UpdateBundleTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void CanLaunchUpdateBundleFromLocalSourceInsteadOfInstall() + { + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv2 = this.CreatePackageInstaller("PackageAv2"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + + var updateBundleSwitch = String.Concat("\"", "-updatebundle:", bundleAv2.Bundle, "\""); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + + // Install the v2 bundle by getting v1 to launch it as an update bundle. + bundleAv1.Install(arguments: updateBundleSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + + bundleAv2.Uninstall(); + bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(); + packageAv2.VerifyInstalled(false); + } + + [Fact] + public void CanLaunchUpdateBundleFromLocalSourceInsteadOfModify() + { + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv2 = this.CreatePackageInstaller("PackageAv2"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + + var updateBundleSwitch = String.Concat("\"", "-updatebundle:", bundleAv2.Bundle, "\""); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + + bundleAv1.Install(); + bundleAv1.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(true); + packageAv2.VerifyInstalled(false); + + // Install the v2 bundle by getting v1 to launch it as an update bundle. + bundleAv1.Modify(arguments: updateBundleSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + + bundleAv2.Uninstall(); + bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(); + packageAv2.VerifyInstalled(false); + } + + [Fact] + public void ForwardsArgumentsToUpdateBundle() + { + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv2 = this.CreatePackageInstaller("PackageAv2"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + var testBAController = this.CreateTestBAController(); + + const string verifyArguments = "these arguments should exist"; + var updateBundleSwitch = String.Concat("\"", "-updatebundle:", bundleAv2.Bundle, "\" ", verifyArguments); + + testBAController.SetVerifyArguments(verifyArguments); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(false); + + // Install the v2 bundle by getting v1 to launch it as an update bundle. + bundleAv1.Install(arguments: updateBundleSwitch); + bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + packageAv1.VerifyInstalled(false); + packageAv2.VerifyInstalled(true); + + // Attempt to uninstall bundleA2 without the verify arguments passed and expect failure code. + bundleAv2.Uninstall(expectedExitCode: -1); + + // Remove the required arguments and uninstall again. + testBAController.SetVerifyArguments(null); + bundleAv2.Uninstall(); + bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(); + packageAv2.VerifyInstalled(false); + } + + // Installs bundle Bv1.0 then tries to update to latest version during modify (but no server exists). + [Fact] + public void CanCheckUpdateServerDuringModifyAndDoNothingWhenServerIsntResponsive() + { + var packageB = this.CreatePackageInstaller("PackageBv1"); + var bundleB = this.CreateBundleInstaller("BundleBv1"); + + packageB.VerifyInstalled(false); + + bundleB.Install(); + bundleB.VerifyRegisteredAndInPackageCache(); + + packageB.VerifyInstalled(true); + + // Run the v1 bundle requesting an update bundle. + bundleB.Modify(arguments: "-checkupdate"); + bundleB.VerifyRegisteredAndInPackageCache(); + + // Verify nothing changed. + packageB.VerifyInstalled(true); + + bundleB.Uninstall(); + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); + packageB.VerifyInstalled(false); + } + + // Installs bundle Bv1.0 then tries to update to latest version during modify (server exists, no feed). + [Fact] + public void CanCheckUpdateServerDuringModifyAndDoNothingWhenFeedIsMissing() + { + var packageB = this.CreatePackageInstaller("PackageBv1"); + var bundleB = this.CreateBundleInstaller("BundleBv1"); + var webServer = this.CreateWebServer(); + + webServer.Start(); + + packageB.VerifyInstalled(false); + + bundleB.Install(); + bundleB.VerifyRegisteredAndInPackageCache(); + + packageB.VerifyInstalled(true); + + // Run the v1 bundle requesting an update bundle. + bundleB.Modify(arguments: "-checkupdate"); + bundleB.VerifyRegisteredAndInPackageCache(); + + // Verify nothing changed. + packageB.VerifyInstalled(true); + + bundleB.Uninstall(); + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); + packageB.VerifyInstalled(false); + } + + // Installs bundle Bv1.0 then tries to update to latest version during modify (server exists, v1.0 feed). + [Fact] + public void CanCheckUpdateServerDuringModifyAndDoNothingWhenAlreadyLatestVersion() + { + var packageB = this.CreatePackageInstaller("PackageBv1"); + var bundleB = this.CreateBundleInstaller("BundleBv1"); + var webServer = this.CreateWebServer(); + + webServer.AddFiles(new Dictionary + { + { "/BundleB/feed", Path.Combine(this.TestContext.TestDataFolder, "FeedBv1.0.xml") }, + }); + webServer.Start(); + + packageB.VerifyInstalled(false); + + bundleB.Install(); + bundleB.VerifyRegisteredAndInPackageCache(); + + packageB.VerifyInstalled(true); + + // Run the v1 bundle requesting an update bundle. + bundleB.Modify(arguments: "-checkupdate"); + bundleB.VerifyRegisteredAndInPackageCache(); + + // Verify nothing changed. + packageB.VerifyInstalled(true); + + bundleB.Uninstall(); + bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); + packageB.VerifyInstalled(false); + } + + // Installs bundle Bv1.0 then does an update to bundle Bv2.0 during modify (server exists, v2.0 feed). + [Fact] + public void CanLaunchUpdateBundleFromDownloadInsteadOfModify() + { + var packageBv1 = this.CreatePackageInstaller("PackageBv1"); + var packageBv2 = this.CreatePackageInstaller("PackageBv2"); + var bundleBv1 = this.CreateBundleInstaller("BundleBv1"); + var bundleBv2 = this.CreateBundleInstaller("BundleBv2"); + var webServer = this.CreateWebServer(); + + webServer.AddFiles(new Dictionary + { + { "/BundleB/feed", Path.Combine(this.TestContext.TestDataFolder, "FeedBv2.0.xml") }, + { "/BundleB/2.0/BundleB.exe", bundleBv2.Bundle }, + }); + webServer.Start(); + + packageBv1.VerifyInstalled(false); + packageBv2.VerifyInstalled(false); + + bundleBv1.Install(); + bundleBv1.VerifyRegisteredAndInPackageCache(); + + packageBv1.VerifyInstalled(true); + packageBv2.VerifyInstalled(false); + + // Run the v1 bundle requesting an update bundle. + bundleBv1.Modify(arguments: "-checkupdate"); + + // The modify -> update is asynchronous, so we need to wait until the real BundleB is done + var childBundles = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(bundleBv2.Bundle)); + foreach (var childBundle in childBundles) + { + childBundle.WaitForExit(); + } + + bundleBv1.VerifyUnregisteredAndRemovedFromPackageCache(); + bundleBv2.VerifyRegisteredAndInPackageCache(); + + packageBv1.VerifyInstalled(false); + packageBv2.VerifyInstalled(true); + + bundleBv2.Uninstall(); + bundleBv2.VerifyUnregisteredAndRemovedFromPackageCache(); + packageBv1.VerifyInstalled(false); + packageBv2.VerifyInstalled(false); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/UpgradeRelatedBundleTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/UpgradeRelatedBundleTests.cs new file mode 100644 index 00000000..70c0c474 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/UpgradeRelatedBundleTests.cs @@ -0,0 +1,36 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.IO; + using WixTestTools; + using Xunit; + using Xunit.Abstractions; + + public class UpgradeRelatedBundleTests : BurnE2ETests + { + public UpgradeRelatedBundleTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void ReportsRelatedBundleMissingFromCache() + { + var packageAv1 = this.CreatePackageInstaller("PackageAv1"); + var packageAv2 = this.CreatePackageInstaller("PackageAv2"); + var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); + var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); + + bundleAv1.Install(); + bundleAv1.VerifyRegisteredAndInPackageCache(); + + bundleAv1.ManuallyUncache(); + + // Verify https://github.com/wixtoolset/issues/issues/4991 + var bundleAv2InstallLogFilePath = bundleAv2.Install(); + bundleAv2.VerifyRegisteredAndInPackageCache(); + + Assert.True(LogVerifier.MessageInLogFileRegex(bundleAv2InstallLogFilePath, @"OnDetectRelatedBundle\(\) - id: \{[0-9A-Za-z\-]{36}\}, missing from cache: True")); + Assert.True(LogVerifier.MessageInLogFileRegex(bundleAv2InstallLogFilePath, @"Detected related bundle: \{[0-9A-Za-z\-]{36}\}, type: Upgrade, scope: PerMachine, version: 1\.0\.0\.0, operation: MajorUpgrade, cached: No")); + } + } +} diff --git a/src/test/burn/WixToolsetTest.BurnE2E/WebServer/CoreOwinWebServer.cs b/src/test/burn/WixToolsetTest.BurnE2E/WebServer/CoreOwinWebServer.cs new file mode 100644 index 00000000..89825813 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/WebServer/CoreOwinWebServer.cs @@ -0,0 +1,70 @@ +// 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. + +namespace WixToolsetTest.BurnE2E +{ + using System; + using System.Collections.Generic; + using System.IO; + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Hosting; + using Microsoft.Extensions.FileProviders; + using Microsoft.Extensions.FileProviders.Physical; + using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Primitives; + + public class CoreOwinWebServer : IWebServer, IFileProvider + { + private Dictionary PhysicalPathsByRelativeUrl { get; } = new Dictionary(); + + private IHost WebHost { get; set; } + + public void AddFiles(Dictionary physicalPathsByRelativeUrl) + { + foreach (var kvp in physicalPathsByRelativeUrl) + { + this.PhysicalPathsByRelativeUrl.Add(kvp.Key, kvp.Value); + } + } + + public void Start() + { + this.WebHost = Host.CreateDefaultBuilder() + .ConfigureWebHostDefaults(webBuilder => + { + // Use localhost instead of * to avoid firewall issues. + webBuilder.UseUrls("http://localhost:9999"); + webBuilder.Configure(appBuilder => + { + appBuilder.UseStaticFiles(new StaticFileOptions + { + FileProvider = this, + RequestPath = "/e2e", + ServeUnknownFileTypes = true, + }); + }); + }) + .Build(); + this.WebHost.Start(); + } + + public void Dispose() + { + var waitTime = TimeSpan.FromSeconds(5); + this.WebHost?.StopAsync(waitTime).Wait(waitTime); + } + + public IDirectoryContents GetDirectoryContents(string subpath) => throw new NotImplementedException(); + + public IFileInfo GetFileInfo(string subpath) + { + if (this.PhysicalPathsByRelativeUrl.TryGetValue(subpath, out var filepath)) + { + return new PhysicalFileInfo(new FileInfo(filepath)); + } + + return new NotFoundFileInfo(subpath); + } + + public IChangeToken Watch(string filter) => throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/test/burn/WixToolsetTest.BurnE2E/WixToolsetTest.BurnE2E.csproj b/src/test/burn/WixToolsetTest.BurnE2E/WixToolsetTest.BurnE2E.csproj new file mode 100644 index 00000000..2aee1157 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/WixToolsetTest.BurnE2E.csproj @@ -0,0 +1,33 @@ + + + + + + netcoreapp3.1 + x64 + Major + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/WixToolsetTest.BurnE2E/runtests.cmd b/src/test/burn/WixToolsetTest.BurnE2E/runtests.cmd new file mode 100644 index 00000000..4c6dc8ee --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/runtests.cmd @@ -0,0 +1,2 @@ +SET RuntimeTestsEnabled=true +dotnet test WixToolsetTest.BurnE2E.dll -v normal \ No newline at end of file diff --git a/src/test/burn/appveyor.cmd b/src/test/burn/appveyor.cmd new file mode 100644 index 00000000..c0d965e5 --- /dev/null +++ b/src/test/burn/appveyor.cmd @@ -0,0 +1,11 @@ +@setlocal +@pushd %~dp0 +@set _C=Release + +msbuild -p:Configuration=%_C% -warnaserror -Restore || exit /b +msbuild -p:Configuration=%_C% src\TestData -Restore || exit /b + +dotnet test -c %_C% --no-build src\WixToolsetTest.BurnE2E || exit /b + +@popd +@endlocal diff --git a/src/test/burn/appveyor.yml b/src/test/burn/appveyor.yml new file mode 100644 index 00000000..d12975dc --- /dev/null +++ b/src/test/burn/appveyor.yml @@ -0,0 +1,27 @@ +# 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. + + +image: Visual Studio 2019 + +environment: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + NUGET_XMLDOC_MODE: skip + RuntimeTestsEnabled: true + + +install: + - reg add HKLM\Software\Policies\Microsoft\Windows\Installer /t REG_SZ /v Logging /d voicewarmupx /f + - reg add HKLM\Software\WOW6432Node\Policies\Microsoft\Windows\Installer /t REG_SZ /v Logging /d voicewarmupx /f + +build_script: + - appveyor.cmd + +test: off + +skip_branch_with_pr: true +skip_tags: true + +on_finish: + - ps: 7z a ('logs_' + (Get-Date).tostring("yyyyMMddHHmmss") + '.zip') $env:TEMP\*.log $env:TEMP\..\*.log + - ps: Push-AppveyorArtifact logs_*.zip diff --git a/src/test/burn/global.json b/src/test/burn/global.json new file mode 100644 index 00000000..697f5687 --- /dev/null +++ b/src/test/burn/global.json @@ -0,0 +1,8 @@ +{ + "msbuild-sdks": { + "WixToolset.Sdk": "4.0.0-build-0213" + }, + "sdk": { + "allowPrerelease": false + } +} diff --git a/src/test/burn/nuget.config b/src/test/burn/nuget.config new file mode 100644 index 00000000..9187a22e --- /dev/null +++ b/src/test/burn/nuget.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3-55-g6feb