| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
| 2 | |
| 3 | namespace WixToolsetTest.BurnE2E |
| 4 | { |
| 5 | using System; |
| 6 | using System.IO; |
| 7 | using WixTestTools; |
| 8 | using Xunit; |
| 9 | using Xunit.Abstractions; |
| 10 | |
| 11 | public class MsiTransactionTests : BurnE2ETests |
| 12 | { |
| 13 | public MsiTransactionTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } |
| 14 | |
| 15 | [RuntimeFact] |
| 16 | public void CanUpgradeBundleWithMsiTransaction() |
| 17 | { |
| 18 | var packageA = this.CreatePackageInstaller("PackageA"); |
| 19 | var packageBv1 = this.CreatePackageInstaller("PackageBv1"); |
| 20 | var packageBv2 = this.CreatePackageInstaller("PackageBv2"); |
| 21 | var packageCv1 = this.CreatePackageInstaller("PackageCv1"); |
| 22 | var packageCv2 = this.CreatePackageInstaller("PackageCv2"); |
| 23 | var packageD = this.CreatePackageInstaller("PackageD"); |
| 24 | |
| 25 | var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); |
| 26 | var bundleAv2 = this.CreateBundleInstaller("BundleAv2"); |
| 27 | |
| 28 | var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs"); |
| 29 | var packageBv1SourceCodeInstalled = packageBv1.GetInstalledFilePath("Package.wxs"); |
| 30 | var packageBv2SourceCodeInstalled = packageBv2.GetInstalledFilePath("Package.wxs"); |
| 31 | var packageCv1SourceCodeInstalled = packageCv1.GetInstalledFilePath("Package.wxs"); |
| 32 | var packageCv2SourceCodeInstalled = packageCv2.GetInstalledFilePath("Package.wxs"); |
| 33 | var packageDSourceCodeInstalled = packageD.GetInstalledFilePath("Package.wxs"); |
| 34 | |
| 35 | // Source file should *not* be installed |
| 36 | Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); |
| 37 | Assert.False(File.Exists(packageBv1SourceCodeInstalled), $"Package Bv1 payload should not be there on test start: {packageBv1SourceCodeInstalled}"); |
| 38 | Assert.False(File.Exists(packageBv2SourceCodeInstalled), $"Package Bv2 payload should not be there on test start: {packageBv2SourceCodeInstalled}"); |
| 39 | Assert.False(File.Exists(packageCv1SourceCodeInstalled), $"Package Cv1 payload should not be there on test start: {packageCv1SourceCodeInstalled}"); |
| 40 | Assert.False(File.Exists(packageCv2SourceCodeInstalled), $"Package Cv2 payload should not be there on test start: {packageCv2SourceCodeInstalled}"); |
| 41 | Assert.False(File.Exists(packageDSourceCodeInstalled), $"Package D payload should not be there on test start: {packageDSourceCodeInstalled}"); |
| 42 | |
| 43 | bundleAv1.Install(); |
| 44 | |
| 45 | var bundleAv1Registration = bundleAv1.VerifyRegisteredAndInPackageCache(); |
| 46 | |
| 47 | // Source file should be installed |
| 48 | Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled)); |
| 49 | Assert.True(File.Exists(packageBv1SourceCodeInstalled), String.Concat("Should have found Package Bv1 payload installed at: ", packageBv1SourceCodeInstalled)); |
| 50 | Assert.True(File.Exists(packageCv1SourceCodeInstalled), String.Concat("Should have found Package Cv1 payload installed at: ", packageCv1SourceCodeInstalled)); |
| 51 | |
| 52 | bundleAv2.Install(); |
| 53 | |
| 54 | var bundleAv2Registration = bundleAv2.VerifyRegisteredAndInPackageCache(); |
| 55 | |
| 56 | // Source file should be upgraded |
| 57 | Assert.True(File.Exists(packageDSourceCodeInstalled), String.Concat("Should have found Package D payload installed at: ", packageDSourceCodeInstalled)); |
| 58 | Assert.True(File.Exists(packageBv2SourceCodeInstalled), String.Concat("Should have found Package Bv2 payload installed at: ", packageBv2SourceCodeInstalled)); |
| 59 | Assert.True(File.Exists(packageCv2SourceCodeInstalled), String.Concat("Should have found Package Cv2 payload installed at: ", packageCv2SourceCodeInstalled)); |
| 60 | Assert.False(File.Exists(packageCv1SourceCodeInstalled), String.Concat("Package Cv1 payload should have been removed by upgrade uninstall from: ", packageCv1SourceCodeInstalled)); |
| 61 | Assert.False(File.Exists(packageBv1SourceCodeInstalled), String.Concat("Package Bv1 payload should have been removed by upgrade uninstall from: ", packageBv1SourceCodeInstalled)); |
| 62 | Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A payload should have been removed by upgrade uninstall from: ", packageASourceCodeInstalled)); |
| 63 | |
| 64 | bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(bundleAv1Registration.CachePath); |
| 65 | |
| 66 | // Uninstall everything. |
| 67 | bundleAv2.Uninstall(); |
| 68 | |
| 69 | // Source file should *not* be installed |
| 70 | Assert.False(File.Exists(packageDSourceCodeInstalled), String.Concat("Package D payload should have been removed by uninstall from: ", packageDSourceCodeInstalled)); |
| 71 | Assert.False(File.Exists(packageBv2SourceCodeInstalled), String.Concat("Package Bv2 payload should have been removed by uninstall from: ", packageBv2SourceCodeInstalled)); |
| 72 | Assert.False(File.Exists(packageCv2SourceCodeInstalled), String.Concat("Package Cv2 payload should have been removed by uninstall from: ", packageCv2SourceCodeInstalled)); |
| 73 | |
| 74 | bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache(bundleAv2Registration.CachePath); |
| 75 | } |
| 76 | |
| 77 | /// <summary> |
| 78 | /// Installs 2 bundles: |
| 79 | /// BundleBv1- installs package Bv1 |
| 80 | /// BundleBv2- installs packages A, Bv2, F |
| 81 | /// package Bv2 performs a major upgrade of package Bv1 |
| 82 | /// package F fails |
| 83 | /// Thus, rolling back the transaction should reinstall package Bv1 |
| 84 | /// </summary> |
| 85 | [RuntimeFact] |
| 86 | public void CanRelyOnMsiTransactionRollback() |
| 87 | { |
| 88 | var packageA = this.CreatePackageInstaller("PackageA"); |
| 89 | var packageBv1 = this.CreatePackageInstaller("PackageBv1"); |
| 90 | var packageBv2 = this.CreatePackageInstaller("PackageBv2"); |
| 91 | this.CreatePackageInstaller("PackageF"); |
| 92 | |
| 93 | var bundleBv1 = this.CreateBundleInstaller("BundleBv1"); |
| 94 | var bundleBv2 = this.CreateBundleInstaller("BundleBv2"); |
| 95 | |
| 96 | var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs"); |
| 97 | var packageBv1SourceCodeInstalled = packageBv1.GetInstalledFilePath("Package.wxs"); |
| 98 | var packageBv2SourceCodeInstalled = packageBv2.GetInstalledFilePath("Package.wxs"); |
| 99 | |
| 100 | // Source file should *not* be installed |
| 101 | Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}"); |
| 102 | Assert.False(File.Exists(packageBv1SourceCodeInstalled), $"Package Bv1 payload should not be there on test start: {packageBv1SourceCodeInstalled}"); |
| 103 | Assert.False(File.Exists(packageBv2SourceCodeInstalled), $"Package Bv2 payload should not be there on test start: {packageBv2SourceCodeInstalled}"); |
| 104 | |
| 105 | bundleBv1.Install(); |
| 106 | |
| 107 | bundleBv1.VerifyRegisteredAndInPackageCache(); |
| 108 | |
| 109 | // Source file should be installed |
| 110 | Assert.True(File.Exists(packageBv1SourceCodeInstalled), String.Concat("Should have found Package Bv1 payload installed at: ", packageBv1SourceCodeInstalled)); |
| 111 | |
| 112 | bundleBv2.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE); |
| 113 | |
| 114 | // Bundle v2 should be registered since it installed a non-permanent package. |
| 115 | bundleBv2.VerifyRegisteredAndInPackageCache(); |
| 116 | |
| 117 | // Bundle v1 should not have been removed since the install of v2 failed in the middle of the chain. |
| 118 | bundleBv1.VerifyRegisteredAndInPackageCache(); |
| 119 | |
| 120 | // Source file should be installed |
| 121 | Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled)); |
| 122 | |
| 123 | // Previous source file should be installed |
| 124 | Assert.True(File.Exists(packageBv1SourceCodeInstalled), String.Concat("Should have found Package Bv1 payload installed at: ", packageBv1SourceCodeInstalled)); |
| 125 | Assert.False(File.Exists(packageBv2SourceCodeInstalled), String.Concat("Should not have found Package Bv2 payload installed at: ", packageBv2SourceCodeInstalled)); |
| 126 | } |
| 127 | } |
| 128 | } |